123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 |
- //===----------------------------------------------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include <cstdint>
- #include <functional>
- #include <memory>
- #include <string>
- #include "CartesianBenchmarks.hpp"
- #include "benchmark/benchmark.h"
- #include "test_macros.h"
- namespace {
- enum class FunctionType {
- Null,
- FunctionPointer,
- MemberFunctionPointer,
- MemberPointer,
- SmallTrivialFunctor,
- SmallNonTrivialFunctor,
- LargeTrivialFunctor,
- LargeNonTrivialFunctor
- };
- struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
- static constexpr const char* Names[] = {"Null",
- "FuncPtr",
- "MemFuncPtr",
- "MemPtr",
- "SmallTrivialFunctor",
- "SmallNonTrivialFunctor",
- "LargeTrivialFunctor",
- "LargeNonTrivialFunctor"};
- };
- enum class Opacity { kOpaque, kTransparent };
- struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
- static constexpr const char* Names[] = {"Opaque", "Transparent"};
- };
- struct S {
- int function() const { return 0; }
- int field = 0;
- };
- int FunctionWithS(const S*) { return 0; }
- struct SmallTrivialFunctor {
- int operator()(const S*) const { return 0; }
- };
- struct SmallNonTrivialFunctor {
- SmallNonTrivialFunctor() {}
- SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
- ~SmallNonTrivialFunctor() {}
- int operator()(const S*) const { return 0; }
- };
- struct LargeTrivialFunctor {
- LargeTrivialFunctor() {
- // Do not spend time initializing the padding.
- }
- int padding[16];
- int operator()(const S*) const { return 0; }
- };
- struct LargeNonTrivialFunctor {
- int padding[16];
- LargeNonTrivialFunctor() {
- // Do not spend time initializing the padding.
- }
- LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
- ~LargeNonTrivialFunctor() {}
- int operator()(const S*) const { return 0; }
- };
- using Function = std::function<int(const S*)>;
- TEST_ALWAYS_INLINE
- inline Function MakeFunction(FunctionType type, bool opaque = false) {
- switch (type) {
- case FunctionType::Null:
- return nullptr;
- case FunctionType::FunctionPointer:
- return maybeOpaque(FunctionWithS, opaque);
- case FunctionType::MemberFunctionPointer:
- return maybeOpaque(&S::function, opaque);
- case FunctionType::MemberPointer:
- return maybeOpaque(&S::field, opaque);
- case FunctionType::SmallTrivialFunctor:
- return maybeOpaque(SmallTrivialFunctor{}, opaque);
- case FunctionType::SmallNonTrivialFunctor:
- return maybeOpaque(SmallNonTrivialFunctor{}, opaque);
- case FunctionType::LargeTrivialFunctor:
- return maybeOpaque(LargeTrivialFunctor{}, opaque);
- case FunctionType::LargeNonTrivialFunctor:
- return maybeOpaque(LargeNonTrivialFunctor{}, opaque);
- }
- }
- template <class Opacity, class FunctionType>
- struct ConstructAndDestroy {
- static void run(benchmark::State& state) {
- for (auto _ : state) {
- if (Opacity() == ::Opacity::kOpaque) {
- benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
- } else {
- MakeFunction(FunctionType());
- }
- }
- }
- static std::string name() {
- return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name();
- }
- };
- template <class FunctionType>
- struct Copy {
- static void run(benchmark::State& state) {
- auto value = MakeFunction(FunctionType());
- for (auto _ : state) {
- benchmark::DoNotOptimize(value);
- auto copy = value; // NOLINT
- benchmark::DoNotOptimize(copy);
- }
- }
- static std::string name() { return "BM_Copy" + FunctionType::name(); }
- };
- template <class FunctionType>
- struct Move {
- static void run(benchmark::State& state) {
- Function values[2] = {MakeFunction(FunctionType())};
- int i = 0;
- for (auto _ : state) {
- benchmark::DoNotOptimize(values);
- benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
- i ^= 1;
- }
- }
- static std::string name() {
- return "BM_Move" + FunctionType::name();
- }
- };
- template <class Function1, class Function2>
- struct Swap {
- static void run(benchmark::State& state) {
- Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
- for (auto _ : state) {
- benchmark::DoNotOptimize(values);
- values[0].swap(values[1]);
- }
- }
- static bool skip() { return Function1() > Function2(); }
- static std::string name() {
- return "BM_Swap" + Function1::name() + Function2::name();
- }
- };
- template <class FunctionType>
- struct OperatorBool {
- static void run(benchmark::State& state) {
- auto f = MakeFunction(FunctionType());
- for (auto _ : state) {
- benchmark::DoNotOptimize(f);
- benchmark::DoNotOptimize(static_cast<bool>(f));
- }
- }
- static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
- };
- template <class FunctionType>
- struct Invoke {
- static void run(benchmark::State& state) {
- S s;
- const auto value = MakeFunction(FunctionType());
- for (auto _ : state) {
- benchmark::DoNotOptimize(value);
- benchmark::DoNotOptimize(value(&s));
- }
- }
- static bool skip() { return FunctionType() == ::FunctionType::Null; }
- static std::string name() { return "BM_Invoke" + FunctionType::name(); }
- };
- template <class FunctionType>
- struct InvokeInlined {
- static void run(benchmark::State& state) {
- S s;
- for (auto _ : state) {
- MakeFunction(FunctionType())(&s);
- }
- }
- static bool skip() { return FunctionType() == ::FunctionType::Null; }
- static std::string name() {
- return "BM_InvokeInlined" + FunctionType::name();
- }
- };
- } // namespace
- int main(int argc, char** argv) {
- benchmark::Initialize(&argc, argv);
- if (benchmark::ReportUnrecognizedArguments(argc, argv))
- return 1;
- makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity,
- AllFunctionTypes>();
- makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
- makeCartesianProductBenchmark<Move, AllFunctionTypes>();
- makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
- makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
- makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
- makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
- benchmark::RunSpecifiedBenchmarks();
- }
|