Reduce compilation costs of benchmarks

We replaced some simple std::algorithm usage by loops, and reduced
header inclusion.
This commit is contained in:
Martin Hořeňovský 2023-04-10 15:03:29 +02:00
parent 7d07efc92b
commit fe64c28925
No known key found for this signature in database
GPG Key ID: DE48307B8B0D381A
7 changed files with 55 additions and 40 deletions

View File

@ -17,8 +17,7 @@
#include <catch2/benchmark/detail/catch_repeat.hpp> #include <catch2/benchmark/detail/catch_repeat.hpp>
#include <catch2/benchmark/detail/catch_run_for_at_least.hpp> #include <catch2/benchmark/detail/catch_run_for_at_least.hpp>
#include <algorithm> #include <vector>
#include <iterator>
namespace Catch { namespace Catch {
namespace Benchmark { namespace Benchmark {
@ -41,14 +40,17 @@ namespace Catch {
Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{})); Detail::run_for_at_least<Clock>(std::chrono::duration_cast<ClockDuration<Clock>>(warmup_time), warmup_iterations, Detail::repeat(now<Clock>{}));
std::vector<FloatDuration<Clock>> times; std::vector<FloatDuration<Clock>> times;
times.reserve(cfg.benchmarkSamples()); const auto num_samples = cfg.benchmarkSamples();
std::generate_n(std::back_inserter(times), cfg.benchmarkSamples(), [this, env] { times.reserve( num_samples );
for ( size_t i = 0; i < num_samples; ++i ) {
Detail::ChronometerModel<Clock> model; Detail::ChronometerModel<Clock> model;
this->benchmark( Chronometer( model, iterations_per_sample ) ); this->benchmark( Chronometer( model, iterations_per_sample ) );
auto sample_time = model.elapsed() - env.clock_cost.mean; auto sample_time = model.elapsed() - env.clock_cost.mean;
if (sample_time < FloatDuration<Clock>::zero()) sample_time = FloatDuration<Clock>::zero(); if ( sample_time < FloatDuration<Clock>::zero() ) {
return sample_time / iterations_per_sample; sample_time = FloatDuration<Clock>::zero();
}); }
times.push_back(sample_time / iterations_per_sample);
}
return times; return times;
} }
}; };

View File

