| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <cstdint> |
| | #include <functional> |
| | #include <memory> |
| | #include <string> |
| |
|
| | #include "CartesianBenchmarks.h" |
| | #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() { |
| | |
| | } |
| | int padding[16]; |
| | int operator()(const S*) const { return 0; } |
| | }; |
| | struct LargeNonTrivialFunctor { |
| | int padding[16]; |
| | LargeNonTrivialFunctor() { |
| | |
| | } |
| | 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; |
| | 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(); |
| | } |
| | }; |
| |
|
| | } |
| |
|
| | 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(); |
| | } |
| |
|