1 // Copyright 2015-2019 Hans Dembinski
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)
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>
13 #include <type_traits>
15 #include "../test/throw_exception.hpp"
16 #include "generator.hpp"
18 #include <boost/assert.hpp>
21 BOOST_ASSERT(false); // don't run with asserts enabled
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>>;
31 template <class T, class U>
32 auto make_storage(const U& axes) {
33 return std::vector<T>(detail::bincount(axes), 0);
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); });
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);
57 template <class Axes, class Storage, class Tuple>
58 void fill_c(const Axes& axes, const std::size_t* strides, Storage& storage,
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++;
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());
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())); }
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()));
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()));
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)];
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())); }
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()));
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()));
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);
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);