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 // Run a function for a minimum amount of time 10 11 #ifndef TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED 12 #define TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED 13 14 #include "../catch_clock.hpp" 15 #include "../catch_chronometer.hpp" 16 #include "catch_measure.hpp" 17 #include "catch_complete_invoke.hpp" 18 #include "catch_timing.hpp" 19 #include "../../catch_meta.hpp" 20 21 #include <utility> 22 #include <type_traits> 23 24 namespace Catch { 25 namespace Benchmark { 26 namespace Detail { 27 template <typename Clock, typename Fun> measure_one(Fun && fun,int iters,std::false_type)28 TimingOf<Clock, Fun(int)> measure_one(Fun&& fun, int iters, std::false_type) { 29 return Detail::measure<Clock>(fun, iters); 30 } 31 template <typename Clock, typename Fun> measure_one(Fun && fun,int iters,std::true_type)32 TimingOf<Clock, Fun(Chronometer)> measure_one(Fun&& fun, int iters, std::true_type) { 33 Detail::ChronometerModel<Clock> meter; 34 auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); 35 36 return { meter.elapsed(), std::move(result), iters }; 37 } 38 39 template <typename Clock, typename Fun> 40 using run_for_at_least_argument_t = typename std::conditional<is_callable<Fun(Chronometer)>::value, Chronometer, int>::type; 41 42 struct optimized_away_error : std::exception { whatCatch::Benchmark::Detail::optimized_away_error43 const char* what() const noexcept override { 44 return "could not measure benchmark, maybe it was optimized away"; 45 } 46 }; 47 48 template <typename Clock, typename Fun> run_for_at_least(ClockDuration<Clock> how_long,int seed,Fun && fun)49 TimingOf<Clock, Fun(run_for_at_least_argument_t<Clock, Fun>)> run_for_at_least(ClockDuration<Clock> how_long, int seed, Fun&& fun) { 50 auto iters = seed; 51 while (iters < (1 << 30)) { 52 auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>()); 53 54 if (Timing.elapsed >= how_long) { 55 return { Timing.elapsed, std::move(Timing.result), iters }; 56 } 57 iters *= 2; 58 } 59 throw optimized_away_error{}; 60 } 61 } // namespace Detail 62 } // namespace Benchmark 63 } // namespace Catch 64 65 #endif // TWOBLUECUBES_CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED 66