Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / benchmarks / stop_token.bench.cpp
blob293d55ed82a08cf4f2b7fc770278a5595ff2efe6
1 //===----------------------------------------------------------------------===//
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
8 #include <numeric>
9 #include <stop_token>
10 #include <thread>
12 #include "benchmark/benchmark.h"
13 #include "make_test_thread.h"
15 using namespace std::chrono_literals;
17 // We have a single thread created by std::jthread consuming the stop_token:
18 // registering/deregistering callbacks, one at a time.
19 void BM_stop_token_single_thread_reg_unreg_callback(benchmark::State& state) {
20 auto thread_func = [&](std::stop_token st, std::atomic<std::uint64_t>* reg_count) {
21 while (!st.stop_requested()) {
22 std::stop_callback cb{st, [&]() noexcept {}};
23 benchmark::DoNotOptimize(cb);
24 reg_count->fetch_add(1, std::memory_order_relaxed);
28 std::atomic<std::uint64_t> reg_count(0);
29 std::uint64_t total_reg_test_param = state.range(0);
31 auto thread = support::make_test_jthread(thread_func, &reg_count);
33 for (auto _ : state) {
34 auto start_total = reg_count.load(std::memory_order_relaxed);
36 while (reg_count.load(std::memory_order_relaxed) - start_total < total_reg_test_param) {
37 std::this_thread::yield();
41 BENCHMARK(BM_stop_token_single_thread_reg_unreg_callback)->RangeMultiplier(2)->Range(1 << 10, 1 << 24);
43 // At startup, it creates a single stop_source which it will then pass an associated stop_token to every
44 // request.
46 // Assume a thread-pool handles these requests and for each request it polls for stop_requested(), then attaches a
47 // stop-callback, does some work, then detaches the stop-callback some time later. The lifetime of requests/callbacks
48 // would overlap with other requests/callback from the same thread.
50 // Say something like each thread keeping a circular buffer of N stop-callbacks and destroying the stop-callbacks in
51 // FIFO order
52 void BM_stop_token_async_reg_unreg_callback(benchmark::State& state) {
53 struct dummy_stop_callback {
54 void operator()() const noexcept {}
57 constexpr size_t thread_count = 20;
58 constexpr size_t concurrent_request_count = 1000;
59 std::atomic<bool> start{false};
61 std::uint64_t total_reg_test_param = state.range(0);
63 std::stop_source ss;
64 std::vector<std::jthread> threads;
65 threads.reserve(thread_count);
66 std::vector<std::atomic<std::uint64_t>> reg_counts(thread_count);
68 auto thread_func = [&start](std::atomic<std::uint64_t>* count, std::stop_token st) {
69 std::vector<std::optional<std::stop_callback<dummy_stop_callback>>> cbs(concurrent_request_count);
71 start.wait(false);
73 std::uint32_t index = 0;
74 while (!st.stop_requested()) {
75 cbs[index].emplace(st, dummy_stop_callback{});
76 index = (index + 1) % concurrent_request_count;
77 count->fetch_add(1, std::memory_order_relaxed);
81 for (size_t i = 0; i < thread_count; ++i) {
82 threads.emplace_back(support::make_test_jthread(thread_func, &reg_counts[i], ss.get_token()));
85 auto get_total_reg = [&] {
86 std::uint64_t total = 0;
87 for (const auto& reg_counts : reg_counts) {
88 total += reg_counts.load(std::memory_order_relaxed);
90 return total;
93 start = true;
94 start.notify_all();
96 for (auto _ : state) {
97 auto start_total = get_total_reg();
99 while (get_total_reg() - start_total < total_reg_test_param) {
100 std::this_thread::yield();
104 ss.request_stop();
106 BENCHMARK(BM_stop_token_async_reg_unreg_callback)->RangeMultiplier(2)->Range(1 << 10, 1 << 24);
108 BENCHMARK_MAIN();