xref: /openbsd-src/gnu/llvm/libcxx/benchmarks/CartesianBenchmarks.h (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1*46035553Spatrick //===----------------------------------------------------------------------===//
2*46035553Spatrick //
3*46035553Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*46035553Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*46035553Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*46035553Spatrick //
7*46035553Spatrick //===----------------------------------------------------------------------===//
8*46035553Spatrick 
9*46035553Spatrick 
10*46035553Spatrick #include <string>
11*46035553Spatrick #include <tuple>
12*46035553Spatrick #include <type_traits>
13*46035553Spatrick #include <vector>
14*46035553Spatrick 
15*46035553Spatrick #include "benchmark/benchmark.h"
16*46035553Spatrick #include "test_macros.h"
17*46035553Spatrick 
18*46035553Spatrick namespace internal {
19*46035553Spatrick 
20*46035553Spatrick template <class D, class E, size_t I>
21*46035553Spatrick struct EnumValue : std::integral_constant<E, static_cast<E>(I)> {
nameEnumValue22*46035553Spatrick   static std::string name() { return std::string("_") + D::Names[I]; }
23*46035553Spatrick };
24*46035553Spatrick 
25*46035553Spatrick template <class D, class E, size_t ...Idxs>
makeEnumValueTuple(std::index_sequence<Idxs...>)26*46035553Spatrick constexpr auto makeEnumValueTuple(std::index_sequence<Idxs...>) {
27*46035553Spatrick   return std::make_tuple(EnumValue<D, E, Idxs>{}...);
28*46035553Spatrick }
29*46035553Spatrick 
30*46035553Spatrick template <class B>
31*46035553Spatrick static auto skip(const B& Bench, int) -> decltype(Bench.skip()) {
32*46035553Spatrick   return Bench.skip();
33*46035553Spatrick }
34*46035553Spatrick template <class B>
skip(const B & Bench,char)35*46035553Spatrick static auto skip(const B& Bench, char) {
36*46035553Spatrick   return false;
37*46035553Spatrick }
38*46035553Spatrick 
39*46035553Spatrick template <class B, class Args, size_t... Is>
makeBenchmarkFromValuesImpl(const Args & A,std::index_sequence<Is...>)40*46035553Spatrick void makeBenchmarkFromValuesImpl(const Args& A, std::index_sequence<Is...>) {
41*46035553Spatrick   for (auto& V : A) {
42*46035553Spatrick     B Bench{std::get<Is>(V)...};
43*46035553Spatrick     if (!internal::skip(Bench, 0)) {
44*46035553Spatrick       benchmark::RegisterBenchmark(Bench.name().c_str(),
45*46035553Spatrick                                    [=](benchmark::State& S) { Bench.run(S); });
46*46035553Spatrick     }
47*46035553Spatrick   }
48*46035553Spatrick }
49*46035553Spatrick 
50*46035553Spatrick template <class B, class... Args>
makeBenchmarkFromValues(const std::vector<std::tuple<Args...>> & A)51*46035553Spatrick void makeBenchmarkFromValues(const std::vector<std::tuple<Args...> >& A) {
52*46035553Spatrick   makeBenchmarkFromValuesImpl<B>(A, std::index_sequence_for<Args...>());
53*46035553Spatrick }
54*46035553Spatrick 
55*46035553Spatrick template <template <class...> class B, class Args, class... U>
makeBenchmarkImpl(const Args & A,std::tuple<U...> t)56*46035553Spatrick void makeBenchmarkImpl(const Args& A, std::tuple<U...> t) {
57*46035553Spatrick   makeBenchmarkFromValues<B<U...> >(A);
58*46035553Spatrick }
59*46035553Spatrick 
60*46035553Spatrick template <template <class...> class B, class Args, class... U,
61*46035553Spatrick           class... T, class... Tuples>
makeBenchmarkImpl(const Args & A,std::tuple<U...>,std::tuple<T...>,Tuples...rest)62*46035553Spatrick void makeBenchmarkImpl(const Args& A, std::tuple<U...>, std::tuple<T...>,
63*46035553Spatrick                        Tuples... rest) {
64*46035553Spatrick   (internal::makeBenchmarkImpl<B>(A, std::tuple<U..., T>(), rest...), ...);
65*46035553Spatrick }
66*46035553Spatrick 
67*46035553Spatrick template <class R, class T>
allValueCombinations(R & Result,const T & Final)68*46035553Spatrick void allValueCombinations(R& Result, const T& Final) {
69*46035553Spatrick   return Result.push_back(Final);
70*46035553Spatrick }
71*46035553Spatrick 
72*46035553Spatrick template <class R, class T, class V, class... Vs>
allValueCombinations(R & Result,const T & Prev,const V & Value,const Vs &...Values)73*46035553Spatrick void allValueCombinations(R& Result, const T& Prev, const V& Value,
74*46035553Spatrick                           const Vs&... Values) {
75*46035553Spatrick   for (const auto& E : Value) {
76*46035553Spatrick     allValueCombinations(Result, std::tuple_cat(Prev, std::make_tuple(E)),
77*46035553Spatrick                          Values...);
78*46035553Spatrick   }
79*46035553Spatrick }
80*46035553Spatrick 
81*46035553Spatrick }  // namespace internal
82*46035553Spatrick 
83*46035553Spatrick // CRTP class that enables using enum types as a dimension for
84*46035553Spatrick // makeCartesianProductBenchmark below.
85*46035553Spatrick // The type passed to `B` will be a std::integral_constant<E, e>, with the
86*46035553Spatrick // additional static function `name()` that returns the stringified name of the
87*46035553Spatrick // label.
88*46035553Spatrick //
89*46035553Spatrick // Eg:
90*46035553Spatrick // enum class MyEnum { A, B };
91*46035553Spatrick // struct AllMyEnum : EnumValuesAsTuple<AllMyEnum, MyEnum, 2> {
92*46035553Spatrick //   static constexpr absl::string_view Names[] = {"A", "B"};
93*46035553Spatrick // };
94*46035553Spatrick template <class Derived, class EnumType, size_t NumLabels>
95*46035553Spatrick using EnumValuesAsTuple =
96*46035553Spatrick     decltype(internal::makeEnumValueTuple<Derived, EnumType>(
97*46035553Spatrick         std::make_index_sequence<NumLabels>{}));
98*46035553Spatrick 
99*46035553Spatrick // Instantiates B<T0, T1, ..., TN> where <Ti...> are the combinations in the
100*46035553Spatrick // cartesian product of `Tuples...`, and pass (arg0, ..., argN) as constructor
101*46035553Spatrick // arguments where `(argi...)` are the combination in the cartesian product of
102*46035553Spatrick // the runtime values of `A...`.
103*46035553Spatrick // B<T...> requires:
104*46035553Spatrick //  - std::string name(args...): The name of the benchmark.
105*46035553Spatrick //  - void run(benchmark::State&, args...): The body of the benchmark.
106*46035553Spatrick // It can also optionally provide:
107*46035553Spatrick //  - bool skip(args...): When `true`, skips the combination. Default is false.
108*46035553Spatrick //
109*46035553Spatrick // Returns int to facilitate registration. The return value is unspecified.
110*46035553Spatrick template <template <class...> class B, class... Tuples, class... Args>
makeCartesianProductBenchmark(const Args &...A)111*46035553Spatrick int makeCartesianProductBenchmark(const Args&... A) {
112*46035553Spatrick   std::vector<std::tuple<typename Args::value_type...> > V;
113*46035553Spatrick   internal::allValueCombinations(V, std::tuple<>(), A...);
114*46035553Spatrick   internal::makeBenchmarkImpl<B>(V, std::tuple<>(), Tuples()...);
115*46035553Spatrick   return 0;
116*46035553Spatrick }
117*46035553Spatrick 
118*46035553Spatrick template <class B, class... Args>
makeCartesianProductBenchmark(const Args &...A)119*46035553Spatrick int makeCartesianProductBenchmark(const Args&... A) {
120*46035553Spatrick   std::vector<std::tuple<typename Args::value_type...> > V;
121*46035553Spatrick   internal::allValueCombinations(V, std::tuple<>(), A...);
122*46035553Spatrick   internal::makeBenchmarkFromValues<B>(V);
123*46035553Spatrick   return 0;
124*46035553Spatrick }
125*46035553Spatrick 
126*46035553Spatrick // When `opaque` is true, this function hides the runtime state of `value` from
127*46035553Spatrick // the optimizer.
128*46035553Spatrick // It returns `value`.
129*46035553Spatrick template <class T>
maybeOpaque(T value,bool opaque)130*46035553Spatrick TEST_ALWAYS_INLINE inline T maybeOpaque(T value, bool opaque) {
131*46035553Spatrick   if (opaque) benchmark::DoNotOptimize(value);
132*46035553Spatrick   return value;
133*46035553Spatrick }
134