#pragma once
+#include "json.h"
#include <cstdint>
#include <functional>
#include <memory>
std::uint32_t log2_stride = 0;
static constexpr std::uint32_t max_sum_log2_mem_loc_count_and_stride = 28;
bool use_json = false;
+ operator JsonValue() const
+ {
+ return JsonValue::Object{
+ {"thread_count", thread_count},
+ {"iteration_count", iteration_count},
+ {"log2_memory_location_count", log2_memory_location_count},
+ {"log2_stride", log2_stride},
+ {"use_json", use_json},
+ };
+ }
};
template <typename Fn, typename Input> class BenchHarness;
+struct BenchmarkResult
+{
+ BenchmarkResult() = default;
+ virtual ~BenchmarkResult() = default;
+ virtual void print() const = 0;
+ virtual operator JsonValue() const = 0;
+};
+
class BenchHarnessBase
{
template <typename Fn, typename Input> friend class BenchHarness;
std::shared_ptr<void> thread_cache;
class ThreadCache;
friend class ThreadCache;
- void base_run(const Config &config,
- void (*fn)(BenchHarnessBase *bench_harness_base,
- std::uint64_t iteration_count,
- std::uint32_t thread_num));
+ std::shared_ptr<BenchmarkResult> base_run(
+ const Config &config, const std::string &name,
+ void (*fn)(BenchHarnessBase *bench_harness_base,
+ std::uint64_t iteration_count, std::uint32_t thread_num));
public:
static std::shared_ptr<void> get_thread_cache();
: fn(std::move(fn)), input(std::move(input))
{
}
- void run(const Config &config)
+ std::shared_ptr<BenchmarkResult> run(const Config &config,
+ const std::string &name)
{
- base_run(config, [](BenchHarnessBase *bench_harness_base,
- std::uint64_t iteration_count,
- std::uint32_t thread_num) {
- auto self = static_cast<BenchHarness *>(bench_harness_base);
- auto &fn = self->fn;
- // copy for repeatability, also so optimization barrier is on copy,
- // not self
- auto input = self->input;
- for (std::uint64_t i = 0; i < iteration_count; i++)
- {
- // optimization barrier
- asm("" : : "r"(std::addressof(input)) : "memory");
-
- if constexpr (std::is_void_v<std::invoke_result_t<
- Fn &, Input, decltype(i),
- decltype(thread_num)>>)
+ return base_run(
+ config, name,
+ [](BenchHarnessBase *bench_harness_base,
+ std::uint64_t iteration_count, std::uint32_t thread_num) {
+ auto self = static_cast<BenchHarness *>(bench_harness_base);
+ auto &fn = self->fn;
+ // copy for repeatability, also so optimization barrier is on
+ // copy, not self
+ auto input = self->input;
+ for (std::uint64_t i = 0; i < iteration_count; i++)
{
- fn(input, i, thread_num);
- }
- else
- {
- auto output = fn(input, i, thread_num);
-
// optimization barrier
- asm("" : : "r"(std::addressof(output)) : "memory");
+ asm("" : : "r"(std::addressof(input)) : "memory");
+
+ if constexpr (std::is_void_v<std::invoke_result_t<
+ Fn &, Input, decltype(i),
+ decltype(thread_num)>>)
+ {
+ fn(input, i, thread_num);
+ }
+ else
+ {
+ auto output = fn(input, i, thread_num);
+
+ // optimization barrier
+ asm("" : : "r"(std::addressof(output)) : "memory");
+ }
}
- }
- });
+ });
}
};
{
private:
std::string m_name;
- std::function<void(const Config &config)> m_run;
+ std::function<std::shared_ptr<BenchmarkResult>(const Config &config,
+ const std::string &name)>
+ m_run;
public:
template <typename Fn, typename Input>
explicit Benchmark(Fn fn, Input input, std::string name)
- : m_name(std::move(name)), m_run([fn, input](const Config &config) {
- return BenchHarness(std::move(fn), std::move(input)).run(config);
+ : m_name(std::move(name)),
+ m_run([fn, input](const Config &config, const std::string &name) {
+ return BenchHarness(std::move(fn), std::move(input))
+ .run(config, name);
})
{
}
- void run(const Config &config)
+ std::shared_ptr<BenchmarkResult> run(const Config &config) const
{
- return m_run(config);
+ return m_run(config, m_name);
}
const std::string &name() const
{