From eb686c069f8a6aa87bd6f1ac344a330f361fe9ec Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 13 Jun 2018 11:44:15 -0700 Subject: - b9a479321581cd0293f124041bf5c06f456afec1 Adds exception safety tests for absl::make_unique(...) by Abseil Team - 78c61364007f6ab66155c151d0061bbec89c3dbd Update variadic visitation to use a switch statement when... by Matt Calabrese - b62eb9546087e0001307a741fcdf023b2d156966 Merge GitHub PR #130 - Add MIPS support to GetProgramCoun... by Derek Mauro - 09ab5739de33c8f1bebab2bb70bf7d4331348f05 Update ABSL_ASSERT to silence clang-tidy warnings about c... by Matt Calabrese - e73ee389ce8fe1a90738973c219ebbb19bb389f3 Update unary visitation to use a switch statement when th... by Matt Calabrese - c8734ccf475b856c95220f21a5ec4f44302cb5ce Work around a MSVC bug for absl::variant, by making `Acce... by Xiaoyi Zhang GitOrigin-RevId: b9a479321581cd0293f124041bf5c06f456afec1 Change-Id: Idb6fc906087c0a4e6fc5c75a391c7f73101c613e --- absl/types/variant_benchmark.cc | 220 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 absl/types/variant_benchmark.cc (limited to 'absl/types/variant_benchmark.cc') diff --git a/absl/types/variant_benchmark.cc b/absl/types/variant_benchmark.cc new file mode 100644 index 000000000000..99658ac70c46 --- /dev/null +++ b/absl/types/variant_benchmark.cc @@ -0,0 +1,220 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Unit tests for the variant template. The 'is' and 'IsEmpty' methods +// of variant are not explicitly tested because they are used repeatedly +// in building other tests. All other public variant methods should have +// explicit tests. + +#include "absl/types/variant.h" + +#include +#include +#include +#include + +#include "benchmark/benchmark.h" +#include "absl/utility/utility.h" + +namespace absl { +namespace { + +template +struct VariantAlternative { + char member; +}; + +template +struct VariantOfAlternativesImpl; + +template +struct VariantOfAlternativesImpl> { + using type = absl::variant...>; +}; + +template +using VariantOfAlternatives = typename VariantOfAlternativesImpl< + absl::make_index_sequence>::type; + +struct Empty {}; + +template +void Ignore(T...) noexcept {} + +template +Empty DoNotOptimizeAndReturnEmpty(T&& arg) noexcept { + benchmark::DoNotOptimize(arg); + return {}; +} + +struct VisitorApplier { + struct Visitor { + template + void operator()(T&&... args) const noexcept { + Ignore(DoNotOptimizeAndReturnEmpty(args)...); + } + }; + + template + void operator()(const Vars&... vars) const noexcept { + absl::visit(Visitor(), vars...); + } +}; + +template +struct MakeWithIndex { + using Variant = VariantOfAlternatives; + + static Variant Run(std::size_t index) { + return index == CurrIndex + ? Variant(absl::in_place_index_t()) + : MakeWithIndex::Run(index); + } +}; + +template +struct MakeWithIndex { + using Variant = VariantOfAlternatives; + + static Variant Run(std::size_t /*index*/) { return Variant(); } +}; + +template +struct MakeVariantTuple; + +template +using always_t = T; + +template +VariantOfAlternatives MakeVariant(std::size_t dimension, + std::size_t index) { + return dimension == 0 + ? MakeWithIndex::Run(index % NumIndices) + : MakeVariant(dimension - 1, index / NumIndices); +} + +template +struct MakeVariantTuple> { + using VariantTuple = + std::tuple, Dimensions>...>; + + static VariantTuple Run(int index) { + return std::make_tuple(MakeVariant(Dimensions, index)...); + } +}; + +constexpr std::size_t integral_pow(std::size_t base, std::size_t power) { + return power == 0 ? 1 : base * integral_pow(base, power - 1); +} + +template +struct VisitTestBody { + template + static bool Run(Vars& vars, State& state) { + if (state.KeepRunning()) { + absl::apply(VisitorApplier(), vars[I]); + return VisitTestBody::Run(vars, state); + } + return false; + } +}; + +template +struct VisitTestBody { + template + static bool Run(Vars& /*vars*/, State& /*state*/) { + return true; + } +}; + +// Visit operations where branch prediction is likely to give a boost. +template +void BM_RedundantVisit(benchmark::State& state) { + auto vars = + MakeVariantTuple>:: + Run(static_cast(state.range(0))); + + for (auto _ : state) { // NOLINT + benchmark::DoNotOptimize(vars); + absl::apply(VisitorApplier(), vars); + } +} + +// Visit operations where branch prediction is unlikely to give a boost. +template +void BM_Visit(benchmark::State& state) { + constexpr std::size_t num_possibilities = + integral_pow(NumIndices, NumDimensions); + + using VariantTupleMaker = + MakeVariantTuple>; + using Tuple = typename VariantTupleMaker::VariantTuple; + + Tuple vars[num_possibilities]; + for (std::size_t i = 0; i < num_possibilities; ++i) + vars[i] = VariantTupleMaker::Run(i); + + while (VisitTestBody::Run(vars, state)) { + } +} + +// Visitation +// Each visit is on a different variant with a different active alternative) + +// Unary visit +BENCHMARK_TEMPLATE(BM_Visit, 1); +BENCHMARK_TEMPLATE(BM_Visit, 2); +BENCHMARK_TEMPLATE(BM_Visit, 3); +BENCHMARK_TEMPLATE(BM_Visit, 4); +BENCHMARK_TEMPLATE(BM_Visit, 5); +BENCHMARK_TEMPLATE(BM_Visit, 6); +BENCHMARK_TEMPLATE(BM_Visit, 7); +BENCHMARK_TEMPLATE(BM_Visit, 8); +BENCHMARK_TEMPLATE(BM_Visit, 16); +BENCHMARK_TEMPLATE(BM_Visit, 32); +BENCHMARK_TEMPLATE(BM_Visit, 64); + +// Binary visit +BENCHMARK_TEMPLATE(BM_Visit, 1, 2); +BENCHMARK_TEMPLATE(BM_Visit, 2, 2); +BENCHMARK_TEMPLATE(BM_Visit, 3, 2); +BENCHMARK_TEMPLATE(BM_Visit, 4, 2); +BENCHMARK_TEMPLATE(BM_Visit, 5, 2); + +// Ternary visit +BENCHMARK_TEMPLATE(BM_Visit, 1, 3); +BENCHMARK_TEMPLATE(BM_Visit, 2, 3); +BENCHMARK_TEMPLATE(BM_Visit, 3, 3); + +// Quaternary visit +BENCHMARK_TEMPLATE(BM_Visit, 1, 4); +BENCHMARK_TEMPLATE(BM_Visit, 2, 4); + +// Redundant Visitation +// Each visit consistently has the same alternative active + +// Unary visit +BENCHMARK_TEMPLATE(BM_RedundantVisit, 1)->Arg(0); +BENCHMARK_TEMPLATE(BM_RedundantVisit, 2)->DenseRange(0, 1); +BENCHMARK_TEMPLATE(BM_RedundantVisit, 8)->DenseRange(0, 7); + +// Binary visit +BENCHMARK_TEMPLATE(BM_RedundantVisit, 1, 2)->Arg(0); +BENCHMARK_TEMPLATE(BM_RedundantVisit, 2, 2) + ->DenseRange(0, integral_pow(2, 2) - 1); +BENCHMARK_TEMPLATE(BM_RedundantVisit, 4, 2) + ->DenseRange(0, integral_pow(4, 2) - 1); + +} // namespace +} // namespace absl -- cgit 1.4.1