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
6 //===----------------------------------------------------------------------===//
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
, ®_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
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
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);
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
);
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
, ®_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
);
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();
106 BENCHMARK(BM_stop_token_async_reg_unreg_callback
)->RangeMultiplier(2)->Range(1 << 10, 1 << 24);