11
11
#include < atomic>
12
12
#include < numeric>
13
13
#include < stop_token>
14
+ #include < pthread.h>
15
+ #include < sched.h>
14
16
#include < thread>
15
17
16
18
#include " benchmark/benchmark.h"
17
19
#include " make_test_thread.h"
18
20
19
21
using namespace std ::chrono_literals;
20
22
21
- void BM_atomic_wait_one_thread_one_atomic_wait (benchmark::State& state) {
22
- std::atomic<std::uint64_t > a;
23
- auto thread_func = [&](std::stop_token st) {
23
+ struct HighPrioTask {
24
+ sched_param param;
25
+ pthread_attr_t attr_t ;
26
+ pthread_t thread;
27
+ std::atomic_bool stopped{false };
28
+
29
+ HighPrioTask (const HighPrioTask&) = delete ;
30
+
31
+ HighPrioTask () {
32
+ pthread_attr_init (&attr_t );
33
+ pthread_attr_setschedpolicy (&attr_t , SCHED_FIFO);
34
+ param.sched_priority = sched_get_priority_max (SCHED_FIFO);
35
+ pthread_attr_setschedparam (&attr_t , ¶m);
36
+ pthread_attr_setinheritsched (&attr_t , PTHREAD_EXPLICIT_SCHED);
37
+
38
+ auto thread_fun = [](void * arg) -> void * {
39
+ auto * stop = reinterpret_cast <std::atomic_bool*>(arg);
40
+ while (!stop->load (std::memory_order_relaxed)) {
41
+ // spin
42
+ }
43
+ return nullptr ;
44
+ };
45
+
46
+ if (pthread_create (&thread, &attr_t , thread_fun, &stopped) != 0 ) {
47
+ throw std::runtime_error (" failed to create thread" );
48
+ }
49
+ }
50
+
51
+ ~HighPrioTask () {
52
+ stopped = true ;
53
+ pthread_attr_destroy (&attr_t );
54
+ pthread_join (thread, nullptr );
55
+ }
56
+ };
57
+
58
+
59
+ template <std::size_t N>
60
+ struct NumHighPrioTasks {
61
+ static constexpr auto value = N;
62
+ };
63
+
64
+
65
+ struct KeepNotifying {
66
+ template <class Atomic >
67
+ static void notify (Atomic& a, std::stop_token st) {
24
68
while (!st.stop_requested ()) {
25
69
a.fetch_add (1 , std::memory_order_relaxed);
26
70
a.notify_all ();
27
71
}
28
- };
72
+ }
73
+ };
74
+
75
+ template <std::size_t N>
76
+ struct NotifyEveryNus {
77
+ template <class Atomic >
78
+ static void notify (Atomic& a, std::stop_token st) {
79
+ while (!st.stop_requested ()) {
80
+ auto start = std::chrono::system_clock::now ();
81
+ a.fetch_add (1 , std::memory_order_relaxed);
82
+ a.notify_all ();
83
+ while (std::chrono::system_clock::now () - start < std::chrono::microseconds{N}) {
84
+ }
85
+ }
86
+ }
87
+ };
88
+
89
+ template <class NotifyPolicy , class NumPrioTasks >
90
+ void BM_1_atomic_1_waiter_1_notifier (benchmark::State& state) {
91
+ [[maybe_unused]] std::array<HighPrioTask, NumPrioTasks::value> tasks{};
92
+ std::atomic<std::uint64_t > a;
93
+ auto thread_func = [&](std::stop_token st) { NotifyPolicy::notify (a, st); };
29
94
30
95
std::uint64_t total_loop_test_param = state.range (0 );
31
96
@@ -38,19 +103,34 @@ void BM_atomic_wait_one_thread_one_atomic_wait(benchmark::State& state) {
38
103
}
39
104
}
40
105
}
41
- BENCHMARK (BM_atomic_wait_one_thread_one_atomic_wait)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 24 );
42
106
43
- void BM_atomic_wait_multi_thread_one_atomic_wait (benchmark::State& state) {
107
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<KeepNotifying, NumHighPrioTasks<0 >>)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 24 );
108
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<NotifyEveryNus<50 >, NumHighPrioTasks<0 >>)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 16 );
109
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<NotifyEveryNus<100 >, NumHighPrioTasks<0 >>)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 16 );
110
+
111
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<KeepNotifying, NumHighPrioTasks<4 >>)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 24 );
112
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<NotifyEveryNus<50 >, NumHighPrioTasks<4 >>)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 16 );
113
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<NotifyEveryNus<100 >, NumHighPrioTasks<4 >>)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 16 );
114
+
115
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<KeepNotifying, NumHighPrioTasks<7 >>)->RangeMultiplier(2 )->Range(1 << 4 , 1 << 8 );
116
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<NotifyEveryNus<50 >, NumHighPrioTasks<7 >>)->RangeMultiplier(2 )->Range(1 << 4 , 1 << 8 );
117
+ BENCHMARK (BM_1_atomic_1_waiter_1_notifier<NotifyEveryNus<100 >, NumHighPrioTasks<7 >>)->RangeMultiplier(2 )->Range(1 << 4 , 1 << 8 );
118
+
119
+
120
+ template <std::size_t N>
121
+ struct NumWaitingThreads {
122
+ static constexpr auto value = N;
123
+ };
124
+
125
+ template <class NotifyPolicy , class NumWaitingThreads , class NumPrioTasks >
126
+ void BM_1_atomic_multi_waiter_1_notifier (benchmark::State& state) {
127
+ [[maybe_unused]] std::array<HighPrioTask, NumPrioTasks::value> tasks{};
128
+
44
129
std::atomic<std::uint64_t > a;
45
- auto notify_func = [&](std::stop_token st) {
46
- while (!st.stop_requested ()) {
47
- a.fetch_add (1 , std::memory_order_relaxed);
48
- a.notify_all ();
49
- }
50
- };
130
+ auto notify_func = [&](std::stop_token st) { NotifyPolicy::notify (a, st); };
51
131
52
132
std::uint64_t total_loop_test_param = state.range (0 );
53
- constexpr auto num_waiting_threads = 15 ;
133
+ constexpr auto num_waiting_threads = NumWaitingThreads::value ;
54
134
std::vector<std::jthread> wait_threads;
55
135
wait_threads.reserve (num_waiting_threads);
56
136
@@ -92,17 +172,113 @@ void BM_atomic_wait_multi_thread_one_atomic_wait(benchmark::State& state) {
92
172
t.join ();
93
173
}
94
174
}
95
- BENCHMARK (BM_atomic_wait_multi_thread_one_atomic_wait)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 20 );
175
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<3 >, NumHighPrioTasks<0 >>)
176
+ ->RangeMultiplier(2 )
177
+ ->Range(1 << 10 , 1 << 20 );
178
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<7 >, NumHighPrioTasks<0 >>)
179
+ ->RangeMultiplier(2 )
180
+ ->Range(1 << 10 , 1 << 20 );
181
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<15 >, NumHighPrioTasks<0 >>)
182
+ ->RangeMultiplier(2 )
183
+ ->Range(1 << 10 , 1 << 20 );
184
+
185
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<3 >, NumHighPrioTasks<0 >>)
186
+ ->RangeMultiplier(2 )
187
+ ->Range(1 << 10 , 1 << 16 );
188
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<7 >, NumHighPrioTasks<0 >>)
189
+ ->RangeMultiplier(2 )
190
+ ->Range(1 << 10 , 1 << 16 );
191
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<15 >, NumHighPrioTasks<0 >>)
192
+ ->RangeMultiplier(2 )
193
+ ->Range(1 << 10 , 1 << 16 );
194
+
195
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<3 >, NumHighPrioTasks<0 >>)
196
+ ->RangeMultiplier(2 )
197
+ ->Range(1 << 8 , 1 << 14 );
198
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<7 >, NumHighPrioTasks<0 >>)
199
+ ->RangeMultiplier(2 )
200
+ ->Range(1 << 8 , 1 << 14 );
201
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<15 >, NumHighPrioTasks<0 >>)
202
+ ->RangeMultiplier(2 )
203
+ ->Range(1 << 8 , 1 << 14 );
204
+
205
+
206
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<3 >, NumHighPrioTasks<4 >>)
207
+ ->RangeMultiplier(2 )
208
+ ->Range(1 << 10 , 1 << 18 );
209
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<7 >, NumHighPrioTasks<4 >>)
210
+ ->RangeMultiplier(2 )
211
+ ->Range(1 << 10 , 1 << 18 );
212
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<15 >, NumHighPrioTasks<4 >>)
213
+ ->RangeMultiplier(2 )
214
+ ->Range(1 << 10 , 1 << 18 );
215
+
216
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<3 >, NumHighPrioTasks<4 >>)
217
+ ->RangeMultiplier(2 )
218
+ ->Range(1 << 10 , 1 << 14 );
219
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<7 >, NumHighPrioTasks<4 >>)
220
+ ->RangeMultiplier(2 )
221
+ ->Range(1 << 10 , 1 << 14 );
222
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<15 >, NumHighPrioTasks<4 >>)
223
+ ->RangeMultiplier(2 )
224
+ ->Range(1 << 10 , 1 << 14 );
96
225
97
- void BM_atomic_wait_multi_thread_wait_different_atomics (benchmark::State& state) {
226
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<3 >, NumHighPrioTasks<4 >>)
227
+ ->RangeMultiplier(2 )
228
+ ->Range(1 << 8 , 1 << 14 );
229
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<7 >, NumHighPrioTasks<4 >>)
230
+ ->RangeMultiplier(2 )
231
+ ->Range(1 << 8 , 1 << 14 );
232
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<15 >, NumHighPrioTasks<4 >>)
233
+ ->RangeMultiplier(2 )
234
+ ->Range(1 << 8 , 1 << 14 );
235
+
236
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<3 >, NumHighPrioTasks<7 >>)
237
+ ->RangeMultiplier(2 )
238
+ ->Range(1 << 4 , 1 << 8 );
239
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<7 >, NumHighPrioTasks<7 >>)
240
+ ->RangeMultiplier(2 )
241
+ ->Range(1 << 4 , 1 << 8 );
242
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<15 >, NumHighPrioTasks<7 >>)
243
+ ->RangeMultiplier(2 )
244
+ ->Range(1 << 4 , 1 << 8 );
245
+
246
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<3 >, NumHighPrioTasks<7 >>)
247
+ ->RangeMultiplier(2 )
248
+ ->Range(1 << 4 , 1 << 8 );
249
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<7 >, NumHighPrioTasks<7 >>)
250
+ ->RangeMultiplier(2 )
251
+ ->Range(1 << 4 , 1 << 8 );
252
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50 >, NumWaitingThreads<15 >, NumHighPrioTasks<7 >>)
253
+ ->RangeMultiplier(2 )
254
+ ->Range(1 << 4 , 1 << 8 );
255
+
256
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<3 >, NumHighPrioTasks<7 >>)
257
+ ->RangeMultiplier(2 )
258
+ ->Range(1 << 4 , 1 << 8 );
259
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<7 >, NumHighPrioTasks<7 >>)
260
+ ->RangeMultiplier(2 )
261
+ ->Range(1 << 4 , 1 << 8 );
262
+ BENCHMARK (BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100 >, NumWaitingThreads<15 >, NumHighPrioTasks<7 >>)
263
+ ->RangeMultiplier(2 )
264
+ ->Range(1 << 4 , 1 << 8 );
265
+
266
+
267
+ template <std::size_t N>
268
+ struct NumberOfAtomics {
269
+ static constexpr auto value = N;
270
+ };
271
+
272
+ template <class NotifyPolicy , class NumberOfAtomics , class NumPrioTasks >
273
+ void BM_N_atomics_N_waiter_N_notifier (benchmark::State& state) {
274
+ [[maybe_unused]] std::array<HighPrioTask, NumPrioTasks::value> tasks{};
98
275
const std::uint64_t total_loop_test_param = state.range (0 );
99
- constexpr std::uint64_t num_atomics = 7 ;
276
+ constexpr std::uint64_t num_atomics = NumberOfAtomics::value ;
100
277
std::vector<std::atomic<std::uint64_t >> atomics (num_atomics);
101
278
102
279
auto notify_func = [&](std::stop_token st, size_t idx) {
103
280
while (!st.stop_requested ()) {
104
- atomics[idx].fetch_add (1 , std::memory_order_relaxed);
105
- atomics[idx].notify_all ();
281
+ NotifyPolicy::notify (atomics[idx], st);
106
282
}
107
283
};
108
284
@@ -153,6 +329,84 @@ void BM_atomic_wait_multi_thread_wait_different_atomics(benchmark::State& state)
153
329
t.join ();
154
330
}
155
331
}
156
- BENCHMARK (BM_atomic_wait_multi_thread_wait_different_atomics)->RangeMultiplier(2 )->Range(1 << 10 , 1 << 20 );
332
+
333
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<2 >, NumHighPrioTasks<0 >>)
334
+ ->RangeMultiplier(2 )
335
+ ->Range(1 << 10 , 1 << 20 );
336
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<3 >, NumHighPrioTasks<0 >>)
337
+ ->RangeMultiplier(2 )
338
+ ->Range(1 << 10 , 1 << 20 );
339
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<5 >, NumHighPrioTasks<0 >>)
340
+ ->RangeMultiplier(2 )
341
+ ->Range(1 << 10 , 1 << 20 );
342
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<7 >, NumHighPrioTasks<0 >>)
343
+ ->RangeMultiplier(2 )
344
+ ->Range(1 << 10 , 1 << 20 );
345
+
346
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<50 >, NumberOfAtomics<2 >, NumHighPrioTasks<0 >>)
347
+ ->RangeMultiplier(2 )
348
+ ->Range(1 << 10 , 1 << 16 );
349
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<50 >, NumberOfAtomics<3 >, NumHighPrioTasks<0 >>)
350
+ ->RangeMultiplier(2 )
351
+ ->Range(1 << 10 , 1 << 16 );
352
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<50 >, NumberOfAtomics<5 >, NumHighPrioTasks<0 >>)
353
+ ->RangeMultiplier(2 )
354
+ ->Range(1 << 10 , 1 << 16 );
355
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<50 >, NumberOfAtomics<7 >, NumHighPrioTasks<0 >>)
356
+ ->RangeMultiplier(2 )
357
+ ->Range(1 << 10 , 1 << 16 );
358
+
359
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<100 >, NumberOfAtomics<2 >, NumHighPrioTasks<0 >>)
360
+ ->RangeMultiplier(2 )
361
+ ->Range(1 << 8 , 1 << 14 );
362
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<100 >, NumberOfAtomics<3 >, NumHighPrioTasks<0 >>)
363
+ ->RangeMultiplier(2 )
364
+ ->Range(1 << 8 , 1 << 14 );
365
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<100 >, NumberOfAtomics<5 >, NumHighPrioTasks<0 >>)
366
+ ->RangeMultiplier(2 )
367
+ ->Range(1 << 8 , 1 << 14 );
368
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<100 >, NumberOfAtomics<7 >, NumHighPrioTasks<0 >>)
369
+ ->RangeMultiplier(2 )
370
+ ->Range(1 << 8 , 1 << 14 );
371
+
372
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<2 >, NumHighPrioTasks<4 >>)
373
+ ->RangeMultiplier(2 )
374
+ ->Range(1 << 10 , 1 << 20 );
375
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<3 >, NumHighPrioTasks<4 >>)
376
+ ->RangeMultiplier(2 )
377
+ ->Range(1 << 10 , 1 << 20 );
378
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<5 >, NumHighPrioTasks<4 >>)
379
+ ->RangeMultiplier(2 )
380
+ ->Range(1 << 10 , 1 << 20 );
381
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<KeepNotifying, NumberOfAtomics<7 >, NumHighPrioTasks<4 >>)
382
+ ->RangeMultiplier(2 )
383
+ ->Range(1 << 10 , 1 << 20 );
384
+
385
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<50 >, NumberOfAtomics<2 >, NumHighPrioTasks<4 >>)
386
+ ->RangeMultiplier(2 )
387
+ ->Range(1 << 10 , 1 << 16 );
388
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<50 >, NumberOfAtomics<3 >, NumHighPrioTasks<4 >>)
389
+ ->RangeMultiplier(2 )
390
+ ->Range(1 << 10 , 1 << 16 );
391
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<50 >, NumberOfAtomics<5 >, NumHighPrioTasks<4 >>)
392
+ ->RangeMultiplier(2 )
393
+ ->Range(1 << 10 , 1 << 16 );
394
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<50 >, NumberOfAtomics<7 >, NumHighPrioTasks<4 >>)
395
+ ->RangeMultiplier(2 )
396
+ ->Range(1 << 10 , 1 << 16 );
397
+
398
+
399
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<100 >, NumberOfAtomics<2 >, NumHighPrioTasks<4 >>)
400
+ ->RangeMultiplier(2 )
401
+ ->Range(1 << 8 , 1 << 14 );
402
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<100 >, NumberOfAtomics<3 >, NumHighPrioTasks<4 >>)
403
+ ->RangeMultiplier(2 )
404
+ ->Range(1 << 8 , 1 << 14 );
405
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<100 >, NumberOfAtomics<5 >, NumHighPrioTasks<4 >>)
406
+ ->RangeMultiplier(2 )
407
+ ->Range(1 << 6 , 1 << 10 );
408
+ BENCHMARK (BM_N_atomics_N_waiter_N_notifier<NotifyEveryNus<100 >, NumberOfAtomics<7 >, NumHighPrioTasks<4 >>)
409
+ ->RangeMultiplier(2 )
410
+ ->Range(1 << 4 , 1 << 8 );
157
411
158
412
BENCHMARK_MAIN ();
0 commit comments