123 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  *  Created by Joachim on 16/04/2019.
 | |
|  *  Adapted from donated nonius code.
 | |
|  *
 | |
|  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
 | |
|  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | |
|  */
 | |
| 
 | |
|  // Benchmark
 | |
| #ifndef TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED
 | |
| #define TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED
 | |
| 
 | |
| #include "../catch_config.hpp"
 | |
| #include "../catch_context.h"
 | |
| #include "../catch_interfaces_reporter.h"
 | |
| #include "../catch_test_registry.h"
 | |
| 
 | |
| #include "catch_chronometer.hpp"
 | |
| #include "catch_clock.hpp"
 | |
| #include "catch_environment.hpp"
 | |
| #include "catch_execution_plan.hpp"
 | |
| #include "detail/catch_estimate_clock.hpp"
 | |
| #include "detail/catch_complete_invoke.hpp"
 | |
| #include "detail/catch_analyse.hpp"
 | |
| #include "detail/catch_benchmark_function.hpp"
 | |
| #include "detail/catch_run_for_at_least.hpp"
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <functional>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| #include <cmath>
 | |
| 
 | |
| namespace Catch {
 | |
|     namespace Benchmark {
 | |
|         struct Benchmark {
 | |
|             Benchmark(std::string &&name)
 | |
|                 : name(std::move(name)) {}
 | |
| 
 | |
|             template <class FUN>
 | |
|             Benchmark(std::string &&name, FUN &&func)
 | |
|                 : fun(std::move(func)), name(std::move(name)) {}
 | |
| 
 | |
|             template <typename Clock>
 | |
|             ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
 | |
|                 auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
 | |
|                 auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
 | |
|                 auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
 | |
|                 int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
 | |
|                 return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
 | |
|             }
 | |
| 
 | |
|             template <typename Clock = default_clock>
 | |
|             void run() {
 | |
|                 IConfigPtr cfg = getCurrentContext().getConfig();
 | |
| 
 | |
|                 auto env = Detail::measure_environment<Clock>();
 | |
| 
 | |
|                 getResultCapture().benchmarkPreparing(name);
 | |
|                 CATCH_TRY{
 | |
|                     auto plan = user_code([&] {
 | |
|                         return prepare<Clock>(*cfg, env);
 | |
|                     });
 | |
| 
 | |
|                     BenchmarkInfo info {
 | |
|                         name,
 | |
|                         plan.estimated_duration.count(),
 | |
|                         plan.iterations_per_sample,
 | |
|                         cfg->benchmarkSamples(),
 | |
|                         cfg->benchmarkResamples(),
 | |
|                         env.clock_resolution.mean.count(),
 | |
|                         env.clock_cost.mean.count()
 | |
|                     };
 | |
| 
 | |
|                     getResultCapture().benchmarkStarting(info);
 | |
| 
 | |
|                     auto samples = user_code([&] {
 | |
|                         return plan.template run<Clock>(*cfg, env);
 | |
|                     });
 | |
| 
 | |
|                     auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
 | |
|                     BenchmarkStats<FloatDuration<Clock>> stats{ info, analysis.samples, analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
 | |
|                     getResultCapture().benchmarkEnded(stats);
 | |
| 
 | |
|                 } CATCH_CATCH_ALL{
 | |
|                     if (translateActiveException() != Detail::benchmarkErrorMsg) // benchmark errors have been reported, otherwise rethrow.
 | |
|                         std::rethrow_exception(std::current_exception());
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             // sets lambda to be used in fun *and* executes benchmark!
 | |
|             template <typename Fun,
 | |
|                 typename std::enable_if<!Detail::is_related<Fun, Benchmark>::value, int>::type = 0>
 | |
|                 Benchmark & operator=(Fun func) {
 | |
|                 fun = Detail::BenchmarkFunction(func);
 | |
|                 run();
 | |
|                 return *this;
 | |
|             }
 | |
| 
 | |
|             explicit operator bool() {
 | |
|                 return true;
 | |
|             }
 | |
| 
 | |
|         private:
 | |
|             Detail::BenchmarkFunction fun;
 | |
|             std::string name;
 | |
|         };
 | |
|     }
 | |
| } // namespace Catch
 | |
| 
 | |
| #define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
 | |
| #define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
 | |
| 
 | |
| #define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
 | |
|     if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
 | |
|         BenchmarkName = [&](int benchmarkIndex)
 | |
| 
 | |
| #define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
 | |
|     if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
 | |
|         BenchmarkName = [&]
 | |
| 
 | |
| #endif // TWOBLUECUBES_CATCH_BENCHMARK_HPP_INCLUDED
 |