1 #include "c11_atomics_benchmarks.h"
9 template <typename T
> struct IntTypeName
;
12 inline constexpr std::string_view int_type_name
= IntTypeName
<T
>::name
;
14 #define INT_TYPE_NAME(sz, ui, uint) \
15 template <> struct IntTypeName<std::uint##sz##_t> final \
17 static constexpr std::string_view name = #ui #sz; \
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)
29 template <std::memory_order order
> struct MemoryOrderName
;
31 template <std::memory_order order
>
32 inline constexpr std::string_view memory_order_name
=
33 MemoryOrderName
<order
>::name
;
35 #define MEMORY_ORDER_NAME(order) \
36 template <> struct MemoryOrderName<std::memory_order_##order> final \
38 static constexpr std::string_view name = #order; \
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
)
47 template <typename T
> using Buf
= std::shared_ptr
<std::vector
<std::atomic
<T
>>>;
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
)
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
;
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
;
66 std::atomic
<T
> *atomic
= &(*buf
)[index
];
67 input
^= static_cast<T
>(iteration
);
68 return fn(input
, atomic
);
73 template <typename T
, std::memory_order order
>
74 static void rmw_benchmarks(std::vector
<Benchmark
> &benches
, Config config
,
79 [](T input
, std::atomic
<T
> *atomic
) {
80 return std::atomic_exchange_explicit(atomic
, input
, order
);
82 "atomic_exchange_", int_type_name
<T
>, "_", memory_order_name
<order
>);
85 [](T input
, std::atomic
<T
> *atomic
) {
86 return std::atomic_fetch_add_explicit(atomic
, input
, order
);
88 "atomic_fetch_add_", int_type_name
<T
>, "_", memory_order_name
<order
>);
91 [](T input
, std::atomic
<T
> *atomic
) {
92 return std::atomic_fetch_sub_explicit(atomic
, input
, order
);
94 "atomic_fetch_sub_", int_type_name
<T
>, "_", memory_order_name
<order
>);
97 [](T input
, std::atomic
<T
> *atomic
) {
98 return std::atomic_fetch_and_explicit(atomic
, input
, order
);
100 "atomic_fetch_and_", int_type_name
<T
>, "_", memory_order_name
<order
>);
102 benches
, config
, buf
,
103 [](T input
, std::atomic
<T
> *atomic
) {
104 return std::atomic_fetch_or_explicit(atomic
, input
, order
);
106 "atomic_fetch_or_", int_type_name
<T
>, "_", memory_order_name
<order
>);
108 benches
, config
, buf
,
109 [](T input
, std::atomic
<T
> *atomic
) {
110 return std::atomic_fetch_xor_explicit(atomic
, input
, order
);
112 "atomic_fetch_xor_", int_type_name
<T
>, "_", memory_order_name
<order
>);
115 template <typename T
, std::memory_order order
>
116 static void load_benchmarks(std::vector
<Benchmark
> &benches
, Config config
,
120 benches
, config
, buf
,
121 [](T
, std::atomic
<T
> *atomic
) {
122 return std::atomic_load_explicit(atomic
, order
);
124 "atomic_load_", int_type_name
<T
>, "_", memory_order_name
<order
>);
127 template <typename T
, std::memory_order order
>
128 static void store_benchmarks(std::vector
<Benchmark
> &benches
, Config config
,
132 benches
, config
, buf
,
133 [](T input
, std::atomic
<T
> *atomic
) {
134 return std::atomic_store_explicit(atomic
, input
, order
);
136 "atomic_store_", int_type_name
<T
>, "_", memory_order_name
<order
>);
139 template <typename T
, std::memory_order succ
, std::memory_order fail
>
140 static void cmp_xchg_benchmarks(std::vector
<Benchmark
> &benches
, Config config
,
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
);
151 "atomic_compare_exchange_weak_", int_type_name
<T
>, "_",
152 memory_order_name
<succ
>, "_", memory_order_name
<fail
>);
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
);
161 "atomic_compare_exchange_strong_", int_type_name
<T
>, "_",
162 memory_order_name
<succ
>, "_", memory_order_name
<fail
>);
165 template <typename T
>
166 static void benchmarks(std::vector
<Benchmark
> &benches
, Config config
)
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
);
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
);
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
);
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
);
187 cmp_xchg_benchmarks
<T
, std::memory_order_relaxed
,
188 std::memory_order_relaxed
>(benches
, config
, buf
);
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
);
195 cmp_xchg_benchmarks
<T
, std::memory_order_release
,
196 std::memory_order_relaxed
>(benches
, config
, buf
);
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
);
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
);
211 std::vector
<Benchmark
> c11_atomics_benchmarks(Config config
)
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
);