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
,
51 const Config
&config
, Buf
<T
> buf
, Fn fn
,
52 NameParts
&&...name_parts
)
54 auto log2_stride
= config
.log2_stride
;
55 std::size_t index_mask
= 1;
56 index_mask
<<= config
.log2_stride
;
57 index_mask
<<= config
.log2_memory_location_count
;
61 [buf
, fn
, index_mask
, log2_stride
](T input
, std::uint64_t iteration
,
62 std::uint32_t thread_num
) {
63 std::size_t index
= iteration
;
64 index
^= static_cast<std::size_t>(thread_num
) * 0x12345;
65 index
<<= log2_stride
;
67 std::atomic
<T
> *atomic
= &(*buf
)[index
];
68 input
^= static_cast<T
>(iteration
);
69 return fn(input
, atomic
, iteration
^ thread_num
);
74 template <typename T
, std::memory_order order
>
75 static void rmw_benchmarks(std::vector
<Benchmark
> &benches
,
76 const Config
&config
, Buf
<T
> buf
)
80 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t) {
81 return std::atomic_exchange_explicit(atomic
, input
, order
);
83 "atomic_exchange_", int_type_name
<T
>, "_", memory_order_name
<order
>);
86 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t) {
87 return std::atomic_fetch_add_explicit(atomic
, input
, order
);
89 "atomic_fetch_add_", int_type_name
<T
>, "_", memory_order_name
<order
>);
92 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t) {
93 return std::atomic_fetch_sub_explicit(atomic
, input
, order
);
95 "atomic_fetch_sub_", int_type_name
<T
>, "_", memory_order_name
<order
>);
98 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t) {
99 return std::atomic_fetch_and_explicit(atomic
, input
, order
);
101 "atomic_fetch_and_", int_type_name
<T
>, "_", memory_order_name
<order
>);
103 benches
, config
, buf
,
104 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t) {
105 return std::atomic_fetch_or_explicit(atomic
, input
, order
);
107 "atomic_fetch_or_", int_type_name
<T
>, "_", memory_order_name
<order
>);
109 benches
, config
, buf
,
110 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t) {
111 return std::atomic_fetch_xor_explicit(atomic
, input
, order
);
113 "atomic_fetch_xor_", int_type_name
<T
>, "_", memory_order_name
<order
>);
116 template <typename T
, std::memory_order order
>
117 static void load_benchmarks(std::vector
<Benchmark
> &benches
,
118 const Config
&config
, Buf
<T
> buf
)
121 benches
, config
, buf
,
122 [](T
, std::atomic
<T
> *atomic
, std::uint64_t) {
123 return std::atomic_load_explicit(atomic
, order
);
125 "atomic_load_", int_type_name
<T
>, "_", memory_order_name
<order
>);
128 template <typename T
, std::memory_order order
>
129 static void store_benchmarks(std::vector
<Benchmark
> &benches
,
130 const Config
&config
, Buf
<T
> buf
)
133 benches
, config
, buf
,
134 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t) {
135 return std::atomic_store_explicit(atomic
, input
, order
);
137 "atomic_store_", int_type_name
<T
>, "_", memory_order_name
<order
>);
140 template <typename T
, std::memory_order succ
, std::memory_order fail
>
141 static void cmp_xchg_benchmarks(std::vector
<Benchmark
> &benches
,
142 const Config
&config
, Buf
<T
> buf
)
145 benches
, config
, buf
,
146 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t state
) {
148 bool succeeded
= std::atomic_compare_exchange_weak_explicit(
149 atomic
, &expected
, input
, succ
, fail
);
150 return std::pair(expected
, succeeded
);
152 "atomic_compare_exchange_weak_", int_type_name
<T
>, "_",
153 memory_order_name
<succ
>, "_", memory_order_name
<fail
>);
155 benches
, config
, buf
,
156 [](T input
, std::atomic
<T
> *atomic
, std::uint64_t state
) {
158 bool succeeded
= std::atomic_compare_exchange_strong_explicit(
159 atomic
, &expected
, input
, succ
, fail
);
160 return std::pair(expected
, succeeded
);
162 "atomic_compare_exchange_strong_", int_type_name
<T
>, "_",
163 memory_order_name
<succ
>, "_", memory_order_name
<fail
>);
166 template <typename T
>
167 static void benchmarks(std::vector
<Benchmark
> &benches
, const Config
&config
)
169 std::size_t buf_size
= 1;
170 buf_size
<<= config
.log2_memory_location_count
;
171 buf_size
<<= config
.log2_stride
;
172 Buf
<T
> buf
= std::make_shared
<std::vector
<std::atomic
<T
>>>(buf_size
);
174 rmw_benchmarks
<T
, std::memory_order_relaxed
>(benches
, config
, buf
);
175 rmw_benchmarks
<T
, std::memory_order_acquire
>(benches
, config
, buf
);
176 rmw_benchmarks
<T
, std::memory_order_release
>(benches
, config
, buf
);
177 rmw_benchmarks
<T
, std::memory_order_acq_rel
>(benches
, config
, buf
);
178 rmw_benchmarks
<T
, std::memory_order_seq_cst
>(benches
, config
, buf
);
180 load_benchmarks
<T
, std::memory_order_relaxed
>(benches
, config
, buf
);
181 load_benchmarks
<T
, std::memory_order_acquire
>(benches
, config
, buf
);
182 load_benchmarks
<T
, std::memory_order_seq_cst
>(benches
, config
, buf
);
184 store_benchmarks
<T
, std::memory_order_relaxed
>(benches
, config
, buf
);
185 store_benchmarks
<T
, std::memory_order_release
>(benches
, config
, buf
);
186 store_benchmarks
<T
, std::memory_order_seq_cst
>(benches
, config
, buf
);
188 cmp_xchg_benchmarks
<T
, std::memory_order_relaxed
,
189 std::memory_order_relaxed
>(benches
, config
, buf
);
191 cmp_xchg_benchmarks
<T
, std::memory_order_acquire
,
192 std::memory_order_relaxed
>(benches
, config
, buf
);
193 cmp_xchg_benchmarks
<T
, std::memory_order_acquire
,
194 std::memory_order_acquire
>(benches
, config
, buf
);
196 cmp_xchg_benchmarks
<T
, std::memory_order_release
,
197 std::memory_order_relaxed
>(benches
, config
, buf
);
199 cmp_xchg_benchmarks
<T
, std::memory_order_acq_rel
,
200 std::memory_order_relaxed
>(benches
, config
, buf
);
201 cmp_xchg_benchmarks
<T
, std::memory_order_acq_rel
,
202 std::memory_order_acquire
>(benches
, config
, buf
);
204 cmp_xchg_benchmarks
<T
, std::memory_order_seq_cst
,
205 std::memory_order_relaxed
>(benches
, config
, buf
);
206 cmp_xchg_benchmarks
<T
, std::memory_order_seq_cst
,
207 std::memory_order_acquire
>(benches
, config
, buf
);
208 cmp_xchg_benchmarks
<T
, std::memory_order_seq_cst
,
209 std::memory_order_seq_cst
>(benches
, config
, buf
);
212 std::vector
<Benchmark
> c11_atomics_benchmarks(const Config
&config
)
214 std::vector
<Benchmark
> benches
;
215 benchmarks
<std::uint8_t>(benches
, config
);
216 benchmarks
<std::uint16_t>(benches
, config
);
217 benchmarks
<std::uint32_t>(benches
, config
);
218 benchmarks
<std::uint64_t>(benches
, config
);
219 benchmarks
<std::int8_t>(benches
, config
);
220 benchmarks
<std::int16_t>(benches
, config
);
221 benchmarks
<std::int32_t>(benches
, config
);
222 benchmarks
<std::int64_t>(benches
, config
);