#include "c11_atomics_benchmarks.h"
-#include <atomic>
-#include <cstdint>
-#include <memory>
-#include <sstream>
-#include <string_view>
-#include <type_traits>
-
-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>
-static 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);
-}
+#include "internals.h"
std::vector<Benchmark> c11_atomics_benchmarks(const Config &config)
{
+ using namespace c11_atomics;
std::vector<Benchmark> benches;
benchmarks<std::uint8_t>(benches, config);
benchmarks<std::uint16_t>(benches, config);
--- /dev/null
+#include "internals.h"
+
+template void c11_atomics::benchmarks<std::int16_t>(
+ std::vector<Benchmark> &benches, const Config &config);
--- /dev/null
+#include "internals.h"
+
+template void c11_atomics::benchmarks<std::int32_t>(
+ std::vector<Benchmark> &benches, const Config &config);
--- /dev/null
+#include "internals.h"
+
+template void c11_atomics::benchmarks<std::int64_t>(
+ std::vector<Benchmark> &benches, const Config &config);
--- /dev/null
+#include "internals.h"
+
+template void c11_atomics::benchmarks<std::int8_t>(
+ std::vector<Benchmark> &benches, const Config &config);
--- /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
--- /dev/null
+#include "internals.h"
+
+template void c11_atomics::benchmarks<std::uint16_t>(
+ std::vector<Benchmark> &benches, const Config &config);
--- /dev/null
+#include "internals.h"
+
+template void c11_atomics::benchmarks<std::uint32_t>(
+ std::vector<Benchmark> &benches, const Config &config);
--- /dev/null
+#include "internals.h"
+
+template void c11_atomics::benchmarks<std::uint64_t>(
+ std::vector<Benchmark> &benches, const Config &config);
--- /dev/null
+#include "internals.h"
+
+template void c11_atomics::benchmarks<std::uint8_t>(
+ std::vector<Benchmark> &benches, const Config &config);