mirror of
https://github.com/catchorg/Catch2.git
synced 2024-11-30 17:23:29 +01:00
ce2560ca95
Changes done to Nonius: * Moved things into "Catch::Benchmark" namespace * Benchmarks were integrated with `TEST_CASE`/`SECTION`/`GENERATE` macros * Removed Nonius's parameters for benchmarks, Generators should be used instead * Added relevant methods to the reporter interface (default-implemented, to avoid breaking existing 3rd party reporters) * Async processing is guarded with `_REENTRANT` macro for GCC/Clang, used by default on MSVC * Added a macro `CATCH_CONFIG_DISABLE_BENCHMARKING` that removes all traces of benchmarking from Catch
114 lines
4.8 KiB
C++
114 lines
4.8 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)
|
|
*/
|
|
|
|
// Environment measurement
|
|
|
|
#ifndef TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED
|
|
#define TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED
|
|
|
|
#include "../catch_clock.hpp"
|
|
#include "../catch_environment.hpp"
|
|
#include "catch_stats.hpp"
|
|
#include "catch_measure.hpp"
|
|
#include "catch_run_for_at_least.hpp"
|
|
#include "../catch_clock.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <tuple>
|
|
#include <vector>
|
|
#include <cmath>
|
|
|
|
namespace Catch {
|
|
namespace Benchmark {
|
|
namespace Detail {
|
|
template <typename Clock>
|
|
std::vector<double> resolution(int k) {
|
|
std::vector<TimePoint<Clock>> times;
|
|
times.reserve(k + 1);
|
|
std::generate_n(std::back_inserter(times), k + 1, now<Clock>{});
|
|
|
|
std::vector<double> deltas;
|
|
deltas.reserve(k);
|
|
std::transform(std::next(times.begin()), times.end(), times.begin(),
|
|
std::back_inserter(deltas),
|
|
[](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); });
|
|
|
|
return deltas;
|
|
}
|
|
|
|
const auto warmup_iterations = 10000;
|
|
const auto warmup_time = std::chrono::milliseconds(100);
|
|
const auto minimum_ticks = 1000;
|
|
const auto warmup_seed = 10000;
|
|
const auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
|
|
const auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
|
|
const auto clock_cost_estimation_tick_limit = 100000;
|
|
const auto clock_cost_estimation_time = std::chrono::milliseconds(10);
|
|
const auto clock_cost_estimation_iterations = 10000;
|
|
|
|
template <typename Clock>
|
|
int warmup() {
|
|
return run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_seed, &resolution<Clock>)
|
|
.iterations;
|
|
}
|
|
template <typename Clock>
|
|
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_resolution(int iterations) {
|
|
auto r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_resolution_estimation_time), iterations, &resolution<Clock>)
|
|
.result;
|
|
return {
|
|
FloatDuration<Clock>(mean(r.begin(), r.end())),
|
|
classify_outliers(r.begin(), r.end()),
|
|
};
|
|
}
|
|
template <typename Clock>
|
|
EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(FloatDuration<Clock> resolution) {
|
|
auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration<Clock>(clock_cost_estimation_time_limit));
|
|
auto time_clock = [](int k) {
|
|
return Detail::measure<Clock>([k] {
|
|
for (int i = 0; i < k; ++i) {
|
|
volatile auto ignored = Clock::now();
|
|
(void)ignored;
|
|
}
|
|
}).elapsed;
|
|
};
|
|
time_clock(1);
|
|
int iters = clock_cost_estimation_iterations;
|
|
auto&& r = run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(clock_cost_estimation_time), iters, time_clock);
|
|
std::vector<double> times;
|
|
int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
|
|
times.reserve(nsamples);
|
|
std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] {
|
|
return static_cast<double>((time_clock(r.iterations) / r.iterations).count());
|
|
});
|
|
return {
|
|
FloatDuration<Clock>(mean(times.begin(), times.end())),
|
|
classify_outliers(times.begin(), times.end()),
|
|
};
|
|
}
|
|
|
|
template <typename Clock>
|
|
Environment<FloatDuration<Clock>> measure_environment() {
|
|
static Environment<FloatDuration<Clock>>* env = nullptr;
|
|
if (env) {
|
|
return *env;
|
|
}
|
|
|
|
auto iters = Detail::warmup<Clock>();
|
|
auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
|
|
auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
|
|
|
|
env = new Environment<FloatDuration<Clock>>{ resolution, cost };
|
|
return *env;
|
|
}
|
|
} // namespace Detail
|
|
} // namespace Benchmark
|
|
} // namespace Catch
|
|
|
|
#endif // TWOBLUECUBES_CATCH_DETAIL_ESTIMATE_CLOCK_HPP_INCLUDED
|