13dc5af6aa3c1b2d645148dd21f5a4ac7fff5667
[benchmarks.git] / src / common / c11_atomics / c11_atomics_benchmarks.cpp
1 #include "c11_atomics_benchmarks.h"
2 #include <atomic>
3 #include <cstdint>
4 #include <memory>
5 #include <sstream>
6 #include <string_view>
7 #include <type_traits>
8
9 template <typename T> struct IntTypeName;
10
11 template <typename T>
12 inline constexpr std::string_view int_type_name = IntTypeName<T>::name;
13
14 #define INT_TYPE_NAME(sz, ui, uint) \
15 template <> struct IntTypeName<std::uint##sz##_t> final \
16 { \
17 static constexpr std::string_view name = #ui #sz; \
18 };
19
20 INT_TYPE_NAME(8, u, uint)
21 INT_TYPE_NAME(16, u, uint)
22 INT_TYPE_NAME(32, u, uint)
23 INT_TYPE_NAME(64, u, uint)
24 INT_TYPE_NAME(8, i, int)
25 INT_TYPE_NAME(16, i, int)
26 INT_TYPE_NAME(32, i, int)
27 INT_TYPE_NAME(64, i, int)
28
29 template <std::memory_order order> struct MemoryOrderName;
30
31 template <std::memory_order order>
32 inline constexpr std::string_view memory_order_name =
33 MemoryOrderName<order>::name;
34
35 #define MEMORY_ORDER_NAME(order) \
36 template <> struct MemoryOrderName<std::memory_order_##order> final \
37 { \
38 static constexpr std::string_view name = #order; \
39 };
40
41 MEMORY_ORDER_NAME(relaxed)
42 MEMORY_ORDER_NAME(acquire)
43 MEMORY_ORDER_NAME(release)
44 MEMORY_ORDER_NAME(acq_rel)
45 MEMORY_ORDER_NAME(seq_cst)
46
47 template <typename T> using Buf = std::shared_ptr<std::vector<std::atomic<T>>>;
48
49 template <typename Fn, typename T, typename... NameParts>
50 static void push_atomic_bench(std::vector<Benchmark> &benches, Config config,
51 Buf<T> buf, Fn fn, NameParts &&...name_parts)
52 {
53 auto log2_stride = config.log2_stride;
54 std::size_t index_mask = 1;
55 index_mask <<= config.log2_stride;
56 index_mask <<= config.log2_memory_location_count;
57 index_mask--;
58 push_bench(
59 benches,
60 [buf, fn, index_mask, log2_stride](T input, std::uint64_t iteration,
61 std::uint32_t thread_num) {
62 std::size_t index = iteration;
63 index ^= static_cast<std::size_t>(thread_num) * 0x12345;
64 index <<= log2_stride;
65 index &= index_mask;
66 std::atomic<T> *atomic = &(*buf)[index];
67 input ^= static_cast<T>(iteration);
68 return fn(input, atomic);
69 },
70 T{}, name_parts...);
71 }
72
73 template <typename T, std::memory_order order>
74 static void rmw_benchmarks(std::vector<Benchmark> &benches, Config config,
75 Buf<T> buf)
76 {
77 push_atomic_bench(
78 benches, config, buf,
79 [](T input, std::atomic<T> *atomic) {
80 return std::atomic_exchange_explicit(atomic, input, order);
81 },
82 "atomic_exchange_", int_type_name<T>, "_", memory_order_name<order>);
83 push_atomic_bench(
84 benches, config, buf,
85 [](T input, std::atomic<T> *atomic) {
86 return std::atomic_fetch_add_explicit(atomic, input, order);
87 },
88 "atomic_fetch_add_", int_type_name<T>, "_", memory_order_name<order>);
89 push_atomic_bench(
90 benches, config, buf,
91 [](T input, std::atomic<T> *atomic) {
92 return std::atomic_fetch_sub_explicit(atomic, input, order);
93 },
94 "atomic_fetch_sub_", int_type_name<T>, "_", memory_order_name<order>);
95 push_atomic_bench(
96 benches, config, buf,
97 [](T input, std::atomic<T> *atomic) {
98 return std::atomic_fetch_and_explicit(atomic, input, order);
99 },
100 "atomic_fetch_and_", int_type_name<T>, "_", memory_order_name<order>);
101 push_atomic_bench(
102 benches, config, buf,
103 [](T input, std::atomic<T> *atomic) {
104 return std::atomic_fetch_or_explicit(atomic, input, order);
105 },
106 "atomic_fetch_or_", int_type_name<T>, "_", memory_order_name<order>);
107 push_atomic_bench(
108 benches, config, buf,
109 [](T input, std::atomic<T> *atomic) {
110 return std::atomic_fetch_xor_explicit(atomic, input, order);
111 },
112 "atomic_fetch_xor_", int_type_name<T>, "_", memory_order_name<order>);
113 }
114
115 template <typename T, std::memory_order order>
116 static void load_benchmarks(std::vector<Benchmark> &benches, Config config,
117 Buf<T> buf)
118 {
119 push_atomic_bench(
120 benches, config, buf,
121 [](T, std::atomic<T> *atomic) {
122 return std::atomic_load_explicit(atomic, order);
123 },
124 "atomic_load_", int_type_name<T>, "_", memory_order_name<order>);
125 }
126
127 template <typename T, std::memory_order order>
128 static void store_benchmarks(std::vector<Benchmark> &benches, Config config,
129 Buf<T> buf)
130 {
131 push_atomic_bench(
132 benches, config, buf,
133 [](T input, std::atomic<T> *atomic) {
134 return std::atomic_store_explicit(atomic, input, order);
135 },
136 "atomic_store_", int_type_name<T>, "_", memory_order_name<order>);
137 }
138
139 template <typename T, std::memory_order succ, std::memory_order fail>
140 static void cmp_xchg_benchmarks(std::vector<Benchmark> &benches, Config config,
141 Buf<T> buf)
142 {
143 push_atomic_bench(
144 benches, config, buf,
145 [](T input, std::atomic<T> *atomic) {
146 T expected = input >> 1;
147 bool succeeded = std::atomic_compare_exchange_weak_explicit(
148 atomic, &expected, input, succ, fail);
149 return std::pair(expected, succeeded);
150 },
151 "atomic_compare_exchange_weak_", int_type_name<T>, "_",
152 memory_order_name<succ>, "_", memory_order_name<fail>);
153 push_atomic_bench(
154 benches, config, buf,
155 [](T input, std::atomic<T> *atomic) {
156 T expected = input >> 1;
157 bool succeeded = std::atomic_compare_exchange_strong_explicit(
158 atomic, &expected, input, succ, fail);
159 return std::pair(expected, succeeded);
160 },
161 "atomic_compare_exchange_strong_", int_type_name<T>, "_",
162 memory_order_name<succ>, "_", memory_order_name<fail>);
163 }
164
165 template <typename T>
166 static void benchmarks(std::vector<Benchmark> &benches, Config config)
167 {
168 std::size_t buf_size = 1;
169 buf_size <<= config.log2_memory_location_count;
170 buf_size <<= config.log2_stride;
171 Buf<T> buf = std::make_shared<std::vector<std::atomic<T>>>(buf_size);
172
173 rmw_benchmarks<T, std::memory_order_relaxed>(benches, config, buf);
174 rmw_benchmarks<T, std::memory_order_acquire>(benches, config, buf);
175 rmw_benchmarks<T, std::memory_order_release>(benches, config, buf);
176 rmw_benchmarks<T, std::memory_order_acq_rel>(benches, config, buf);
177 rmw_benchmarks<T, std::memory_order_seq_cst>(benches, config, buf);
178
179 load_benchmarks<T, std::memory_order_relaxed>(benches, config, buf);
180 load_benchmarks<T, std::memory_order_acquire>(benches, config, buf);
181 load_benchmarks<T, std::memory_order_seq_cst>(benches, config, buf);
182
183 store_benchmarks<T, std::memory_order_relaxed>(benches, config, buf);
184 store_benchmarks<T, std::memory_order_release>(benches, config, buf);
185 store_benchmarks<T, std::memory_order_seq_cst>(benches, config, buf);
186
187 cmp_xchg_benchmarks<T, std::memory_order_relaxed,
188 std::memory_order_relaxed>(benches, config, buf);
189
190 cmp_xchg_benchmarks<T, std::memory_order_acquire,
191 std::memory_order_relaxed>(benches, config, buf);
192 cmp_xchg_benchmarks<T, std::memory_order_acquire,
193 std::memory_order_acquire>(benches, config, buf);
194
195 cmp_xchg_benchmarks<T, std::memory_order_release,
196 std::memory_order_relaxed>(benches, config, buf);
197
198 cmp_xchg_benchmarks<T, std::memory_order_acq_rel,
199 std::memory_order_relaxed>(benches, config, buf);
200 cmp_xchg_benchmarks<T, std::memory_order_acq_rel,
201 std::memory_order_acquire>(benches, config, buf);
202
203 cmp_xchg_benchmarks<T, std::memory_order_seq_cst,
204 std::memory_order_relaxed>(benches, config, buf);
205 cmp_xchg_benchmarks<T, std::memory_order_seq_cst,
206 std::memory_order_acquire>(benches, config, buf);
207 cmp_xchg_benchmarks<T, std::memory_order_seq_cst,
208 std::memory_order_seq_cst>(benches, config, buf);
209 }
210
211 std::vector<Benchmark> c11_atomics_benchmarks(Config config)
212 {
213 std::vector<Benchmark> benches;
214 benchmarks<std::uint8_t>(benches, config);
215 benchmarks<std::uint16_t>(benches, config);
216 benchmarks<std::uint32_t>(benches, config);
217 benchmarks<std::uint64_t>(benches, config);
218 benchmarks<std::int8_t>(benches, config);
219 benchmarks<std::int16_t>(benches, config);
220 benchmarks<std::int32_t>(benches, config);
221 benchmarks<std::int64_t>(benches, config);
222 return benches;
223 }