1 /* 2 * Created by Joachim on 16/04/2019. 3 * Adapted from donated nonius code. 4 * 5 * Distributed under the Boost Software License, Version 1.0. (See accompanying 6 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 */ 8 9 // Dumb std::function implementation for consistent call overhead 10 11 #ifndef TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED 12 #define TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED 13 14 #include "../catch_chronometer.hpp" 15 #include "catch_complete_invoke.hpp" 16 #include "../../catch_meta.hpp" 17 18 #include <cassert> 19 #include <type_traits> 20 #include <utility> 21 #include <memory> 22 23 namespace Catch { 24 namespace Benchmark { 25 namespace Detail { 26 template <typename T> 27 using Decay = typename std::decay<T>::type; 28 template <typename T, typename U> 29 struct is_related 30 : std::is_same<Decay<T>, Decay<U>> {}; 31 32 /// We need to reinvent std::function because every piece of code that might add overhead 33 /// in a measurement context needs to have consistent performance characteristics so that we 34 /// can account for it in the measurement. 35 /// Implementations of std::function with optimizations that aren't always applicable, like 36 /// small buffer optimizations, are not uncommon. 37 /// This is effectively an implementation of std::function without any such optimizations; 38 /// it may be slow, but it is consistently slow. 39 struct BenchmarkFunction { 40 private: 41 struct callable { 42 virtual void call(Chronometer meter) const = 0; 43 virtual callable* clone() const = 0; 44 virtual ~callable() = default; 45 }; 46 template <typename Fun> 47 struct model : public callable { modelCatch::Benchmark::Detail::BenchmarkFunction::model48 model(Fun&& fun) : fun(std::move(fun)) {} modelCatch::Benchmark::Detail::BenchmarkFunction::model49 model(Fun const& fun) : fun(fun) {} 50 cloneCatch::Benchmark::Detail::BenchmarkFunction::model51 model<Fun>* clone() const override { return new model<Fun>(*this); } 52 callCatch::Benchmark::Detail::BenchmarkFunction::model53 void call(Chronometer meter) const override { 54 call(meter, is_callable<Fun(Chronometer)>()); 55 } callCatch::Benchmark::Detail::BenchmarkFunction::model56 void call(Chronometer meter, std::true_type) const { 57 fun(meter); 58 } callCatch::Benchmark::Detail::BenchmarkFunction::model59 void call(Chronometer meter, std::false_type) const { 60 meter.measure(fun); 61 } 62 63 Fun fun; 64 }; 65 operator ()Catch::Benchmark::Detail::BenchmarkFunction::do_nothing66 struct do_nothing { void operator()() const {} }; 67 68 template <typename T> BenchmarkFunctionCatch::Benchmark::Detail::BenchmarkFunction69 BenchmarkFunction(model<T>* c) : f(c) {} 70 71 public: BenchmarkFunctionCatch::Benchmark::Detail::BenchmarkFunction72 BenchmarkFunction() 73 : f(new model<do_nothing>{ {} }) {} 74 75 template <typename Fun, 76 typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0> BenchmarkFunctionCatch::Benchmark::Detail::BenchmarkFunction77 BenchmarkFunction(Fun&& fun) 78 : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {} 79 BenchmarkFunctionCatch::Benchmark::Detail::BenchmarkFunction80 BenchmarkFunction(BenchmarkFunction&& that) 81 : f(std::move(that.f)) {} 82 BenchmarkFunctionCatch::Benchmark::Detail::BenchmarkFunction83 BenchmarkFunction(BenchmarkFunction const& that) 84 : f(that.f->clone()) {} 85 operator =Catch::Benchmark::Detail::BenchmarkFunction86 BenchmarkFunction& operator=(BenchmarkFunction&& that) { 87 f = std::move(that.f); 88 return *this; 89 } 90 operator =Catch::Benchmark::Detail::BenchmarkFunction91 BenchmarkFunction& operator=(BenchmarkFunction const& that) { 92 f.reset(that.f->clone()); 93 return *this; 94 } 95 operator ()Catch::Benchmark::Detail::BenchmarkFunction96 void operator()(Chronometer meter) const { f->call(meter); } 97 98 private: 99 std::unique_ptr<callable> f; 100 }; 101 } // namespace Detail 102 } // namespace Benchmark 103 } // namespace Catch 104 105 #endif // TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED 106