Imported Upstream version 1.71.0
[platform/upstream/boost.git] / libs / histogram / benchmark / histogram_filling_experiments.cpp
1 // Copyright 2015-2019 Hans Dembinski
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7 #include <benchmark/benchmark.h>
8 #include <boost/histogram/axis.hpp>
9 #include <boost/histogram/axis/traits.hpp>
10 #include <boost/histogram/detail/axes.hpp>
11 #include <boost/mp11/algorithm.hpp>
12 #include <tuple>
13 #include <type_traits>
14 #include <vector>
15 #include "../test/throw_exception.hpp"
16 #include "generator.hpp"
17
18 #include <boost/assert.hpp>
19 struct assert_check {
20   assert_check() {
21     BOOST_ASSERT(false); // don't run with asserts enabled
22   }
23 } _;
24
25 using namespace boost::histogram;
26 using reg = axis::regular<>;
27 using integ = axis::integer<>;
28 using var = axis::variable<>;
29 using vector_of_variant = std::vector<axis::variant<reg, integ, var>>;
30
31 template <class T, class U>
32 auto make_storage(const U& axes) {
33   return std::vector<T>(detail::bincount(axes), 0);
34 }
35
36 template <class T>
37 auto make_strides(const T& axes) {
38   std::vector<std::size_t> strides(detail::axes_rank(axes) + 1, 1);
39   auto sit = strides.begin();
40   detail::for_each_axis(axes, [&](const auto& a) { *++sit *= axis::traits::extent(a); });
41   return strides;
42 }
43
44 template <class Axes, class Storage, class Tuple>
45 void fill_b(const Axes& axes, Storage& storage, const Tuple& t) {
46   using namespace boost::mp11;
47   std::size_t stride = 1, index = 0;
48   mp_for_each<mp_iota<mp_size<Tuple>>>([&](auto i) {
49     const auto& a = boost::histogram::detail::axis_get<i>(axes);
50     const auto& v = std::get<i>(t);
51     index += (a.index(v) + 1) * stride;
52     stride *= axis::traits::extent(a);
53   });
54   ++storage[index];
55 }
56
57 template <class Axes, class Storage, class Tuple>
58 void fill_c(const Axes& axes, const std::size_t* strides, Storage& storage,
59             const Tuple& t) {
60   using namespace boost::mp11;
61   std::size_t index = 0;
62   assert(boost::histogram::detail::axes_rank(axes) ==
63          boost::histogram::detail::axes_rank(t));
64   mp_for_each<mp_iota<mp_size<Tuple>>>([&](auto i) {
65     const auto& a = boost::histogram::detail::axis_get<i>(axes);
66     const auto& v = std::get<i>(t);
67     index += (a.index(v) + 1) * *strides++;
68   });
69   ++storage[index];
70 }
71
72 template <class T, class Distribution>
73 static void fill_1d_a(benchmark::State& state) {
74   auto axes = std::make_tuple(reg(100, 0, 1));
75   generator<Distribution> gen;
76   auto storage = make_storage<T>(axes);
77   for (auto _ : state) {
78     const auto i = std::get<0>(axes).index(gen());
79     ++storage[i + 1];
80   }
81 }
82
83 template <class T, class Distribution>
84 static void fill_1d_b(benchmark::State& state) {
85   auto axes = std::make_tuple(reg(100, 0, 1));
86   generator<Distribution> gen;
87   auto storage = make_storage<T>(axes);
88   for (auto _ : state) { fill_b(axes, storage, std::forward_as_tuple(gen())); }
89 }
90
91 template <class T, class Distribution>
92 static void fill_1d_c(benchmark::State& state) {
93   auto axes = std::make_tuple(reg(100, 0, 1));
94   generator<Distribution> gen;
95   auto storage = make_storage<T>(axes);
96   auto strides = make_strides(axes);
97   for (auto _ : state) {
98     fill_c(axes, strides.data(), storage, std::forward_as_tuple(gen()));
99   }
100 }
101
102 template <class T, class Distribution>
103 static void fill_1d_c_dyn(benchmark::State& state) {
104   auto axes = vector_of_variant({reg(100, 0, 1)});
105   generator<Distribution> gen;
106   auto storage = make_storage<T>(axes);
107   auto strides = make_strides(axes);
108   for (auto _ : state) {
109     fill_c(axes, strides.data(), storage, std::forward_as_tuple(gen()));
110   }
111 }
112
113 template <class T, class Distribution>
114 static void fill_2d_a(benchmark::State& state) {
115   auto axes = std::make_tuple(reg(100, 0, 1), reg(100, 0, 1));
116   generator<Distribution> gen;
117   auto storage = make_storage<T>(axes);
118   for (auto _ : state) {
119     const auto i0 = std::get<0>(axes).index(gen());
120     const auto i1 = std::get<1>(axes).index(gen());
121     const auto stride = axis::traits::extent(std::get<0>(axes));
122     ++storage[(i0 + 1) * stride + (i1 + 1)];
123   }
124 }
125
126 template <class T, class Distribution>
127 static void fill_2d_b(benchmark::State& state) {
128   auto axes = std::make_tuple(reg(100, 0, 1), reg(100, 0, 1));
129   generator<Distribution> gen;
130   auto storage = make_storage<T>(axes);
131   for (auto _ : state) { fill_b(axes, storage, std::forward_as_tuple(gen(), gen())); }
132 }
133
134 template <class T, class Distribution>
135 static void fill_2d_c(benchmark::State& state) {
136   auto axes = std::make_tuple(reg(100, 0, 1), reg(100, 0, 1));
137   generator<Distribution> gen;
138   auto storage = make_storage<T>(axes);
139   auto strides = make_strides(axes);
140   assert(strides.size() == 3);
141   assert(strides[0] == 1);
142   assert(strides[1] == 102);
143   for (auto _ : state) {
144     fill_c(axes, strides.data(), storage, std::forward_as_tuple(gen(), gen()));
145   }
146 }
147
148 template <class T, class Distribution>
149 static void fill_2d_c_dyn(benchmark::State& state) {
150   auto axes = vector_of_variant({reg(100, 0, 1), reg(100, 0, 1)});
151   generator<Distribution> gen;
152   auto storage = make_storage<T>(axes);
153   auto strides = make_strides(axes);
154   assert(strides.size() == 3);
155   assert(strides[0] == 1);
156   assert(strides[1] == 102);
157   for (auto _ : state) {
158     fill_c(axes, strides.data(), storage, std::forward_as_tuple(gen(), gen()));
159   }
160 }
161
162 BENCHMARK_TEMPLATE(fill_1d_a, int, uniform);
163 BENCHMARK_TEMPLATE(fill_1d_a, double, uniform);
164 BENCHMARK_TEMPLATE(fill_1d_b, double, uniform);
165 BENCHMARK_TEMPLATE(fill_1d_c, double, uniform);
166 BENCHMARK_TEMPLATE(fill_1d_c_dyn, double, uniform);
167 BENCHMARK_TEMPLATE(fill_2d_a, double, uniform);
168 BENCHMARK_TEMPLATE(fill_2d_b, double, uniform);
169 BENCHMARK_TEMPLATE(fill_2d_c, double, uniform);
170 BENCHMARK_TEMPLATE(fill_2d_c_dyn, double, uniform);
171
172 BENCHMARK_TEMPLATE(fill_1d_a, double, normal);
173 BENCHMARK_TEMPLATE(fill_1d_b, double, normal);
174 BENCHMARK_TEMPLATE(fill_1d_c, double, normal);
175 BENCHMARK_TEMPLATE(fill_2d_a, double, normal);
176 BENCHMARK_TEMPLATE(fill_2d_b, double, normal);
177 BENCHMARK_TEMPLATE(fill_2d_c, double, normal);