| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include "dtypes.h" | ||
| 4 | #include "utilities/stopwatch.h" | ||
| 5 | |||
| 6 | #include <cmath> | ||
| 7 | #include <tuple> | ||
| 8 | |||
| 9 | namespace lython { | ||
| 10 | |||
| 11 | template <typename T = double> | ||
| 12 | struct ValueStream { | ||
| 13 | |||
| 14 | void add(T value) { | ||
| 15 | ✗ | sum += value; | |
| 16 | ✗ | count += 1; | |
| 17 | ✗ | sum_squared += value * value; | |
| 18 | ✗ | } | |
| 19 | |||
| 20 | double mean() const { return sum / double(count); } | ||
| 21 | |||
| 22 | double var() const { | ||
| 23 | ✗ | double m = mean(); | |
| 24 | ✗ | return sum_squared / double(count) - m * m; | |
| 25 | } | ||
| 26 | |||
| 27 | double total() const { return sum; } | ||
| 28 | |||
| 29 | double std() const { return sqrt(var()); } | ||
| 30 | |||
| 31 | T sum = 0; | ||
| 32 | T sum_squared = 0; | ||
| 33 | int count = 0; | ||
| 34 | }; | ||
| 35 | |||
| 36 | template <class T> | ||
| 37 | void fakeuse(T&& datum) { | ||
| 38 | #ifdef __linux__ | ||
| 39 | ✗ | asm volatile("" : "+r"(datum)); | |
| 40 | #endif | ||
| 41 | ✗ | } | |
| 42 | |||
| 43 | template <typename... Args> | ||
| 44 | struct Benchmark { | ||
| 45 | Benchmark(std::string const& name, | ||
| 46 | std::function<void(Args...)> function, | ||
| 47 | int count = 100, | ||
| 48 | int repeat = 100000): | ||
| 49 | ✗ | name(name), | |
| 50 | ✗ | function(function), count(count), repeat(repeat) {} | |
| 51 | |||
| 52 | void run(Args... args) { | ||
| 53 | ✗ | val = ValueStream<double>(); | |
| 54 | |||
| 55 | ✗ | for (int i = 0; i < count; i++) { | |
| 56 | ✗ | StopWatch<double, std::chrono::milliseconds> time; | |
| 57 | |||
| 58 | ✗ | for (int j = 0; j < repeat; j++) { | |
| 59 | ✗ | function(args...); | |
| 60 | } | ||
| 61 | ✗ | val.add(time.stop()); | |
| 62 | } | ||
| 63 | ✗ | } | |
| 64 | |||
| 65 | void report(std::ostream& out) { | ||
| 66 | out << fmt::format( | ||
| 67 | "{:>30} | {:10.3f} | {:10.3f} | {:10.3f} \n", name, val.mean(), val.std(), val.total()); | ||
| 68 | } | ||
| 69 | |||
| 70 | std::string name; | ||
| 71 | std::function<void(Args...)> function; | ||
| 72 | ValueStream<double> val; | ||
| 73 | int count; | ||
| 74 | int repeat; | ||
| 75 | }; | ||
| 76 | |||
| 77 | template <typename... Args> | ||
| 78 | std::ostream& print(std::ostream& out, Args... args) { | ||
| 79 | print(out, args...); | ||
| 80 | return out; | ||
| 81 | } | ||
| 82 | |||
| 83 | template <typename... Args, typename T, typename V> | ||
| 84 | std::ostream& print(std::ostream& out, T val, V v, Args... args) { | ||
| 85 | print(out, v, args...); | ||
| 86 | out << val << "-"; | ||
| 87 | return out; | ||
| 88 | } | ||
| 89 | |||
| 90 | template <typename... Args, typename T> | ||
| 91 | std::ostream& print(std::ostream& out, T val, Args... args) { | ||
| 92 | ✗ | print(out, args...); | |
| 93 | ✗ | out << val; | |
| 94 | ✗ | return out; | |
| 95 | } | ||
| 96 | |||
| 97 | template <> | ||
| 98 | std::ostream& print(std::ostream& out) { | ||
| 99 | ✗ | return out; | |
| 100 | } | ||
| 101 | |||
| 102 | template <typename... Args> | ||
| 103 | struct Compare { | ||
| 104 | Compare(std::vector<Benchmark<Args...>> const& benchs, int count = 100, int repeat = 100000): | ||
| 105 | ✗ | benchmarks(benchs), count(count), repeat(repeat) {} | |
| 106 | |||
| 107 | void run(std::ostream& out) { | ||
| 108 | ✗ | int i = 0; | |
| 109 | |||
| 110 | ✗ | for (std::tuple<Args...>& args: setups) { | |
| 111 | ✗ | for (Benchmark<Args...>& bench: benchmarks) { | |
| 112 | ✗ | progress(out, i); | |
| 113 | |||
| 114 | ✗ | bench.count = count; | |
| 115 | ✗ | bench.repeat = repeat; | |
| 116 | |||
| 117 | std::apply([&bench](auto&&... args) { bench.run(args...); }, args); | ||
| 118 | |||
| 119 | ✗ | std::stringstream ss; | |
| 120 | ✗ | ss << bench.name << " ("; | |
| 121 | std::apply([&ss](auto&&... args) { print(ss, args...); }, args); | ||
| 122 | ✗ | ss << ")"; | |
| 123 | |||
| 124 | ✗ | results.emplace_back(ss.str(), bench.val); | |
| 125 | ✗ | i += 1; | |
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | ✗ | progress(out, i); | |
| 130 | ✗ | } | |
| 131 | |||
| 132 | void add_setup(Args... args) { setups.push_back(std::make_tuple(args...)); } | ||
| 133 | |||
| 134 | void progress(std::ostream& out, int i) { | ||
| 135 | ✗ | float n = total(); | |
| 136 | |||
| 137 | ✗ | out << fmt::format("{:6.2f} % {}/{}\n", float(i) * 100.0 / n, i, n); | |
| 138 | ✗ | } | |
| 139 | |||
| 140 | float total() { return float(benchmarks.size()) * float(setups.size()); } | ||
| 141 | |||
| 142 | void report(std::ostream& out) { | ||
| 143 | ✗ | out << fmt::format( | |
| 144 | "{:>30} | {:>10} | {:>10} | {:>10} \n", "bench", "mean (ms)", "std (ms)", "total (ms)"); | ||
| 145 | ✗ | out << "---------------------------------------------------------------------\n"; | |
| 146 | |||
| 147 | ✗ | for (auto const& bench: results) { | |
| 148 | ✗ | report(out, bench); | |
| 149 | } | ||
| 150 | ✗ | } | |
| 151 | |||
| 152 | void as_csv(std::ostream& out) { | ||
| 153 | out << "bench,mean (ms),std (ms),total (ms)"; | ||
| 154 | for (auto const& bench: results) { | ||
| 155 | as_csv(out, bench); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | private: | ||
| 160 | void report(std::ostream& out, std::tuple<String, ValueStream<double>> const& result) { | ||
| 161 | ✗ | String name = std::get<0>(result); | |
| 162 | ✗ | ValueStream<double> val = std::get<1>(result); | |
| 163 | ✗ | out << fmt::format( | |
| 164 | ✗ | "{:>30} | {:10.3f} | {:10.3f} | {:10.3f} \n", name, val.mean(), val.std(), val.total()); | |
| 165 | ✗ | } | |
| 166 | |||
| 167 | void as_csv(std::ostream& out, std::tuple<String, ValueStream<double>> const& result) { | ||
| 168 | String name = std::get<0>(result); | ||
| 169 | ValueStream<double> val = std::get<1>(result); | ||
| 170 | out << fmt::format("{},{},{},{}\n", name, val.mean(), val.std(), val.total()); | ||
| 171 | } | ||
| 172 | |||
| 173 | std::vector<std::tuple<String, ValueStream<double>>> results; | ||
| 174 | std::vector<std::tuple<Args...>> setups; | ||
| 175 | std::vector<Benchmark<Args...>> benchmarks; | ||
| 176 | int count; | ||
| 177 | int repeat; | ||
| 178 | int col_size = 0; | ||
| 179 | }; | ||
| 180 | |||
| 181 | } // namespace lython | ||
| 182 |