10e6a833eSSamuel Benzaquen //===----------------------------------------------------------------------===//
20e6a833eSSamuel Benzaquen //
357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60e6a833eSSamuel Benzaquen //
70e6a833eSSamuel Benzaquen //===----------------------------------------------------------------------===//
80e6a833eSSamuel Benzaquen
90e6a833eSSamuel Benzaquen #include <cstdint>
100e6a833eSSamuel Benzaquen #include <functional>
110e6a833eSSamuel Benzaquen #include <memory>
120e6a833eSSamuel Benzaquen #include <string>
130e6a833eSSamuel Benzaquen
14*f938755aSNico Weber #include "CartesianBenchmarks.h"
150e6a833eSSamuel Benzaquen #include "benchmark/benchmark.h"
160e6a833eSSamuel Benzaquen #include "test_macros.h"
170e6a833eSSamuel Benzaquen
180e6a833eSSamuel Benzaquen namespace {
190e6a833eSSamuel Benzaquen
200e6a833eSSamuel Benzaquen enum class FunctionType {
210e6a833eSSamuel Benzaquen Null,
220e6a833eSSamuel Benzaquen FunctionPointer,
230e6a833eSSamuel Benzaquen MemberFunctionPointer,
240e6a833eSSamuel Benzaquen MemberPointer,
250e6a833eSSamuel Benzaquen SmallTrivialFunctor,
260e6a833eSSamuel Benzaquen SmallNonTrivialFunctor,
270e6a833eSSamuel Benzaquen LargeTrivialFunctor,
280e6a833eSSamuel Benzaquen LargeNonTrivialFunctor
290e6a833eSSamuel Benzaquen };
300e6a833eSSamuel Benzaquen
310e6a833eSSamuel Benzaquen struct AllFunctionTypes : EnumValuesAsTuple<AllFunctionTypes, FunctionType, 8> {
320e6a833eSSamuel Benzaquen static constexpr const char* Names[] = {"Null",
330e6a833eSSamuel Benzaquen "FuncPtr",
340e6a833eSSamuel Benzaquen "MemFuncPtr",
350e6a833eSSamuel Benzaquen "MemPtr",
360e6a833eSSamuel Benzaquen "SmallTrivialFunctor",
370e6a833eSSamuel Benzaquen "SmallNonTrivialFunctor",
380e6a833eSSamuel Benzaquen "LargeTrivialFunctor",
390e6a833eSSamuel Benzaquen "LargeNonTrivialFunctor"};
400e6a833eSSamuel Benzaquen };
410e6a833eSSamuel Benzaquen
420e6a833eSSamuel Benzaquen enum class Opacity { kOpaque, kTransparent };
430e6a833eSSamuel Benzaquen
440e6a833eSSamuel Benzaquen struct AllOpacity : EnumValuesAsTuple<AllOpacity, Opacity, 2> {
450e6a833eSSamuel Benzaquen static constexpr const char* Names[] = {"Opaque", "Transparent"};
460e6a833eSSamuel Benzaquen };
470e6a833eSSamuel Benzaquen
480e6a833eSSamuel Benzaquen struct S {
function__anon90649daa0111::S490e6a833eSSamuel Benzaquen int function() const { return 0; }
509039b601SEric Fiselier int field = 0;
510e6a833eSSamuel Benzaquen };
520e6a833eSSamuel Benzaquen
FunctionWithS(const S *)530e6a833eSSamuel Benzaquen int FunctionWithS(const S*) { return 0; }
540e6a833eSSamuel Benzaquen
550e6a833eSSamuel Benzaquen struct SmallTrivialFunctor {
operator ()__anon90649daa0111::SmallTrivialFunctor560e6a833eSSamuel Benzaquen int operator()(const S*) const { return 0; }
570e6a833eSSamuel Benzaquen };
580e6a833eSSamuel Benzaquen struct SmallNonTrivialFunctor {
SmallNonTrivialFunctor__anon90649daa0111::SmallNonTrivialFunctor590e6a833eSSamuel Benzaquen SmallNonTrivialFunctor() {}
SmallNonTrivialFunctor__anon90649daa0111::SmallNonTrivialFunctor600e6a833eSSamuel Benzaquen SmallNonTrivialFunctor(const SmallNonTrivialFunctor&) {}
~SmallNonTrivialFunctor__anon90649daa0111::SmallNonTrivialFunctor610e6a833eSSamuel Benzaquen ~SmallNonTrivialFunctor() {}
operator ()__anon90649daa0111::SmallNonTrivialFunctor620e6a833eSSamuel Benzaquen int operator()(const S*) const { return 0; }
630e6a833eSSamuel Benzaquen };
640e6a833eSSamuel Benzaquen struct LargeTrivialFunctor {
LargeTrivialFunctor__anon90649daa0111::LargeTrivialFunctor650e6a833eSSamuel Benzaquen LargeTrivialFunctor() {
660e6a833eSSamuel Benzaquen // Do not spend time initializing the padding.
670e6a833eSSamuel Benzaquen }
680e6a833eSSamuel Benzaquen int padding[16];
operator ()__anon90649daa0111::LargeTrivialFunctor690e6a833eSSamuel Benzaquen int operator()(const S*) const { return 0; }
700e6a833eSSamuel Benzaquen };
710e6a833eSSamuel Benzaquen struct LargeNonTrivialFunctor {
720e6a833eSSamuel Benzaquen int padding[16];
LargeNonTrivialFunctor__anon90649daa0111::LargeNonTrivialFunctor730e6a833eSSamuel Benzaquen LargeNonTrivialFunctor() {
740e6a833eSSamuel Benzaquen // Do not spend time initializing the padding.
750e6a833eSSamuel Benzaquen }
LargeNonTrivialFunctor__anon90649daa0111::LargeNonTrivialFunctor760e6a833eSSamuel Benzaquen LargeNonTrivialFunctor(const LargeNonTrivialFunctor&) {}
~LargeNonTrivialFunctor__anon90649daa0111::LargeNonTrivialFunctor770e6a833eSSamuel Benzaquen ~LargeNonTrivialFunctor() {}
operator ()__anon90649daa0111::LargeNonTrivialFunctor780e6a833eSSamuel Benzaquen int operator()(const S*) const { return 0; }
790e6a833eSSamuel Benzaquen };
800e6a833eSSamuel Benzaquen
810e6a833eSSamuel Benzaquen using Function = std::function<int(const S*)>;
820e6a833eSSamuel Benzaquen
830e6a833eSSamuel Benzaquen TEST_ALWAYS_INLINE
MakeFunction(FunctionType type,bool opaque=false)840e6a833eSSamuel Benzaquen inline Function MakeFunction(FunctionType type, bool opaque = false) {
850e6a833eSSamuel Benzaquen switch (type) {
860e6a833eSSamuel Benzaquen case FunctionType::Null:
870e6a833eSSamuel Benzaquen return nullptr;
880e6a833eSSamuel Benzaquen case FunctionType::FunctionPointer:
890e6a833eSSamuel Benzaquen return maybeOpaque(FunctionWithS, opaque);
900e6a833eSSamuel Benzaquen case FunctionType::MemberFunctionPointer:
910e6a833eSSamuel Benzaquen return maybeOpaque(&S::function, opaque);
920e6a833eSSamuel Benzaquen case FunctionType::MemberPointer:
930e6a833eSSamuel Benzaquen return maybeOpaque(&S::field, opaque);
940e6a833eSSamuel Benzaquen case FunctionType::SmallTrivialFunctor:
950e6a833eSSamuel Benzaquen return maybeOpaque(SmallTrivialFunctor{}, opaque);
960e6a833eSSamuel Benzaquen case FunctionType::SmallNonTrivialFunctor:
970e6a833eSSamuel Benzaquen return maybeOpaque(SmallNonTrivialFunctor{}, opaque);
980e6a833eSSamuel Benzaquen case FunctionType::LargeTrivialFunctor:
990e6a833eSSamuel Benzaquen return maybeOpaque(LargeTrivialFunctor{}, opaque);
1000e6a833eSSamuel Benzaquen case FunctionType::LargeNonTrivialFunctor:
1010e6a833eSSamuel Benzaquen return maybeOpaque(LargeNonTrivialFunctor{}, opaque);
1020e6a833eSSamuel Benzaquen }
1030e6a833eSSamuel Benzaquen }
1040e6a833eSSamuel Benzaquen
1050e6a833eSSamuel Benzaquen template <class Opacity, class FunctionType>
1060e6a833eSSamuel Benzaquen struct ConstructAndDestroy {
run__anon90649daa0111::ConstructAndDestroy1070e6a833eSSamuel Benzaquen static void run(benchmark::State& state) {
1080e6a833eSSamuel Benzaquen for (auto _ : state) {
1090e6a833eSSamuel Benzaquen if (Opacity() == ::Opacity::kOpaque) {
1100e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(MakeFunction(FunctionType(), true));
1110e6a833eSSamuel Benzaquen } else {
1120e6a833eSSamuel Benzaquen MakeFunction(FunctionType());
1130e6a833eSSamuel Benzaquen }
1140e6a833eSSamuel Benzaquen }
1150e6a833eSSamuel Benzaquen }
1160e6a833eSSamuel Benzaquen
name__anon90649daa0111::ConstructAndDestroy1170e6a833eSSamuel Benzaquen static std::string name() {
1180e6a833eSSamuel Benzaquen return "BM_ConstructAndDestroy" + FunctionType::name() + Opacity::name();
1190e6a833eSSamuel Benzaquen }
1200e6a833eSSamuel Benzaquen };
1210e6a833eSSamuel Benzaquen
1220e6a833eSSamuel Benzaquen template <class FunctionType>
1230e6a833eSSamuel Benzaquen struct Copy {
run__anon90649daa0111::Copy1240e6a833eSSamuel Benzaquen static void run(benchmark::State& state) {
1250e6a833eSSamuel Benzaquen auto value = MakeFunction(FunctionType());
1260e6a833eSSamuel Benzaquen for (auto _ : state) {
1270e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(value);
1280e6a833eSSamuel Benzaquen auto copy = value; // NOLINT
1290e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(copy);
1300e6a833eSSamuel Benzaquen }
1310e6a833eSSamuel Benzaquen }
1320e6a833eSSamuel Benzaquen
name__anon90649daa0111::Copy1330e6a833eSSamuel Benzaquen static std::string name() { return "BM_Copy" + FunctionType::name(); }
1340e6a833eSSamuel Benzaquen };
1350e6a833eSSamuel Benzaquen
1360e6a833eSSamuel Benzaquen template <class FunctionType>
1370e6a833eSSamuel Benzaquen struct Move {
run__anon90649daa0111::Move1380e6a833eSSamuel Benzaquen static void run(benchmark::State& state) {
1390e6a833eSSamuel Benzaquen Function values[2] = {MakeFunction(FunctionType())};
1400e6a833eSSamuel Benzaquen int i = 0;
1410e6a833eSSamuel Benzaquen for (auto _ : state) {
1420e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(values);
1430e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(values[i ^ 1] = std::move(values[i]));
1440e6a833eSSamuel Benzaquen i ^= 1;
1450e6a833eSSamuel Benzaquen }
1460e6a833eSSamuel Benzaquen }
1470e6a833eSSamuel Benzaquen
name__anon90649daa0111::Move1480e6a833eSSamuel Benzaquen static std::string name() {
1490e6a833eSSamuel Benzaquen return "BM_Move" + FunctionType::name();
1500e6a833eSSamuel Benzaquen }
1510e6a833eSSamuel Benzaquen };
1520e6a833eSSamuel Benzaquen
1530e6a833eSSamuel Benzaquen template <class Function1, class Function2>
1540e6a833eSSamuel Benzaquen struct Swap {
run__anon90649daa0111::Swap1550e6a833eSSamuel Benzaquen static void run(benchmark::State& state) {
1560e6a833eSSamuel Benzaquen Function values[2] = {MakeFunction(Function1()), MakeFunction(Function2())};
1570e6a833eSSamuel Benzaquen for (auto _ : state) {
1580e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(values);
1590e6a833eSSamuel Benzaquen values[0].swap(values[1]);
1600e6a833eSSamuel Benzaquen }
1610e6a833eSSamuel Benzaquen }
1620e6a833eSSamuel Benzaquen
skip__anon90649daa0111::Swap1630e6a833eSSamuel Benzaquen static bool skip() { return Function1() > Function2(); }
1640e6a833eSSamuel Benzaquen
name__anon90649daa0111::Swap1650e6a833eSSamuel Benzaquen static std::string name() {
1660e6a833eSSamuel Benzaquen return "BM_Swap" + Function1::name() + Function2::name();
1670e6a833eSSamuel Benzaquen }
1680e6a833eSSamuel Benzaquen };
1690e6a833eSSamuel Benzaquen
1700e6a833eSSamuel Benzaquen template <class FunctionType>
1710e6a833eSSamuel Benzaquen struct OperatorBool {
run__anon90649daa0111::OperatorBool1720e6a833eSSamuel Benzaquen static void run(benchmark::State& state) {
1730e6a833eSSamuel Benzaquen auto f = MakeFunction(FunctionType());
1740e6a833eSSamuel Benzaquen for (auto _ : state) {
1750e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(f);
1760e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(static_cast<bool>(f));
1770e6a833eSSamuel Benzaquen }
1780e6a833eSSamuel Benzaquen }
1790e6a833eSSamuel Benzaquen
name__anon90649daa0111::OperatorBool1800e6a833eSSamuel Benzaquen static std::string name() { return "BM_OperatorBool" + FunctionType::name(); }
1810e6a833eSSamuel Benzaquen };
1820e6a833eSSamuel Benzaquen
1830e6a833eSSamuel Benzaquen template <class FunctionType>
1840e6a833eSSamuel Benzaquen struct Invoke {
run__anon90649daa0111::Invoke1850e6a833eSSamuel Benzaquen static void run(benchmark::State& state) {
1860e6a833eSSamuel Benzaquen S s;
1870e6a833eSSamuel Benzaquen const auto value = MakeFunction(FunctionType());
1880e6a833eSSamuel Benzaquen for (auto _ : state) {
1890e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(value);
1900e6a833eSSamuel Benzaquen benchmark::DoNotOptimize(value(&s));
1910e6a833eSSamuel Benzaquen }
1920e6a833eSSamuel Benzaquen }
1930e6a833eSSamuel Benzaquen
skip__anon90649daa0111::Invoke1940e6a833eSSamuel Benzaquen static bool skip() { return FunctionType() == ::FunctionType::Null; }
1950e6a833eSSamuel Benzaquen
name__anon90649daa0111::Invoke1960e6a833eSSamuel Benzaquen static std::string name() { return "BM_Invoke" + FunctionType::name(); }
1970e6a833eSSamuel Benzaquen };
1980e6a833eSSamuel Benzaquen
1990e6a833eSSamuel Benzaquen template <class FunctionType>
2000e6a833eSSamuel Benzaquen struct InvokeInlined {
run__anon90649daa0111::InvokeInlined2010e6a833eSSamuel Benzaquen static void run(benchmark::State& state) {
2020e6a833eSSamuel Benzaquen S s;
2030e6a833eSSamuel Benzaquen for (auto _ : state) {
2040e6a833eSSamuel Benzaquen MakeFunction(FunctionType())(&s);
2050e6a833eSSamuel Benzaquen }
2060e6a833eSSamuel Benzaquen }
2070e6a833eSSamuel Benzaquen
skip__anon90649daa0111::InvokeInlined2080e6a833eSSamuel Benzaquen static bool skip() { return FunctionType() == ::FunctionType::Null; }
2090e6a833eSSamuel Benzaquen
name__anon90649daa0111::InvokeInlined2100e6a833eSSamuel Benzaquen static std::string name() {
2110e6a833eSSamuel Benzaquen return "BM_InvokeInlined" + FunctionType::name();
2120e6a833eSSamuel Benzaquen }
2130e6a833eSSamuel Benzaquen };
2140e6a833eSSamuel Benzaquen
2150e6a833eSSamuel Benzaquen } // namespace
2160e6a833eSSamuel Benzaquen
main(int argc,char ** argv)2170e6a833eSSamuel Benzaquen int main(int argc, char** argv) {
2180e6a833eSSamuel Benzaquen benchmark::Initialize(&argc, argv);
2190e6a833eSSamuel Benzaquen if (benchmark::ReportUnrecognizedArguments(argc, argv))
2200e6a833eSSamuel Benzaquen return 1;
2210e6a833eSSamuel Benzaquen
2220e6a833eSSamuel Benzaquen makeCartesianProductBenchmark<ConstructAndDestroy, AllOpacity,
2230e6a833eSSamuel Benzaquen AllFunctionTypes>();
2240e6a833eSSamuel Benzaquen makeCartesianProductBenchmark<Copy, AllFunctionTypes>();
2250e6a833eSSamuel Benzaquen makeCartesianProductBenchmark<Move, AllFunctionTypes>();
2260e6a833eSSamuel Benzaquen makeCartesianProductBenchmark<Swap, AllFunctionTypes, AllFunctionTypes>();
2270e6a833eSSamuel Benzaquen makeCartesianProductBenchmark<OperatorBool, AllFunctionTypes>();
2280e6a833eSSamuel Benzaquen makeCartesianProductBenchmark<Invoke, AllFunctionTypes>();
2290e6a833eSSamuel Benzaquen makeCartesianProductBenchmark<InvokeInlined, AllFunctionTypes>();
2300e6a833eSSamuel Benzaquen benchmark::RunSpecifiedBenchmarks();
2310e6a833eSSamuel Benzaquen }
232