finish adding json output
[benchmarks.git] / src / harness.h
index 72ee8d1c36458141018030b95cdbc37270517e30..b9ab39d38709d1ae217f317e009040c781ab1696 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
 
+#include "json.h"
 #include <cstdint>
 #include <functional>
 #include <memory>
@@ -18,10 +19,28 @@ struct Config final
     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;
@@ -30,10 +49,10 @@ class BenchHarnessBase
     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();
@@ -51,36 +70,38 @@ class BenchHarness final : private BenchHarnessBase
         : 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");
+                    }
                 }
-            }
-        });
+            });
     }
 };
 
@@ -88,19 +109,23 @@ class Benchmark final
 {
   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
     {