@ -10,14 +10,11 @@
#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED #ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED #define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
#include <catch2/benchmark/catch_clock.hpp>
#include <catch2/benchmark/catch_estimate.hpp> #include <catch2/benchmark/catch_estimate.hpp>
#include <catch2/benchmark/catch_outlier_classification.hpp> #include <catch2/benchmark/catch_outlier_classification.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <algorithm>
#include <vector> #include <vector>
#include <iterator>
namespace Catch { namespace Catch {
namespace Benchmark { namespace Benchmark {
@ -33,7 +30,9 @@ namespace Catch {
operator SampleAnalysis<Duration2>() const { operator SampleAnalysis<Duration2>() const {
std::vector<Duration2> samples2; std::vector<Duration2> samples2;
samples2.reserve(samples.size()); samples2.reserve(samples.size());
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](Duration d) { return Duration2(d); }); for (auto const& d : samples) {
samples2.push_back(Duration2(d));
}
return { return {
CATCH_MOVE(samples2), CATCH_MOVE(samples2),
mean, mean,

View File

@ -16,8 +16,6 @@
#include <catch2/interfaces/catch_interfaces_config.hpp> #include <catch2/interfaces/catch_interfaces_config.hpp>
#include <catch2/internal/catch_move_and_forward.hpp> #include <catch2/internal/catch_move_and_forward.hpp>
#include <algorithm>
#include <iterator>
#include <vector> #include <vector>
namespace Catch { namespace Catch {
@ -28,7 +26,9 @@ namespace Catch {
if (!cfg.benchmarkNoAnalysis()) { if (!cfg.benchmarkNoAnalysis()) {
std::vector<double> samples; std::vector<double> samples;
samples.reserve(static_cast<size_t>(last - first)); samples.reserve(static_cast<size_t>(last - first));
std::transform(first, last, std::back_inserter(samples), [](Duration d) { return d.count(); }); for (auto current = first; current != last; ++current) {
samples.push_back( current->count() );
}
auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end()); auto analysis = Catch::Benchmark::Detail::analyse_samples(cfg.benchmarkConfidenceInterval(), cfg.benchmarkResamples(), samples.begin(), samples.end());
auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end()); auto outliers = Catch::Benchmark::Detail::classify_outliers(samples.begin(), samples.end());
@ -43,7 +43,10 @@ namespace Catch {
}; };
std::vector<Duration> samples2; std::vector<Duration> samples2;
samples2.reserve(samples.size()); samples2.reserve(samples.size());
std::transform(samples.begin(), samples.end(), std::back_inserter(samples2), [](double d) { return Duration(d); }); for (auto s : samples) {
samples2.push_back( Duration( s ) );
}
return { return {
CATCH_MOVE(samples2), CATCH_MOVE(samples2),
wrap_estimate(analysis.mean), wrap_estimate(analysis.mean),

View File

@ -19,7 +19,6 @@
#include <catch2/internal/catch_unique_ptr.hpp> #include <catch2/internal/catch_unique_ptr.hpp>
#include <algorithm> #include <algorithm>
#include <iterator>
#include <vector> #include <vector>
#include <cmath> #include <cmath>
@ -30,13 +29,16 @@ namespace Catch {
std::vector<double> resolution(int k) { std::vector<double> resolution(int k) {
std::vector<TimePoint<Clock>> times; std::vector<TimePoint<Clock>> times;
times.reserve(static_cast<size_t>(k + 1)); times.reserve(static_cast<size_t>(k + 1));
std::generate_n(std::back_inserter(times), k + 1, now<Clock>{}); for ( int i = 0; i < k + 1; ++i ) {
times.push_back( Clock::now() );
}
std::vector<double> deltas; std::vector<double> deltas;
deltas.reserve(static_cast<size_t>(k)); deltas.reserve(static_cast<size_t>(k));
std::transform(std::next(times.begin()), times.end(), times.begin(), for ( size_t idx = 1; idx < times.size(); ++idx ) {
std::back_inserter(deltas), deltas.push_back( static_cast<double>(
[](TimePoint<Clock> a, TimePoint<Clock> b) { return static_cast<double>((a - b).count()); }); ( times[idx] - times[idx - 1] ).count() ) );
}
return deltas; return deltas;
} }
@ -84,9 +86,11 @@ namespace Catch {
std::vector<double> times; std::vector<double> times;
int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed)); int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
times.reserve(static_cast<size_t>(nsamples)); times.reserve(static_cast<size_t>(nsamples));
std::generate_n(std::back_inserter(times), nsamples, [time_clock, &r] { for ( int s = 0; s < nsamples; ++s ) {
return static_cast<double>((time_clock(r.iterations) / r.iterations).count()); times.push_back( static_cast<double>(
}); ( time_clock( r.iterations ) / r.iterations )
.count() ) );
}
return { return {
FloatDuration<Clock>(mean(times.begin(), times.end())), FloatDuration<Clock>(mean(times.begin(), times.end())),
classify_outliers(times.begin(), times.end()), classify_outliers(times.begin(), times.end()),

View File

@ -13,7 +13,7 @@
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <iterator> #include <numeric>
#include <random> #include <random>
@ -35,12 +35,19 @@ using Catch::Benchmark::Detail::sample;
sample out; sample out;
out.reserve(resamples); out.reserve(resamples);
std::generate_n(std::back_inserter(out), resamples, [n, first, &estimator, &dist, &rng] { // We allocate the vector outside the loop to avoid realloc per resample
std::vector<double> resampled; std::vector<double> resampled;
resampled.reserve( n ); resampled.reserve( n );
std::generate_n(std::back_inserter(resampled), n, [first, &dist, &rng] { return first[static_cast<std::ptrdiff_t>(dist(rng))]; }); for ( size_t i = 0; i < resamples; ++i ) {
return estimator(resampled.begin(), resampled.end()); resampled.clear();
}); for ( size_t s = 0; s < n; ++s ) {
resampled.push_back(
first[static_cast<std::ptrdiff_t>( dist( rng ) )] );
}
const auto estimate =
estimator( resampled.begin(), resampled.end() );
out.push_back( estimate );
}
std::sort(out.begin(), out.end()); std::sort(out.begin(), out.end());
return out; return out;
} }

View File

@ -15,8 +15,6 @@
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <numeric>
#include <tuple>
#include <cmath> #include <cmath>
namespace Catch { namespace Catch {
@ -77,13 +75,13 @@ namespace Catch {
sample jack = jackknife(estimator, first, last); sample jack = jackknife(estimator, first, last);
double jack_mean = mean(jack.begin(), jack.end()); double jack_mean = mean(jack.begin(), jack.end());
double sum_squares, sum_cubes; double sum_squares = 0, sum_cubes = 0;
std::tie(sum_squares, sum_cubes) = std::accumulate(jack.begin(), jack.end(), std::make_pair(0., 0.), [jack_mean](std::pair<double, double> sqcb, double x) -> std::pair<double, double> { for (double x : jack) {
auto d = jack_mean - x; auto difference = jack_mean - x;
auto d2 = d * d; auto square = difference * difference;
auto d3 = d2 * d; auto cube = square * difference;
return { sqcb.first + d2, sqcb.second + d3 }; sum_squares += square; sum_cubes += cube;
}); }
double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5)); double accel = sum_cubes / (6 * std::pow(sum_squares, 1.5));
long n = static_cast<long>(resample.size()); long n = static_cast<long>(resample.size());

View File

@ -22,6 +22,8 @@
#include <catch2/benchmark/detail/catch_benchmark_function.hpp> #include <catch2/benchmark/detail/catch_benchmark_function.hpp>
#include <catch2/benchmark/detail/catch_estimate_clock.hpp> #include <catch2/benchmark/detail/catch_estimate_clock.hpp>
#include <numeric>
namespace { namespace {
struct manual_clock { struct manual_clock {
public: public: