variant_benchmark.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 // Unit tests for the variant template. The 'is' and 'IsEmpty' methods
00016 // of variant are not explicitly tested because they are used repeatedly
00017 // in building other tests. All other public variant methods should have
00018 // explicit tests.
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 /*index*/) { return Variant(); }
00091 };
00092 
00093 template <std::size_t NumIndices, class Dimensions>
00094 struct MakeVariantTuple;
00095 
00096 template <class T, std::size_t /*I*/>
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& /*vars*/, State& /*state*/) {
00137     return true;
00138   }
00139 };
00140 
00141 // Visit operations where branch prediction is likely to give a boost.
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) {  // NOLINT
00149     benchmark::DoNotOptimize(vars);
00150     absl::apply(VisitorApplier(), vars);
00151   }
00152 }
00153 
00154 // Visit operations where branch prediction is unlikely to give a boost.
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 // Visitation
00173 //   Each visit is on a different variant with a different active alternative)
00174 
00175 // Unary visit
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 // Binary visit
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 // Ternary visit
00196 BENCHMARK_TEMPLATE(BM_Visit, 1, 3);
00197 BENCHMARK_TEMPLATE(BM_Visit, 2, 3);
00198 BENCHMARK_TEMPLATE(BM_Visit, 3, 3);
00199 
00200 // Quaternary visit
00201 BENCHMARK_TEMPLATE(BM_Visit, 1, 4);
00202 BENCHMARK_TEMPLATE(BM_Visit, 2, 4);
00203 
00204 // Redundant Visitation
00205 //   Each visit consistently has the same alternative active
00206 
00207 // Unary visit
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 // Binary visit
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 }  // namespace
00220 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:16