00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "absl/types/variant.h"
00021
00022 #include <cstddef>
00023 #include <cstdlib>
00024 #include <string>
00025 #include <tuple>
00026
00027 #include "benchmark/benchmark.h"
00028 #include "absl/utility/utility.h"
00029
00030 namespace absl {
00031 namespace {
00032
00033 template <std::size_t I>
00034 struct VariantAlternative {
00035 char member;
00036 };
00037
00038 template <class Indices>
00039 struct VariantOfAlternativesImpl;
00040
00041 template <std::size_t... Indices>
00042 struct VariantOfAlternativesImpl<absl::index_sequence<Indices...>> {
00043 using type = absl::variant<VariantAlternative<Indices>...>;
00044 };
00045
00046 template <std::size_t NumAlternatives>
00047 using VariantOfAlternatives = typename VariantOfAlternativesImpl<
00048 absl::make_index_sequence<NumAlternatives>>::type;
00049
00050 struct Empty {};
00051
00052 template <class... T>
00053 void Ignore(T...) noexcept {}
00054
00055 template <class T>
00056 Empty DoNotOptimizeAndReturnEmpty(T&& arg) noexcept {
00057 benchmark::DoNotOptimize(arg);
00058 return {};
00059 }
00060
00061 struct VisitorApplier {
00062 struct Visitor {
00063 template <class... T>
00064 void operator()(T&&... args) const noexcept {
00065 Ignore(DoNotOptimizeAndReturnEmpty(args)...);
00066 }
00067 };
00068
00069 template <class... Vars>
00070 void operator()(const Vars&... vars) const noexcept {
00071 absl::visit(Visitor(), vars...);
00072 }
00073 };
00074
00075 template <std::size_t NumIndices, std::size_t CurrIndex = NumIndices - 1>
00076 struct MakeWithIndex {
00077 using Variant = VariantOfAlternatives<NumIndices>;
00078
00079 static Variant Run(std::size_t index) {
00080 return index == CurrIndex
00081 ? Variant(absl::in_place_index_t<CurrIndex>())
00082 : MakeWithIndex<NumIndices, CurrIndex - 1>::Run(index);
00083 }
00084 };
00085
00086 template <std::size_t NumIndices>
00087 struct MakeWithIndex<NumIndices, 0> {
00088 using Variant = VariantOfAlternatives<NumIndices>;
00089
00090 static Variant Run(std::size_t ) { return Variant(); }
00091 };
00092
00093 template <std::size_t NumIndices, class Dimensions>
00094 struct MakeVariantTuple;
00095
00096 template <class T, std::size_t >
00097 using always_t = T;
00098
00099 template <std::size_t NumIndices>
00100 VariantOfAlternatives<NumIndices> MakeVariant(std::size_t dimension,
00101 std::size_t index) {
00102 return dimension == 0
00103 ? MakeWithIndex<NumIndices>::Run(index % NumIndices)
00104 : MakeVariant<NumIndices>(dimension - 1, index / NumIndices);
00105 }
00106
00107 template <std::size_t NumIndices, std::size_t... Dimensions>
00108 struct MakeVariantTuple<NumIndices, absl::index_sequence<Dimensions...>> {
00109 using VariantTuple =
00110 std::tuple<always_t<VariantOfAlternatives<NumIndices>, Dimensions>...>;
00111
00112 static VariantTuple Run(int index) {
00113 return std::make_tuple(MakeVariant<NumIndices>(Dimensions, index)...);
00114 }
00115 };
00116
00117 constexpr std::size_t integral_pow(std::size_t base, std::size_t power) {
00118 return power == 0 ? 1 : base * integral_pow(base, power - 1);
00119 }
00120
00121 template <std::size_t End, std::size_t I = 0>
00122 struct VisitTestBody {
00123 template <class Vars, class State>
00124 static bool Run(Vars& vars, State& state) {
00125 if (state.KeepRunning()) {
00126 absl::apply(VisitorApplier(), vars[I]);
00127 return VisitTestBody<End, I + 1>::Run(vars, state);
00128 }
00129 return false;
00130 }
00131 };
00132
00133 template <std::size_t End>
00134 struct VisitTestBody<End, End> {
00135 template <class Vars, class State>
00136 static bool Run(Vars& , State& ) {
00137 return true;
00138 }
00139 };
00140
00141
00142 template <std::size_t NumIndices, std::size_t NumDimensions = 1>
00143 void BM_RedundantVisit(benchmark::State& state) {
00144 auto vars =
00145 MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>::
00146 Run(static_cast<std::size_t>(state.range(0)));
00147
00148 for (auto _ : state) {
00149 benchmark::DoNotOptimize(vars);
00150 absl::apply(VisitorApplier(), vars);
00151 }
00152 }
00153
00154
00155 template <std::size_t NumIndices, std::size_t NumDimensions = 1>
00156 void BM_Visit(benchmark::State& state) {
00157 constexpr std::size_t num_possibilities =
00158 integral_pow(NumIndices, NumDimensions);
00159
00160 using VariantTupleMaker =
00161 MakeVariantTuple<NumIndices, absl::make_index_sequence<NumDimensions>>;
00162 using Tuple = typename VariantTupleMaker::VariantTuple;
00163
00164 Tuple vars[num_possibilities];
00165 for (std::size_t i = 0; i < num_possibilities; ++i)
00166 vars[i] = VariantTupleMaker::Run(i);
00167
00168 while (VisitTestBody<num_possibilities>::Run(vars, state)) {
00169 }
00170 }
00171
00172
00173
00174
00175
00176 BENCHMARK_TEMPLATE(BM_Visit, 1);
00177 BENCHMARK_TEMPLATE(BM_Visit, 2);
00178 BENCHMARK_TEMPLATE(BM_Visit, 3);
00179 BENCHMARK_TEMPLATE(BM_Visit, 4);
00180 BENCHMARK_TEMPLATE(BM_Visit, 5);
00181 BENCHMARK_TEMPLATE(BM_Visit, 6);
00182 BENCHMARK_TEMPLATE(BM_Visit, 7);
00183 BENCHMARK_TEMPLATE(BM_Visit, 8);
00184 BENCHMARK_TEMPLATE(BM_Visit, 16);
00185 BENCHMARK_TEMPLATE(BM_Visit, 32);
00186 BENCHMARK_TEMPLATE(BM_Visit, 64);
00187
00188
00189 BENCHMARK_TEMPLATE(BM_Visit, 1, 2);
00190 BENCHMARK_TEMPLATE(BM_Visit, 2, 2);
00191 BENCHMARK_TEMPLATE(BM_Visit, 3, 2);
00192 BENCHMARK_TEMPLATE(BM_Visit, 4, 2);
00193 BENCHMARK_TEMPLATE(BM_Visit, 5, 2);
00194
00195
00196 BENCHMARK_TEMPLATE(BM_Visit, 1, 3);
00197 BENCHMARK_TEMPLATE(BM_Visit, 2, 3);
00198 BENCHMARK_TEMPLATE(BM_Visit, 3, 3);
00199
00200
00201 BENCHMARK_TEMPLATE(BM_Visit, 1, 4);
00202 BENCHMARK_TEMPLATE(BM_Visit, 2, 4);
00203
00204
00205
00206
00207
00208 BENCHMARK_TEMPLATE(BM_RedundantVisit, 1)->Arg(0);
00209 BENCHMARK_TEMPLATE(BM_RedundantVisit, 2)->DenseRange(0, 1);
00210 BENCHMARK_TEMPLATE(BM_RedundantVisit, 8)->DenseRange(0, 7);
00211
00212
00213 BENCHMARK_TEMPLATE(BM_RedundantVisit, 1, 2)->Arg(0);
00214 BENCHMARK_TEMPLATE(BM_RedundantVisit, 2, 2)
00215 ->DenseRange(0, integral_pow(2, 2) - 1);
00216 BENCHMARK_TEMPLATE(BM_RedundantVisit, 4, 2)
00217 ->DenseRange(0, integral_pow(4, 2) - 1);
00218
00219 }
00220 }