File indexing completed on 2025-01-30 10:02:47
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
0011 #define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
0012
0013 #include <catch2/benchmark/catch_clock.hpp>
0014 #include <catch2/benchmark/catch_environment.hpp>
0015 #include <catch2/benchmark/detail/catch_stats.hpp>
0016 #include <catch2/benchmark/detail/catch_measure.hpp>
0017 #include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
0018 #include <catch2/benchmark/catch_clock.hpp>
0019 #include <catch2/internal/catch_unique_ptr.hpp>
0020
0021 #include <algorithm>
0022 #include <vector>
0023 #include <cmath>
0024
0025 namespace Catch {
0026 namespace Benchmark {
0027 namespace Detail {
0028 template <typename Clock>
0029 std::vector<double> resolution(int k) {
0030 std::vector<TimePoint<Clock>> times;
0031 times.reserve(static_cast<size_t>(k + 1));
0032 for ( int i = 0; i < k + 1; ++i ) {
0033 times.push_back( Clock::now() );
0034 }
0035
0036 std::vector<double> deltas;
0037 deltas.reserve(static_cast<size_t>(k));
0038 for ( size_t idx = 1; idx < times.size(); ++idx ) {
0039 deltas.push_back( static_cast<double>(
0040 ( times[idx] - times[idx - 1] ).count() ) );
0041 }
0042
0043 return deltas;
0044 }
0045
0046 constexpr auto warmup_iterations = 10000;
0047 constexpr auto warmup_time = std::chrono::milliseconds(100);
0048 constexpr auto minimum_ticks = 1000;
0049 constexpr auto warmup_seed = 10000;
0050 constexpr auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
0051 constexpr auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
0052 constexpr auto clock_cost_estimation_tick_limit = 100000;
0053 constexpr auto clock_cost_estimation_time = std::chrono::milliseconds(10);
0054 constexpr auto clock_cost_estimation_iterations = 10000;
0055
0056 template <typename Clock>
0057 int warmup() {
0058 return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
0059 .iterations;
0060 }
0061 template <typename Clock>
0062 EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
0063 auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
0064 .result;
0065 return {
0066 FloatDuration<Clock>(mean(r.begin(), r.end())),
0067 classify_outliers(r.begin(), r.end()),
0068 };
0069 }
0070 template <typename Clock>
0071 EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
0072 auto time_limit = (std::min)(
0073 resolution * clock_cost_estimation_tick_limit,
0074 FloatDuration<Clock>(clock_cost_estimation_time_limit));
0075 auto time_clock = [](int k) {
0076 return Detail::measure<Clock>([k] {
0077 for (int i = 0; i < k; ++i) {
0078 volatile auto ignored = Clock::now();
0079 (void)ignored;
0080 }
0081 }).elapsed;
0082 };
0083 time_clock(1);
0084 int iters = clock_cost_estimation_iterations;
0085 auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
0086 std::vector<double> times;
0087 int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
0088 times.reserve(static_cast<size_t>(nsamples));
0089 for ( int s = 0; s < nsamples; ++s ) {
0090 times.push_back( static_cast<double>(
0091 ( time_clock( r.iterations ) / r.iterations )
0092 .count() ) );
0093 }
0094 return {
0095 FloatDuration<Clock>(mean(times.begin(), times.end())),
0096 classify_outliers(times.begin(), times.end()),
0097 };
0098 }
0099
0100 template <typename Clock>
0101 Environment<FloatDuration<Clock>> measure_environment() {
0102 #if defined(__clang__)
0103 # pragma clang diagnostic push
0104 # pragma clang diagnostic ignored "-Wexit-time-destructors"
0105 #endif
0106 static Catch::Detail::unique_ptr<Environment<FloatDuration<Clock>>> env;
0107 #if defined(__clang__)
0108 # pragma clang diagnostic pop
0109 #endif
0110 if (env) {
0111 return *env;
0112 }
0113
0114 auto iters = Detail::warmup<Clock>();
0115 auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
0116 auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
0117
0118 env = Catch::Detail::make_unique<Environment<FloatDuration<Clock>>>( Environment<FloatDuration<Clock>>{resolution, cost} );
0119 return *env;
0120 }
0121 }
0122 }
0123 }
0124
0125 #endif