File indexing completed on 2025-01-30 10:02:48
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef CATCH_BENCHMARK_HPP_INCLUDED
0011 #define CATCH_BENCHMARK_HPP_INCLUDED
0012
0013 #include <catch2/catch_user_config.hpp>
0014 #include <catch2/internal/catch_compiler_capabilities.hpp>
0015 #include <catch2/internal/catch_context.hpp>
0016 #include <catch2/internal/catch_move_and_forward.hpp>
0017 #include <catch2/internal/catch_test_failure_exception.hpp>
0018 #include <catch2/internal/catch_unique_name.hpp>
0019 #include <catch2/interfaces/catch_interfaces_capture.hpp>
0020 #include <catch2/interfaces/catch_interfaces_config.hpp>
0021 #include <catch2/interfaces/catch_interfaces_registry_hub.hpp>
0022 #include <catch2/benchmark/detail/catch_benchmark_stats.hpp>
0023 #include <catch2/benchmark/catch_clock.hpp>
0024 #include <catch2/benchmark/catch_environment.hpp>
0025 #include <catch2/benchmark/catch_execution_plan.hpp>
0026 #include <catch2/benchmark/detail/catch_estimate_clock.hpp>
0027 #include <catch2/benchmark/detail/catch_analyse.hpp>
0028 #include <catch2/benchmark/detail/catch_benchmark_function.hpp>
0029 #include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
0030
0031 #include <algorithm>
0032 #include <chrono>
0033 #include <exception>
0034 #include <functional>
0035 #include <string>
0036 #include <vector>
0037 #include <cmath>
0038
0039 namespace Catch {
0040 namespace Benchmark {
0041 struct Benchmark {
0042 Benchmark(std::string&& benchmarkName)
0043 : name(CATCH_MOVE(benchmarkName)) {}
0044
0045 template <class FUN>
0046 Benchmark(std::string&& benchmarkName , FUN &&func)
0047 : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
0048
0049 template <typename Clock>
0050 ExecutionPlan<FloatDuration<Clock>> prepare(const IConfig &cfg, Environment<FloatDuration<Clock>> env) const {
0051 auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
0052 auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
0053 auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(run_time), 1, fun);
0054 int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
0055 return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast<FloatDuration<Clock>>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
0056 }
0057
0058 template <typename Clock = default_clock>
0059 void run() {
0060 auto const* cfg = getCurrentContext().getConfig();
0061
0062 auto env = Detail::measure_environment<Clock>();
0063
0064 getResultCapture().benchmarkPreparing(name);
0065 CATCH_TRY{
0066 auto plan = user_code([&] {
0067 return prepare<Clock>(*cfg, env);
0068 });
0069
0070 BenchmarkInfo info {
0071 CATCH_MOVE(name),
0072 plan.estimated_duration.count(),
0073 plan.iterations_per_sample,
0074 cfg->benchmarkSamples(),
0075 cfg->benchmarkResamples(),
0076 env.clock_resolution.mean.count(),
0077 env.clock_cost.mean.count()
0078 };
0079
0080 getResultCapture().benchmarkStarting(info);
0081
0082 auto samples = user_code([&] {
0083 return plan.template run<Clock>(*cfg, env);
0084 });
0085
0086 auto analysis = Detail::analyse(*cfg, env, samples.begin(), samples.end());
0087 BenchmarkStats<FloatDuration<Clock>> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
0088 getResultCapture().benchmarkEnded(stats);
0089 } CATCH_CATCH_ANON (TestFailureException const&) {
0090 getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
0091 } CATCH_CATCH_ALL{
0092 getResultCapture().benchmarkFailed(translateActiveException());
0093
0094
0095 std::rethrow_exception(std::current_exception());
0096 }
0097 }
0098
0099
0100 template <typename Fun, std::enable_if_t<!Detail::is_related<Fun, Benchmark>::value, int> = 0>
0101 Benchmark & operator=(Fun func) {
0102 auto const* cfg = getCurrentContext().getConfig();
0103 if (!cfg->skipBenchmarks()) {
0104 fun = Detail::BenchmarkFunction(func);
0105 run();
0106 }
0107 return *this;
0108 }
0109
0110 explicit operator bool() {
0111 return true;
0112 }
0113
0114 private:
0115 Detail::BenchmarkFunction fun;
0116 std::string name;
0117 };
0118 }
0119 }
0120
0121 #define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
0122 #define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
0123
0124 #define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
0125 if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
0126 BenchmarkName = [&](int benchmarkIndex)
0127
0128 #define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
0129 if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
0130 BenchmarkName = [&]
0131
0132 #if defined(CATCH_CONFIG_PREFIX_ALL)
0133
0134 #define CATCH_BENCHMARK(...) \
0135 INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
0136 #define CATCH_BENCHMARK_ADVANCED(name) \
0137 INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
0138
0139 #else
0140
0141 #define BENCHMARK(...) \
0142 INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
0143 #define BENCHMARK_ADVANCED(name) \
0144 INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
0145
0146 #endif
0147
0148 #endif