1 | //===----------------------------------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef TEST_BENCHMARK_ATOMIC_WAIT_HELPER_H |
10 | #define TEST_BENCHMARK_ATOMIC_WAIT_HELPER_H |
11 | |
12 | #include <atomic> |
13 | #include <chrono> |
14 | #include <exception> |
15 | #include <stop_token> |
16 | #include <thread> |
17 | |
18 | struct HighPrioTask { |
19 | sched_param param; |
20 | pthread_attr_t attr_t; |
21 | pthread_t thread; |
22 | std::atomic_bool stopped{false}; |
23 | |
24 | HighPrioTask(const HighPrioTask&) = delete; |
25 | |
26 | HighPrioTask() { |
27 | pthread_attr_init(attr: &attr_t); |
28 | pthread_attr_setschedpolicy(attr: &attr_t, SCHED_FIFO); |
29 | param.sched_priority = sched_get_priority_max(SCHED_FIFO); |
30 | pthread_attr_setschedparam(attr: &attr_t, param: ¶m); |
31 | pthread_attr_setinheritsched(attr: &attr_t, PTHREAD_EXPLICIT_SCHED); |
32 | |
33 | auto thread_fun = [](void* arg) -> void* { |
34 | auto* stop = reinterpret_cast<std::atomic_bool*>(arg); |
35 | while (!stop->load(m: std::memory_order_relaxed)) { |
36 | // spin |
37 | } |
38 | return nullptr; |
39 | }; |
40 | |
41 | if (pthread_create(newthread: &thread, attr: &attr_t, start_routine: thread_fun, arg: &stopped) != 0) { |
42 | throw std::runtime_error("failed to create thread" ); |
43 | } |
44 | } |
45 | |
46 | ~HighPrioTask() { |
47 | stopped = true; |
48 | pthread_attr_destroy(attr: &attr_t); |
49 | pthread_join(th: thread, thread_return: nullptr); |
50 | } |
51 | }; |
52 | |
53 | template <std::size_t N> |
54 | struct NumHighPrioTasks { |
55 | static constexpr auto value = N; |
56 | }; |
57 | |
58 | template <std::size_t N> |
59 | struct NumWaitingThreads { |
60 | static constexpr auto value = N; |
61 | }; |
62 | |
63 | template <std::size_t N> |
64 | struct NumberOfAtomics { |
65 | static constexpr auto value = N; |
66 | }; |
67 | |
68 | struct KeepNotifying { |
69 | template <class Atomic> |
70 | static void notify(Atomic& a, std::stop_token st) { |
71 | while (!st.stop_requested()) { |
72 | a.fetch_add(1, std::memory_order_relaxed); |
73 | a.notify_all(); |
74 | } |
75 | } |
76 | }; |
77 | |
78 | template <std::size_t N> |
79 | struct NotifyEveryNus { |
80 | template <class Atomic> |
81 | static void notify(Atomic& a, std::stop_token st) { |
82 | while (!st.stop_requested()) { |
83 | auto start = std::chrono::system_clock::now(); |
84 | a.fetch_add(1, std::memory_order_relaxed); |
85 | a.notify_all(); |
86 | while (std::chrono::system_clock::now() - start < std::chrono::microseconds{N}) { |
87 | } |
88 | } |
89 | } |
90 | }; |
91 | |
92 | #endif // TEST_BENCHMARK_ATOMIC_WAIT_HELPER_H |