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