Skip to content

Commit 16f3342

Browse files
committed
Strengthen remote polling coverage
1 parent ee93b23 commit 16f3342

3 files changed

Lines changed: 207 additions & 101 deletions

File tree

examples/benchmark/common.hpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include <barrier>
2424
#include <chrono>
2525
#include <cmath>
26-
#include <cstdlib>
2726
#include <iomanip>
2827
#include <iostream>
2928
#include <memory>
@@ -121,10 +120,6 @@ void my_main(int argc, char** argv, exec::numa_policy policy = exec::get_numa_po
121120
nthreads = std::atoi(argv[1]);
122121
}
123122
std::size_t total_scheds = 10'000'000;
124-
if (argc > 2)
125-
{
126-
total_scheds = static_cast<std::size_t>(std::strtoull(argv[2], nullptr, 10));
127-
}
128123
#ifndef STDEXEC_NO_MONOTONIC_BUFFER_RESOURCE
129124
std::vector<std::unique_ptr<char, numa_deleter>> buffers;
130125
#endif

test/exec/test_static_thread_pool.cpp

Lines changed: 85 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <exception>
2727
#include <latch>
2828
#include <mutex>
29+
#include <optional>
2930
#include <ranges>
3031
#include <stdexcept>
3132
#include <thread>
@@ -234,86 +235,106 @@ TEST_CASE("bulk on static_thread_pool executes on multiple threads, take 2",
234235
REQUIRE(thread_ids.size() == num_of_threads);
235236
}
236237

237-
TEST_CASE("static_thread_pool drains remote work after idle transitions",
238-
"[types][static_thread_pool][stress]")
238+
namespace
239239
{
240-
constexpr std::size_t num_producers = 4;
241-
constexpr std::size_t rounds = 10'000;
242-
243-
std::latch ready{num_producers};
244-
std::atomic<bool> start{false};
245-
std::atomic<bool> stop{false};
246-
std::vector<std::atomic<std::size_t>> completed(num_producers);
247-
std::vector<std::thread> producers;
248-
producers.reserve(num_producers);
249-
for (auto& count: completed)
240+
void run_remote_poll_stress(bool separate_schedulers)
250241
{
251-
count.store(0, std::memory_order_relaxed);
252-
}
253-
254-
exec::static_thread_pool pool{1};
255-
auto scheduler = pool.get_scheduler();
242+
constexpr std::size_t num_producers = 4;
243+
constexpr std::size_t rounds = 10'000;
244+
245+
std::latch ready{num_producers};
246+
std::atomic<bool> start{false};
247+
std::atomic<bool> stop{false};
248+
std::vector<std::atomic<std::size_t>> completed(num_producers);
249+
std::vector<std::thread> producers;
250+
producers.reserve(num_producers);
251+
for (auto& count: completed)
252+
{
253+
count.store(0, std::memory_order_relaxed);
254+
}
256255

257-
for (std::size_t producer = 0; producer < num_producers; ++producer)
258-
{
259-
producers.emplace_back(
260-
[&, producer]
261-
{
262-
ready.count_down();
263-
while (!start.load(std::memory_order_acquire))
264-
{
265-
std::this_thread::yield();
266-
}
256+
exec::static_thread_pool pool{1};
257+
using scheduler_t = decltype(pool.get_scheduler());
258+
std::optional<scheduler_t> shared_scheduler;
259+
if (!separate_schedulers)
260+
{
261+
shared_scheduler.emplace(pool.get_scheduler());
262+
}
267263

268-
auto* const producer_completed = &completed[producer];
269-
std::size_t expected = 0;
270-
for (std::size_t round = 0; round < rounds && !stop.load(std::memory_order_relaxed);
271-
++round)
264+
for (std::size_t producer = 0; producer < num_producers; ++producer)
265+
{
266+
producers.emplace_back(
267+
[&, producer]
272268
{
273-
std::size_t const batch_size = (round % 4 == 0) ? 2 : 1;
274-
expected += batch_size;
275-
for (std::size_t i = 0; i < batch_size; ++i)
269+
auto scheduler = separate_schedulers ? pool.get_scheduler() : *shared_scheduler;
270+
ready.count_down();
271+
while (!start.load(std::memory_order_acquire))
276272
{
277-
exec::start_detached(
278-
ex::schedule(scheduler)
279-
| ex::then([producer_completed]
280-
{ producer_completed->fetch_add(1, std::memory_order_relaxed); }));
273+
std::this_thread::yield();
281274
}
282275

283-
while (!stop.load(std::memory_order_relaxed)
284-
&& producer_completed->load(std::memory_order_relaxed) < expected)
276+
auto* const producer_completed = &completed[producer];
277+
std::size_t expected = 0;
278+
for (std::size_t round = 0; round < rounds && !stop.load(std::memory_order_relaxed);
279+
++round)
285280
{
281+
std::size_t const batch_size = (round % 4 == 0) ? 2 : 1;
282+
expected += batch_size;
283+
for (std::size_t i = 0; i < batch_size; ++i)
284+
{
285+
exec::start_detached(
286+
ex::schedule(scheduler)
287+
| ex::then([producer_completed]
288+
{ producer_completed->fetch_add(1, std::memory_order_relaxed); }));
289+
}
290+
291+
while (!stop.load(std::memory_order_relaxed)
292+
&& producer_completed->load(std::memory_order_relaxed) < expected)
293+
{
294+
std::this_thread::yield();
295+
}
286296
std::this_thread::yield();
287297
}
288-
std::this_thread::yield();
289-
}
290-
});
291-
}
298+
});
299+
}
292300

293-
ready.wait();
294-
start.store(true, std::memory_order_release);
301+
ready.wait();
302+
start.store(true, std::memory_order_release);
295303

296-
auto const expected = num_producers * rounds + num_producers * ((rounds + 3) / 4);
297-
auto const deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10);
298-
auto completed_total = [&]
299-
{
300-
std::size_t result = 0;
301-
for (auto const & count: completed)
304+
auto const expected = num_producers * rounds + num_producers * ((rounds + 3) / 4);
305+
auto const deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10);
306+
auto completed_total = [&]
302307
{
303-
result += count.load(std::memory_order_relaxed);
308+
std::size_t result = 0;
309+
for (auto const & count: completed)
310+
{
311+
result += count.load(std::memory_order_relaxed);
312+
}
313+
return result;
314+
};
315+
316+
while (completed_total() < expected && std::chrono::steady_clock::now() < deadline)
317+
{
318+
std::this_thread::yield();
319+
}
320+
stop.store(true, std::memory_order_release);
321+
for (auto& producer: producers)
322+
{
323+
producer.join();
304324
}
305-
return result;
306-
};
307325

308-
while (completed_total() < expected && std::chrono::steady_clock::now() < deadline)
309-
{
310-
std::this_thread::yield();
311-
}
312-
stop.store(true, std::memory_order_release);
313-
for (auto& producer: producers)
314-
{
315-
producer.join();
326+
CHECK(completed_total() == expected);
316327
}
328+
} // namespace
329+
330+
TEST_CASE("static_thread_pool drains remote work from a shared scheduler",
331+
"[types][static_thread_pool][stress]")
332+
{
333+
run_remote_poll_stress(false);
334+
}
317335

318-
CHECK(completed_total() == expected);
336+
TEST_CASE("static_thread_pool drains remote work from producer schedulers",
337+
"[types][static_thread_pool][stress]")
338+
{
339+
run_remote_poll_stress(true);
319340
}

0 commit comments

Comments
 (0)