From d551f341f60e10b6f783413c04b228c1583f4d76 Mon Sep 17 00:00:00 2001 From: Minh Vu Date: Tue, 11 Aug 2026 00:50:52 +0200 Subject: [PATCH 1/2] Fix constrained worker selection --- include/exec/static_thread_pool.hpp | 4 +-- test/exec/test_static_thread_pool.cpp | 48 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/include/exec/static_thread_pool.hpp b/include/exec/static_thread_pool.hpp index f9d2e027d..5359c1913 100644 --- a/include/exec/static_thread_pool.hpp +++ b/include/exec/static_thread_pool.hpp @@ -853,8 +853,8 @@ namespace experimental::execution { thread_local std::uint64_t start_index{std::uint64_t(std::random_device{}())}; start_index += 1; - std::size_t target_index = start_index % thread_count_; - std::size_t n_threads = num_threads(constraints); + std::size_t const n_threads = num_threads(constraints); + std::size_t target_index = start_index % (n_threads == 0 ? thread_count_ : n_threads); if (n_threads != 0) { for (std::size_t node_index = 0; node_index < numa_.num_nodes(); ++node_index) diff --git a/test/exec/test_static_thread_pool.cpp b/test/exec/test_static_thread_pool.cpp index b0cceede7..8bf6a8c1c 100644 --- a/test/exec/test_static_thread_pool.cpp +++ b/test/exec/test_static_thread_pool.cpp @@ -31,6 +31,35 @@ namespace ex = STDEXEC; namespace { + thread_local int current_numa_node = -1; + + struct two_node_numa_policy + { + [[nodiscard]] + constexpr auto num_nodes() const noexcept -> std::size_t + { + return 2; + } + + [[nodiscard]] + constexpr auto num_cpus(int) const noexcept -> std::size_t + { + return 2; + } + + auto bind_to_node(int node) const noexcept -> int + { + current_numa_node = node; + return 0; + } + + [[nodiscard]] + constexpr auto thread_index_to_node(std::size_t index) const noexcept -> int + { + return index < 2 ? 1 : 0; + } + }; + #if !STDEXEC_NO_STDCPP_EXCEPTIONS() struct throwing_set_next_receiver { @@ -69,6 +98,25 @@ namespace #endif } // namespace +TEST_CASE("constrained static_thread_pool scheduler selects eligible workers", + "[types][static_thread_pool]") +{ + constexpr std::size_t const num_of_threads = 4; + exec::static_thread_pool pool{ + num_of_threads, {}, exec::numa_policy{two_node_numa_policy{}}}; + exec::nodemask constraints{}; + constraints.set(0); + auto scheduler = pool.get_constrained_scheduler(&constraints); + + for (std::size_t i = 0; i < num_of_threads; ++i) + { + auto [node] = ex::sync_wait(ex::schedule(scheduler) + | ex::then([]() noexcept { return current_numa_node; })) + .value(); + CHECK(node == 0); + } +} + TEST_CASE("static_thread_pool::get_scheduler_on_thread Test start on a specific thread", "[types][static_thread_pool]") { From 7024d2cc9e614f47ce4fb65a0ed381fa9479ef22 Mon Sep 17 00:00:00 2001 From: Eric Niebler Date: Mon, 10 Aug 2026 17:22:22 -0700 Subject: [PATCH 2/2] clang-format --- include/exec/static_thread_pool.hpp | 4 ++-- test/exec/test_static_thread_pool.cpp | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/include/exec/static_thread_pool.hpp b/include/exec/static_thread_pool.hpp index 5359c1913..30eda78e1 100644 --- a/include/exec/static_thread_pool.hpp +++ b/include/exec/static_thread_pool.hpp @@ -853,8 +853,8 @@ namespace experimental::execution { thread_local std::uint64_t start_index{std::uint64_t(std::random_device{}())}; start_index += 1; - std::size_t const n_threads = num_threads(constraints); - std::size_t target_index = start_index % (n_threads == 0 ? thread_count_ : n_threads); + std::size_t const n_threads = num_threads(constraints); + std::size_t target_index = start_index % (n_threads == 0 ? thread_count_ : n_threads); if (n_threads != 0) { for (std::size_t node_index = 0; node_index < numa_.num_nodes(); ++node_index) diff --git a/test/exec/test_static_thread_pool.cpp b/test/exec/test_static_thread_pool.cpp index 8bf6a8c1c..01109af5a 100644 --- a/test/exec/test_static_thread_pool.cpp +++ b/test/exec/test_static_thread_pool.cpp @@ -102,9 +102,8 @@ TEST_CASE("constrained static_thread_pool scheduler selects eligible workers", "[types][static_thread_pool]") { constexpr std::size_t const num_of_threads = 4; - exec::static_thread_pool pool{ - num_of_threads, {}, exec::numa_policy{two_node_numa_policy{}}}; - exec::nodemask constraints{}; + exec::static_thread_pool pool{num_of_threads, {}, exec::numa_policy{two_node_numa_policy{}}}; + exec::nodemask constraints{}; constraints.set(0); auto scheduler = pool.get_constrained_scheduler(&constraints);