--- /dev/null
+#pragma once
+
+#include "../../harness.h"
+#include <atomic>
+#include <cstdint>
+
+namespace c11_atomics
+{
+
+template <typename T> struct IntTypeName;
+
+template <typename T>
+inline constexpr std::string_view int_type_name = IntTypeName<T>::name;
+
+#define INT_TYPE_NAME(sz, ui, uint) \
+ template <> struct IntTypeName<std::uint##sz##_t> final \
+ { \
+ static constexpr std::string_view name = #ui #sz; \
+ };
+
+INT_TYPE_NAME(8, u, uint)
+INT_TYPE_NAME(16, u, uint)
+INT_TYPE_NAME(32, u, uint)
+INT_TYPE_NAME(64, u, uint)
+INT_TYPE_NAME(8, i, int)
+INT_TYPE_NAME(16, i, int)
+INT_TYPE_NAME(32, i, int)
+INT_TYPE_NAME(64, i, int)
+
+template <std::memory_order order> struct MemoryOrderName;
+
+template <std::memory_order order>
+inline constexpr std::string_view memory_order_name =
+ MemoryOrderName<order>::name;
+
+#define MEMORY_ORDER_NAME(order) \
+ template <> struct MemoryOrderName<std::memory_order_##order> final \
+ { \
+ static constexpr std::string_view name = #order; \
+ };
+
+MEMORY_ORDER_NAME(relaxed)
+MEMORY_ORDER_NAME(acquire)
+MEMORY_ORDER_NAME(release)
+MEMORY_ORDER_NAME(acq_rel)
+MEMORY_ORDER_NAME(seq_cst)
+
+template <typename T> using Buf = std::shared_ptr<std::vector<std::atomic<T>>>;
+
+template <typename Fn, typename T, typename... NameParts>
+static void push_atomic_bench(std::vector<Benchmark> &benches,
+ const Config &config, Buf<T> buf, Fn fn,
+ NameParts &&...name_parts)
+{
+ auto log2_stride = config.log2_stride;
+ std::size_t index_mask = 1;
+ index_mask <<= config.log2_stride;
+ index_mask <<= config.log2_memory_location_count;
+ index_mask--;
+ push_bench(
+ benches,
+ [buf, fn, index_mask, log2_stride](T input, std::uint64_t iteration,
+ std::uint32_t thread_num) {
+ std::size_t index = iteration;
+ index ^= static_cast<std::size_t>(thread_num) * 0x12345;
+ index <<= log2_stride;
+ index &= index_mask;
+ std::atomic<T> *atomic = &(*buf)[index];
+ input ^= static_cast<T>(iteration);
+ return fn(input, atomic, iteration ^ thread_num);
+ },
+ T{}, name_parts...);
+}
+
+template <typename T, std::memory_order order>
+static void rmw_benchmarks(std::vector<Benchmark> &benches,
+ const Config &config, Buf<T> buf)
+{
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t) {
+ return std::atomic_exchange_explicit(atomic, input, order);
+ },
+ "atomic_exchange_", int_type_name<T>, "_", memory_order_name<order>);
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t) {
+ return std::atomic_fetch_add_explicit(atomic, input, order);
+ },
+ "atomic_fetch_add_", int_type_name<T>, "_", memory_order_name<order>);
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t) {
+ return std::atomic_fetch_sub_explicit(atomic, input, order);
+ },
+ "atomic_fetch_sub_", int_type_name<T>, "_", memory_order_name<order>);
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t) {
+ return std::atomic_fetch_and_explicit(atomic, input, order);
+ },
+ "atomic_fetch_and_", int_type_name<T>, "_", memory_order_name<order>);
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t) {
+ return std::atomic_fetch_or_explicit(atomic, input, order);
+ },
+ "atomic_fetch_or_", int_type_name<T>, "_", memory_order_name<order>);
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t) {
+ return std::atomic_fetch_xor_explicit(atomic, input, order);
+ },
+ "atomic_fetch_xor_", int_type_name<T>, "_", memory_order_name<order>);
+}
+
+template <typename T, std::memory_order order>
+static void load_benchmarks(std::vector<Benchmark> &benches,
+ const Config &config, Buf<T> buf)
+{
+ push_atomic_bench(
+ benches, config, buf,
+ [](T, std::atomic<T> *atomic, std::uint64_t) {
+ return std::atomic_load_explicit(atomic, order);
+ },
+ "atomic_load_", int_type_name<T>, "_", memory_order_name<order>);
+}
+
+template <typename T, std::memory_order order>
+static void store_benchmarks(std::vector<Benchmark> &benches,
+ const Config &config, Buf<T> buf)
+{
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t) {
+ return std::atomic_store_explicit(atomic, input, order);
+ },
+ "atomic_store_", int_type_name<T>, "_", memory_order_name<order>);
+}
+
+template <typename T, std::memory_order succ, std::memory_order fail>
+static void cmp_xchg_benchmarks(std::vector<Benchmark> &benches,
+ const Config &config, Buf<T> buf)
+{
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t state) {
+ T expected = state;
+ bool succeeded = std::atomic_compare_exchange_weak_explicit(
+ atomic, &expected, input, succ, fail);
+ return std::pair(expected, succeeded);
+ },
+ "atomic_compare_exchange_weak_", int_type_name<T>, "_",
+ memory_order_name<succ>, "_", memory_order_name<fail>);
+ push_atomic_bench(
+ benches, config, buf,
+ [](T input, std::atomic<T> *atomic, std::uint64_t state) {
+ T expected = state;
+ bool succeeded = std::atomic_compare_exchange_strong_explicit(
+ atomic, &expected, input, succ, fail);
+ return std::pair(expected, succeeded);
+ },
+ "atomic_compare_exchange_strong_", int_type_name<T>, "_",
+ memory_order_name<succ>, "_", memory_order_name<fail>);
+}
+
+template <typename T>
+void benchmarks(std::vector<Benchmark> &benches, const Config &config)
+{
+ std::size_t buf_size = 1;
+ buf_size <<= config.log2_memory_location_count;
+ buf_size <<= config.log2_stride;
+ Buf<T> buf = std::make_shared<std::vector<std::atomic<T>>>(buf_size);
+
+ rmw_benchmarks<T, std::memory_order_relaxed>(benches, config, buf);
+ rmw_benchmarks<T, std::memory_order_acquire>(benches, config, buf);
+ rmw_benchmarks<T, std::memory_order_release>(benches, config, buf);
+ rmw_benchmarks<T, std::memory_order_acq_rel>(benches, config, buf);
+ rmw_benchmarks<T, std::memory_order_seq_cst>(benches, config, buf);
+
+ load_benchmarks<T, std::memory_order_relaxed>(benches, config, buf);
+ load_benchmarks<T, std::memory_order_acquire>(benches, config, buf);
+ load_benchmarks<T, std::memory_order_seq_cst>(benches, config, buf);
+
+ store_benchmarks<T, std::memory_order_relaxed>(benches, config, buf);
+ store_benchmarks<T, std::memory_order_release>(benches, config, buf);
+ store_benchmarks<T, std::memory_order_seq_cst>(benches, config, buf);
+
+ cmp_xchg_benchmarks<T, std::memory_order_relaxed,
+ std::memory_order_relaxed>(benches, config, buf);
+
+ cmp_xchg_benchmarks<T, std::memory_order_acquire,
+ std::memory_order_relaxed>(benches, config, buf);
+ cmp_xchg_benchmarks<T, std::memory_order_acquire,
+ std::memory_order_acquire>(benches, config, buf);
+
+ cmp_xchg_benchmarks<T, std::memory_order_release,
+ std::memory_order_relaxed>(benches, config, buf);
+
+ cmp_xchg_benchmarks<T, std::memory_order_acq_rel,
+ std::memory_order_relaxed>(benches, config, buf);
+ cmp_xchg_benchmarks<T, std::memory_order_acq_rel,
+ std::memory_order_acquire>(benches, config, buf);
+
+ cmp_xchg_benchmarks<T, std::memory_order_seq_cst,
+ std::memory_order_relaxed>(benches, config, buf);
+ cmp_xchg_benchmarks<T, std::memory_order_seq_cst,
+ std::memory_order_acquire>(benches, config, buf);
+ cmp_xchg_benchmarks<T, std::memory_order_seq_cst,
+ std::memory_order_seq_cst>(benches, config, buf);
+}
+
+#define C11_ATOMICS_TYPES \
+ C11_ATOMICS_TYPE(std::uint8_t) \
+ C11_ATOMICS_TYPE(std::uint16_t) \
+ C11_ATOMICS_TYPE(std::uint32_t) \
+ C11_ATOMICS_TYPE(std::uint64_t) \
+ C11_ATOMICS_TYPE(std::int8_t) \
+ C11_ATOMICS_TYPE(std::int16_t) \
+ C11_ATOMICS_TYPE(std::int32_t) \
+ C11_ATOMICS_TYPE(std::int64_t) \
+ //
+
+#define C11_ATOMICS_TYPE(T) \
+ extern template void benchmarks<T>(std::vector<Benchmark> & benches, \
+ const Config &config);
+
+C11_ATOMICS_TYPES
+
+#undef C11_ATOMICS_TYPE
+
+} // namespace c11_atomics
\ No newline at end of file