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