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 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 11 #include "atomic_wait_helper.h" 12 13 #include <atomic> 14 #include <cstdint> 15 #include <numeric> 16 #include <stop_token> 17 #include <thread> 18 #include <chrono> 19 #include <array> 20 21 #include "benchmark/benchmark.h" 22 #include "make_test_thread.h" 23 24 using namespace std::chrono_literals; 25 26 template <class NotifyPolicy, class NumWaitingThreads, class NumPrioTasks> 27 void BM_1_atomic_multi_waiter_1_notifier(benchmark::State& state) { 28 [[maybe_unused]] std::array<HighPrioTask, NumPrioTasks::value> tasks{}; 29 30 std::atomic<std::uint64_t> a; 31 auto notify_func = [&](std::stop_token st) { NotifyPolicy::notify(a, st); }; 32 33 std::uint64_t total_loop_test_param = state.range(0); 34 constexpr auto num_waiting_threads = NumWaitingThreads::value; 35 std::vector<std::jthread> wait_threads; 36 wait_threads.reserve(num_waiting_threads); 37 38 auto notify_thread = support::make_test_jthread(notify_func); 39 40 std::atomic<std::uint64_t> start_flag = 0; 41 std::atomic<std::uint64_t> done_count = 0; 42 auto wait_func = [&a, &start_flag, &done_count, total_loop_test_param](std::stop_token st) { 43 auto old_start = 0; 44 while (!st.stop_requested()) { 45 start_flag.wait(old_start); 46 old_start = start_flag.load(); 47 for (std::uint64_t i = 0; i < total_loop_test_param; ++i) { 48 auto old = a.load(std::memory_order_relaxed); 49 a.wait(old); 50 } 51 done_count.fetch_add(1); 52 } 53 }; 54 55 for (size_t i = 0; i < num_waiting_threads; ++i) { 56 wait_threads.emplace_back(support::make_test_jthread(wait_func)); 57 } 58 59 for (auto _ : state) { 60 done_count = 0; 61 start_flag.fetch_add(1); 62 start_flag.notify_all(); 63 while (done_count < num_waiting_threads) { 64 std::this_thread::yield(); 65 } 66 } 67 for (auto& t : wait_threads) { 68 t.request_stop(); 69 } 70 start_flag.fetch_add(1); 71 start_flag.notify_all(); 72 for (auto& t : wait_threads) { 73 t.join(); 74 } 75 } 76 77 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<3>, NumHighPrioTasks<0>>) 78 ->RangeMultiplier(2) 79 ->Range(1 << 14, 1 << 16); 80 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<7>, NumHighPrioTasks<0>>) 81 ->RangeMultiplier(2) 82 ->Range(1 << 12, 1 << 14); 83 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<15>, NumHighPrioTasks<0>>) 84 ->RangeMultiplier(2) 85 ->Range(1 << 10, 1 << 12); 86 87 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<3>, NumHighPrioTasks<0>>) 88 ->RangeMultiplier(2) 89 ->Range(1 << 10, 1 << 12); 90 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<7>, NumHighPrioTasks<0>>) 91 ->RangeMultiplier(2) 92 ->Range(1 << 8, 1 << 10); 93 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<15>, NumHighPrioTasks<0>>) 94 ->RangeMultiplier(2) 95 ->Range(1 << 6, 1 << 8); 96 97 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<3>, NumHighPrioTasks<0>>) 98 ->RangeMultiplier(2) 99 ->Range(1 << 8, 1 << 10); 100 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<7>, NumHighPrioTasks<0>>) 101 ->RangeMultiplier(2) 102 ->Range(1 << 6, 1 << 8); 103 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<15>, NumHighPrioTasks<0>>) 104 ->RangeMultiplier(2) 105 ->Range(1 << 4, 1 << 6); 106 107 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<3>, NumHighPrioTasks<4>>) 108 ->RangeMultiplier(2) 109 ->Range(1 << 8, 1 << 10); 110 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<7>, NumHighPrioTasks<4>>) 111 ->RangeMultiplier(2) 112 ->Range(1 << 6, 1 << 8); 113 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<15>, NumHighPrioTasks<4>>) 114 ->RangeMultiplier(2) 115 ->Range(1 << 4, 1 << 6); 116 117 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<3>, NumHighPrioTasks<4>>) 118 ->RangeMultiplier(2) 119 ->Range(1 << 8, 1 << 10); 120 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<7>, NumHighPrioTasks<4>>) 121 ->RangeMultiplier(2) 122 ->Range(1 << 6, 1 << 8); 123 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<15>, NumHighPrioTasks<4>>) 124 ->RangeMultiplier(2) 125 ->Range(1 << 4, 1 << 6); 126 127 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<3>, NumHighPrioTasks<4>>) 128 ->RangeMultiplier(2) 129 ->Range(1 << 8, 1 << 10); 130 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<7>, NumHighPrioTasks<4>>) 131 ->RangeMultiplier(2) 132 ->Range(1 << 6, 1 << 8); 133 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<15>, NumHighPrioTasks<4>>) 134 ->RangeMultiplier(2) 135 ->Range(1 << 4, 1 << 6); 136 137 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<3>, NumHighPrioTasks<7>>) 138 ->RangeMultiplier(2) 139 ->Range(1 << 4, 1 << 6); 140 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<7>, NumHighPrioTasks<7>>) 141 ->RangeMultiplier(2) 142 ->Range(1 << 3, 1 << 5); 143 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<KeepNotifying, NumWaitingThreads<15>, NumHighPrioTasks<7>>) 144 ->RangeMultiplier(2) 145 ->Range(1 << 2, 1 << 4); 146 147 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<3>, NumHighPrioTasks<7>>) 148 ->RangeMultiplier(2) 149 ->Range(1 << 3, 1 << 5); 150 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<7>, NumHighPrioTasks<7>>) 151 ->RangeMultiplier(2) 152 ->Range(1 << 2, 1 << 4); 153 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<50>, NumWaitingThreads<15>, NumHighPrioTasks<7>>) 154 ->RangeMultiplier(2) 155 ->Range(1 << 1, 1 << 3); 156 157 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<3>, NumHighPrioTasks<7>>) 158 ->RangeMultiplier(2) 159 ->Range(1 << 3, 1 << 5); 160 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<7>, NumHighPrioTasks<7>>) 161 ->RangeMultiplier(2) 162 ->Range(1 << 2, 1 << 4); 163 BENCHMARK(BM_1_atomic_multi_waiter_1_notifier<NotifyEveryNus<100>, NumWaitingThreads<15>, NumHighPrioTasks<7>>) 164 ->RangeMultiplier(2) 165 ->Range(1 << 1, 1 << 3); 166 167 BENCHMARK_MAIN(); 168