From 434b99a75d1baf2e9ff4a1b2835f11b88531d25d Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 31 Oct 2025 11:13:50 +0100 Subject: [PATCH 1/7] Compute search time that is independent of parameters list. --- src/problems/vrp.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/problems/vrp.h b/src/problems/vrp.h index 6b9506852..06110fec2 100644 --- a/src/problems/vrp.h +++ b/src/problems/vrp.h @@ -213,6 +213,17 @@ class VRP { std::exception_ptr ep = nullptr; std::mutex ep_m; + const auto actual_nb_threads = std::min(nb_searches, nb_threads); + + Timeout search_time; + if (timeout.has_value()) { + // Max number of solving per thread. + const auto dv = std::div(static_cast(nb_searches), + static_cast(actual_nb_threads)); + const unsigned max_solving_number = dv.quot + ((dv.rem == 0) ? 0 : 1); + search_time = timeout.value() / max_solving_number; + } + auto run_solving = [&context, ¶meters, &timeout, &ep, &ep_m, depth, this]( const std::vector& param_ranks) { From 426a88139570f0e88fa04872bb4158ea684ebfa6 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 31 Oct 2025 11:28:04 +0100 Subject: [PATCH 2/7] Simplify solving lambda to run on a single parameter. --- src/problems/vrp.h | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/problems/vrp.h b/src/problems/vrp.h index 06110fec2..97ddb6fc3 100644 --- a/src/problems/vrp.h +++ b/src/problems/vrp.h @@ -225,23 +225,15 @@ class VRP { } auto run_solving = - [&context, ¶meters, &timeout, &ep, &ep_m, depth, this]( - const std::vector& param_ranks) { + [&context, &search_time, ¶meters, &timeout, &ep, &ep_m, depth, this]( + const unsigned rank) { try { - // Decide time allocated for each search. - Timeout search_time; - if (timeout.has_value()) { - search_time = timeout.value() / param_ranks.size(); - } - - for (auto rank : param_ranks) { - run_single_search(_input, - parameters[rank], - rank, - depth, - search_time, - context); - } + run_single_search(_input, + parameters[rank], + rank, + depth, + search_time, + context); } catch (...) { const std::scoped_lock lock(ep_m); ep = std::current_exception(); From 62dad3e3bf9129987b362d6047001312c6c49cf5 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 31 Oct 2025 11:28:16 +0100 Subject: [PATCH 3/7] Create nb_searches threads. --- src/problems/vrp.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/problems/vrp.h b/src/problems/vrp.h index 97ddb6fc3..4e3199f7d 100644 --- a/src/problems/vrp.h +++ b/src/problems/vrp.h @@ -241,12 +241,10 @@ class VRP { }; std::vector solving_threads; - solving_threads.reserve(nb_threads); + solving_threads.reserve(nb_searches); - for (const auto& param_ranks : thread_ranks) { - if (!param_ranks.empty()) { - solving_threads.emplace_back(run_solving, param_ranks); - } + for (unsigned i = 0; i < nb_searches; ++i) { + solving_threads.emplace_back(run_solving, i); } for (auto& t : solving_threads) { From e967d5116d954c698c7941df549479d2810420c2 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 31 Oct 2025 14:44:50 +0100 Subject: [PATCH 4/7] Limit solving concurrency using a counting_semaphore. --- src/problems/vrp.h | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/problems/vrp.h b/src/problems/vrp.h index 4e3199f7d..cde24e5d9 100644 --- a/src/problems/vrp.h +++ b/src/problems/vrp.h @@ -214,6 +214,7 @@ class VRP { std::mutex ep_m; const auto actual_nb_threads = std::min(nb_searches, nb_threads); + std::counting_semaphore<32> semaphore(actual_nb_threads); Timeout search_time; if (timeout.has_value()) { @@ -224,21 +225,29 @@ class VRP { search_time = timeout.value() / max_solving_number; } - auto run_solving = - [&context, &search_time, ¶meters, &timeout, &ep, &ep_m, depth, this]( - const unsigned rank) { - try { - run_single_search(_input, - parameters[rank], - rank, - depth, - search_time, - context); - } catch (...) { - const std::scoped_lock lock(ep_m); - ep = std::current_exception(); - } - }; + auto run_solving = [&context, + &semaphore, + &search_time, + ¶meters, + &timeout, + &ep, + &ep_m, + depth, + this](const unsigned rank) { + semaphore.acquire(); + try { + run_single_search(_input, + parameters[rank], + rank, + depth, + search_time, + context); + } catch (...) { + const std::scoped_lock lock(ep_m); + ep = std::current_exception(); + } + semaphore.release(); + }; std::vector solving_threads; solving_threads.reserve(nb_searches); From 07fcd38e830541a2ade3e73f5c4f36eb99cdede7 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Fri, 31 Oct 2025 14:48:58 +0100 Subject: [PATCH 5/7] Remove parameters splitting logic. --- src/problems/vrp.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/problems/vrp.h b/src/problems/vrp.h index cde24e5d9..b04b3dc51 100644 --- a/src/problems/vrp.h +++ b/src/problems/vrp.h @@ -203,13 +203,6 @@ class VRP { SolvingContext context(_input, nb_searches); - // Split the heuristic parameters among threads. - std::vector> - thread_ranks(nb_threads, std::vector()); - for (std::size_t i = 0; i < nb_searches; ++i) { - thread_ranks[i % nb_threads].push_back(i); - } - std::exception_ptr ep = nullptr; std::mutex ep_m; From 1683cda1f2c40ca1cbdeede62eb676498d7544a7 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Tue, 4 Nov 2025 15:24:40 +0100 Subject: [PATCH 6/7] Add assert on semaphore count. --- src/problems/vrp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/problems/vrp.h b/src/problems/vrp.h index b04b3dc51..e5ed1469e 100644 --- a/src/problems/vrp.h +++ b/src/problems/vrp.h @@ -207,6 +207,7 @@ class VRP { std::mutex ep_m; const auto actual_nb_threads = std::min(nb_searches, nb_threads); + assert(actual_nb_threads <= 32); std::counting_semaphore<32> semaphore(actual_nb_threads); Timeout search_time; From b1c5cf3f925e4691e5ce78f27c00c91644cb0d00 Mon Sep 17 00:00:00 2001 From: jcoupey Date: Tue, 4 Nov 2025 15:28:06 +0100 Subject: [PATCH 7/7] Mention refactor in changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c8c8ea9e1..aa0b3e469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - Update README to clarify high-level purpose and usage of the project (#1264) - Remove unused breaks_travel_margin members from TWRoute and associated code (#1295) - Run routing requests in parallel (#1218) +- Refactor parallel solving (#1305) #### CI