Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/Progmasoft/Catch3/Benchmark
diff options
context:
space:
mode:
authorLeitwolf2026-10-25 10:31:36 +0300
committerGitHub2026-10-25 10:31:36 +0300
commitd2e3e074bb2e1b8ffd9fc990d0b87667ea602f58 (patch)
tree0bce4462b2e190c39b3e1c5f697e3e4abd1a5e2a /src/Progmasoft/Catch3/Benchmark
parent13f81a480a93807c14dddb5abdb97355ced4d4c5 (diff)
parent126dc333564cb72b5115d9a9242d66694694b6d0 (diff)
downloadcatch3-d2e3e074bb2e1b8ffd9fc990d0b87667ea602f58.tar.gz
Merge pull request #18 from Progmasoft/build/catch3-identity
Give Catch3 its own build names and headers
Diffstat (limited to 'src/Progmasoft/Catch3/Benchmark')
-rw-r--r--src/Progmasoft/Catch3/Benchmark/All.hpp44
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Benchmark.cpp54
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Benchmark.hpp220
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Chronometer.cpp17
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Chronometer.hpp75
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Clock.hpp25
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Constructor.hpp80
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/Analyse.cpp85
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/Analyse.hpp25
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/BenchmarkFunction.cpp23
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/BenchmarkFunction.hpp85
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/BenchmarkStats.hpp47
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/BenchmarkStatsFwd.hpp23
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/CompleteInvoke.hpp56
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/EstimateClock.hpp124
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/Measure.hpp30
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/Repeat.hpp34
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/RunForAtLeast.cpp31
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/RunForAtLeast.hpp63
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/Stats.cpp393
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/Stats.hpp58
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Detail/Timing.hpp27
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Environment.hpp27
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Estimate.hpp23
-rw-r--r--src/Progmasoft/Catch3/Benchmark/ExecutionPlan.hpp56
-rw-r--r--src/Progmasoft/Catch3/Benchmark/Optimizer.hpp83
-rw-r--r--src/Progmasoft/Catch3/Benchmark/OutlierClassification.hpp26
-rw-r--r--src/Progmasoft/Catch3/Benchmark/SampleAnalysis.hpp29
28 files changed, 1863 insertions, 0 deletions
diff --git a/src/Progmasoft/Catch3/Benchmark/All.hpp b/src/Progmasoft/Catch3/Benchmark/All.hpp
new file mode 100644
index 00000000..bc0d9526
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/All.hpp
@@ -0,0 +1,44 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+/** \file
+ * This is a convenience header for Catch2's benchmarking. It includes
+ * **all** of Catch2 headers related to benchmarking.
+ *
+ * Generally the Catch2 users should use specific includes they need,
+ * but this header can be used instead for ease-of-experimentation, or
+ * just plain convenience, at the cost of (significantly) increased
+ * compilation times.
+ *
+ * When a new header is added to either the `benchmark` folder, or to
+ * the corresponding internal (detail) subfolder, it should be added here.
+ */
+
+#pragma once
+
+#include <Progmasoft/Catch3/Benchmark/Benchmark.hpp>
+#include <Progmasoft/Catch3/Benchmark/Chronometer.hpp>
+#include <Progmasoft/Catch3/Benchmark/Clock.hpp>
+#include <Progmasoft/Catch3/Benchmark/Constructor.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/Analyse.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/BenchmarkFunction.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/BenchmarkStats.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/BenchmarkStatsFwd.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/CompleteInvoke.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/EstimateClock.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/Measure.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/Repeat.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/RunForAtLeast.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/Stats.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/Timing.hpp>
+#include <Progmasoft/Catch3/Benchmark/Environment.hpp>
+#include <Progmasoft/Catch3/Benchmark/Estimate.hpp>
+#include <Progmasoft/Catch3/Benchmark/ExecutionPlan.hpp>
+#include <Progmasoft/Catch3/Benchmark/Optimizer.hpp>
+#include <Progmasoft/Catch3/Benchmark/OutlierClassification.hpp>
+#include <Progmasoft/Catch3/Benchmark/SampleAnalysis.hpp>
+
diff --git a/src/Progmasoft/Catch3/Benchmark/Benchmark.cpp b/src/Progmasoft/Catch3/Benchmark/Benchmark.cpp
new file mode 100644
index 00000000..8967b12c
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/Benchmark.cpp
@@ -0,0 +1,54 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#include <Progmasoft/Catch3/Benchmark/Benchmark.hpp>
+
+#include <algorithm>
+#include <chrono>
+#include <cmath>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+
+ Environment measure_environment_default() {
+ return Detail::measure_environment<default_clock>();
+ }
+
+ ExecutionPlan prepare_default( const IConfig& cfg,
+ Environment env,
+ BenchmarkFunction&& fun ) {
+ // This mirrors Benchmark::prepare<default_clock>(), but with the
+ // clock fixed so it is instantiated once here in the library.
+ 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<default_clock>(
+ std::chrono::duration_cast<IDuration>( 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(),
+ CATCH_MOVE( fun ),
+ std::chrono::duration_cast<FDuration>(
+ cfg.benchmarkWarmupTime() ),
+ Detail::warmup_iterations };
+ }
+
+ std::vector<FDuration> run_plan_default( ExecutionPlan const& plan,
+ const IConfig& cfg,
+ Environment env ) {
+ return plan.run<default_clock>( cfg, env );
+ }
+
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
diff --git a/src/Progmasoft/Catch3/Benchmark/Benchmark.hpp b/src/Progmasoft/Catch3/Benchmark/Benchmark.hpp
new file mode 100644
index 00000000..f19c6603
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/Benchmark.hpp
@@ -0,0 +1,220 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+// Adapted from donated nonius code.
+
+#pragma once
+
+#include <Progmasoft/Catch3/UserConfig.hpp>
+#include <Progmasoft/Catch3/Internal/CompilerCapabilities.hpp>
+#include <Progmasoft/Catch3/Internal/Context.hpp>
+#include <Progmasoft/Catch3/Internal/MoveAndForward.hpp>
+#include <Progmasoft/Catch3/Internal/TestFailureException.hpp>
+#include <Progmasoft/Catch3/Internal/UniqueName.hpp>
+#include <Progmasoft/Catch3/Interfaces/IResultCapture.hpp>
+#include <Progmasoft/Catch3/Interfaces/IConfig.hpp>
+#include <Progmasoft/Catch3/Interfaces/IRegistryHub.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/BenchmarkStats.hpp>
+#include <Progmasoft/Catch3/Benchmark/Clock.hpp>
+#include <Progmasoft/Catch3/Benchmark/Environment.hpp>
+#include <Progmasoft/Catch3/Benchmark/ExecutionPlan.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/EstimateClock.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/Analyse.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/BenchmarkFunction.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/RunForAtLeast.hpp>
+
+#include <algorithm>
+#include <chrono>
+#include <exception>
+#include <string>
+#include <cmath>
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename Clock>
+ ExecutionPlan prepare( const IConfig& cfg,
+ Environment env,
+ BenchmarkFunction&& fun ) {
+ 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<IDuration>( 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(),
+ CATCH_MOVE( fun ),
+ std::chrono::duration_cast<FDuration>(
+ cfg.benchmarkWarmupTime() ),
+ Detail::warmup_iterations };
+ }
+
+ // These are wrappers for their respective function templated
+ // over `default_clock`. This allows outlining the usual use
+ // of the template into single TU and save on compilation costs.
+
+ Environment measure_environment_default();
+ ExecutionPlan prepare_default( const IConfig& cfg,
+ Environment env,
+ BenchmarkFunction&& fun );
+ std::vector<FDuration> run_plan_default( ExecutionPlan const& plan,
+ const IConfig& cfg,
+ Environment env );
+
+ template <typename Clock>
+ std::enable_if_t<std::is_same<Clock, default_clock>::value,
+ Environment>
+ measureEnvironmentDispatch() {
+ return measure_environment_default();
+ }
+ template <typename Clock>
+ std::enable_if_t<!std::is_same<Clock, default_clock>::value,
+ Environment>
+ measureEnvironmentDispatch() {
+ return measure_environment<Clock>();
+ }
+
+ template <typename Clock>
+ std::enable_if_t<std::is_same<Clock, default_clock>::value,
+ std::vector<FDuration>>
+ runPlanDispatch( ExecutionPlan const& plan,
+ const IConfig& cfg,
+ Environment env ) {
+ return run_plan_default( plan, cfg, env );
+ }
+ template <typename Clock>
+ std::enable_if_t<!std::is_same<Clock, default_clock>::value,
+ std::vector<FDuration>>
+ runPlanDispatch( ExecutionPlan const& plan,
+ const IConfig& cfg,
+ Environment env ) {
+ return plan.template run<Clock>( cfg, env );
+ }
+
+ template <typename Clock>
+ std::enable_if_t<std::is_same<Clock, default_clock>::value,
+ ExecutionPlan>
+ prepareDispatch( const IConfig& cfg,
+ Environment env,
+ BenchmarkFunction&& fun ) {
+ return prepare_default( cfg, env, CATCH_MOVE( fun ) );
+ }
+ template <typename Clock>
+ std::enable_if_t<!std::is_same<Clock, default_clock>::value,
+ ExecutionPlan>
+ prepareDispatch( const IConfig& cfg,
+ Environment env,
+ BenchmarkFunction&& fun ) {
+ return prepare<Clock>( cfg, env, CATCH_MOVE( fun ) );
+ }
+ } // namespace Detail
+
+ struct Benchmark {
+ Benchmark(std::string&& benchmarkName)
+ : name(CATCH_MOVE(benchmarkName)) {}
+
+ template <class FUN>
+ Benchmark(std::string&& benchmarkName , FUN &&func)
+ : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
+
+ template <typename Clock = default_clock>
+ void run() {
+ static_assert( Clock::is_steady,
+ "Benchmarking clock should be steady" );
+ auto const* cfg = getCurrentContext().getConfig();
+
+ auto env = Detail::measureEnvironmentDispatch<Clock>();
+
+ getResultCapture().benchmarkPreparing(name);
+ CATCH_TRY{
+ auto plan = user_code([&] {
+ return Detail::prepareDispatch<Clock>( *cfg, env, CATCH_MOVE(fun) );
+ });
+
+ BenchmarkInfo info {
+ CATCH_MOVE(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 Detail::runPlanDispatch<Clock>( plan, *cfg, env );
+ });
+
+ auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size());
+ BenchmarkStats<> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
+ getResultCapture().benchmarkEnded(stats);
+ } CATCH_CATCH_ALL {
+ getResultCapture().benchmarkFailed(translateActiveException());
+ // We let the exception go further up so that the
+ // test case is marked as failed.
+ std::rethrow_exception(std::current_exception());
+ }
+ }
+
+ // sets lambda to be used in fun *and* executes benchmark!
+ template <typename Fun, std::enable_if_t<!Detail::is_related_v<Fun, Benchmark>, int> = 0>
+ Benchmark & operator=(Fun func) {
+ auto const* cfg = getCurrentContext().getConfig();
+ if (!cfg->skipBenchmarks()) {
+ 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 = [&]
+
+#if defined(CATCH_CONFIG_PREFIX_ALL)
+
+#define CATCH_BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define CATCH_BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
+
+#else
+
+#define BENCHMARK(...) \
+ INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
+#define BENCHMARK_ADVANCED(name) \
+ INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
+
+#endif
+
diff --git a/src/Progmasoft/Catch3/Benchmark/Chronometer.cpp b/src/Progmasoft/Catch3/Benchmark/Chronometer.cpp
new file mode 100644
index 00000000..78cbb97e
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/Chronometer.cpp
@@ -0,0 +1,17 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+
+#include <Progmasoft/Catch3/Benchmark/Chronometer.hpp>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ ChronometerConcept::~ChronometerConcept() = default;
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
diff --git a/src/Progmasoft/Catch3/Benchmark/Chronometer.hpp b/src/Progmasoft/Catch3/Benchmark/Chronometer.hpp
new file mode 100644
index 00000000..e5550e57
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/Chronometer.hpp
@@ -0,0 +1,75 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+// Adapted from donated nonius code.
+
+#pragma once
+
+#include <Progmasoft/Catch3/Benchmark/Clock.hpp>
+#include <Progmasoft/Catch3/Benchmark/Optimizer.hpp>
+#include <Progmasoft/Catch3/Internal/Meta.hpp>
+#include <Progmasoft/Catch3/Internal/MoveAndForward.hpp>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ struct ChronometerConcept {
+ virtual void start() = 0;
+ virtual void finish() = 0;
+ virtual ~ChronometerConcept(); // = default;
+
+ ChronometerConcept() = default;
+ ChronometerConcept(ChronometerConcept const&) = default;
+ ChronometerConcept& operator=(ChronometerConcept const&) = default;
+ };
+ template <typename Clock>
+ struct ChronometerModel final : public ChronometerConcept {
+ void start() override { started = Clock::now(); }
+ void finish() override { finished = Clock::now(); }
+
+ IDuration elapsed() const {
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(
+ finished - started );
+ }
+
+ TimePoint<Clock> started;
+ TimePoint<Clock> finished;
+ };
+ } // namespace Detail
+
+ struct Chronometer {
+ public:
+ template <typename Fun>
+ void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable<Fun(int)>()); }
+
+ int runs() const { return repeats; }
+
+ Chronometer(Detail::ChronometerConcept& meter, int repeats_)
+ : impl(&meter)
+ , repeats(repeats_) {}
+
+ private:
+ template <typename Fun>
+ void measure(Fun&& fun, std::false_type) {
+ measure([&fun](int) { return fun(); }, std::true_type());
+ }
+
+ template <typename Fun>
+ void measure(Fun&& fun, std::true_type) {
+ Detail::optimizer_barrier();
+ impl->start();
+ for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i);
+ impl->finish();
+ Detail::optimizer_barrier();
+ }
+
+ Detail::ChronometerConcept* impl;
+ int repeats;
+ };
+ } // namespace Benchmark
+} // namespace Catch
+
diff --git a/src/Progmasoft/Catch3/Benchmark/Clock.hpp b/src/Progmasoft/Catch3/Benchmark/Clock.hpp
new file mode 100644
index 00000000..b2cca2e9
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/Clock.hpp
@@ -0,0 +1,25 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+// Adapted from donated nonius code.
+
+#pragma once
+
+#include <chrono>
+
+namespace Catch {
+ namespace Benchmark {
+ using IDuration = std::chrono::nanoseconds;
+ using FDuration = std::chrono::duration<double, std::nano>;
+
+ template <typename Clock>
+ using TimePoint = typename Clock::time_point;
+
+ using default_clock = std::chrono::steady_clock;
+ } // namespace Benchmark
+} // namespace Catch
+
diff --git a/src/Progmasoft/Catch3/Benchmark/Constructor.hpp b/src/Progmasoft/Catch3/Benchmark/Constructor.hpp
new file mode 100644
index 00000000..5d054620
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/Constructor.hpp
@@ -0,0 +1,80 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+// Adapted from donated nonius code.
+
+#pragma once
+
+#include <Progmasoft/Catch3/Internal/MoveAndForward.hpp>
+
+#include <type_traits>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ template <typename T, bool Destruct>
+ struct ObjectStorage
+ {
+ ObjectStorage() = default;
+
+ ObjectStorage(const ObjectStorage& other)
+ {
+ new(&data) T(other.stored_object());
+ }
+
+ ObjectStorage(ObjectStorage&& other)
+ {
+ new(data) T(CATCH_MOVE(other.stored_object()));
+ }
+
+ ~ObjectStorage() { destruct_on_exit<T>(); }
+
+ template <typename... Args>
+ void construct(Args&&... args)
+ {
+ new (data) T(CATCH_FORWARD(args)...);
+ }
+
+ template <bool AllowManualDestruction = !Destruct>
+ std::enable_if_t<AllowManualDestruction> destruct()
+ {
+ stored_object().~T();
+ }
+
+ private:
+ // If this is a constructor benchmark, destruct the underlying object
+ template <typename U>
+ void destruct_on_exit(std::enable_if_t<Destruct, U>* = nullptr) { destruct<true>(); }
+ // Otherwise, don't
+ template <typename U>
+ void destruct_on_exit(std::enable_if_t<!Destruct, U>* = nullptr) { }
+
+#if defined( __GNUC__ ) && __GNUC__ <= 6
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+ T& stored_object() { return *reinterpret_cast<T*>( data ); }
+
+ T const& stored_object() const {
+ return *reinterpret_cast<T const*>( data );
+ }
+#if defined( __GNUC__ ) && __GNUC__ <= 6
+# pragma GCC diagnostic pop
+#endif
+
+ alignas( T ) unsigned char data[sizeof( T )]{};
+ };
+ } // namespace Detail
+
+ template <typename T>
+ using storage_for = Detail::ObjectStorage<T, true>;
+
+ template <typename T>
+ using destructable_object = Detail::ObjectStorage<T, false>;
+ } // namespace Benchmark
+} // namespace Catch
+
diff --git a/src/Progmasoft/Catch3/Benchmark/Detail/Analyse.cpp b/src/Progmasoft/Catch3/Benchmark/Detail/Analyse.cpp
new file mode 100644
index 00000000..eb1e2847
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/Detail/Analyse.cpp
@@ -0,0 +1,85 @@
+
+// Copyright Catch2 Authors
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE.txt or copy at
+// https://www.boost.org/LICENSE_1_0.txt)
+
+// SPDX-License-Identifier: BSL-1.0
+// Adapted from donated nonius code.
+
+#include <Progmasoft/Catch3/Benchmark/Detail/Analyse.hpp>
+#include <Progmasoft/Catch3/Benchmark/Clock.hpp>
+#include <Progmasoft/Catch3/Benchmark/SampleAnalysis.hpp>
+#include <Progmasoft/Catch3/Benchmark/Detail/Stats.hpp>
+#include <Progmasoft/Catch3/Interfaces/IConfig.hpp>
+#include <Progmasoft/Catch3/Internal/MoveAndForward.hpp>
+
+#include <vector>
+
+namespace Catch {
+ namespace Benchmark {
+ namespace Detail {
+ SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) {
+ if (!cfg.benchmarkNoAnalysis()) {
+ std::vector<double> samples;
+ samples.reserve(static_cast<size_t>(last - first));
+ for (auto current = first; current != last; ++current) {
+ samples.push_back( current->count() );
+ }
+
+ auto analysis = Catch::Benchmark::Detail::analyse_samples(
+ cfg.benchmarkConfidenceInterval(),
+ cfg.benchmarkResamples(),
+ samples.data(),
+ samples.data() + samples.size() );
+ auto outliers = Catch::Benchmark::Detail::classify_outliers(
+ samples.data(), samples.data() + samples.size() );
+
+ auto wrap_estimate = [](Estimate<double> e) {
+ return Estimate<FDuration>{
+ FDuration( e.point ),
+ FDuration( e.lower_bound ),
+ FDuration( e.upper_bound ),
+ e.confidence_interval,
+ };
+ };
+ std::vector<FDuration> samples2;
+ samples2.reserve(samples.size());
+ for (auto s : samples) {
+ samples2.push_back( FDuration( s ) );
+ }
+
+ return {
+ CATCH_MOVE(samples2),
+ wrap_estimate(analysis.mean),
+ wrap_estimate(analysis.standard_deviation),
+ outliers,
+ analysis.outlier_variance,
+ };
+ } else {
+ std::vector<FDuration> samples;
+ samples.reserve(static_cast<size_t>(last - first));
+
+ FDuration mean = FDuration(0);
+ int i = 0;
+ for (auto it = first; it < last; ++it, ++i) {
+ samples.push_back(*it);
+ mean += *it;
+ }
+ mean /= i;
+
+ return SampleAnalysis{
+ CATCH_MOVE(samples),
+ Estimate<FDuration>{ mean, mean, mean, 0.0 },
+ Estimate<FDuration>{ FDuration( 0 ),
+ FDuration( 0 ),
+ FDuration( 0 ),
+ 0.0 },
+ OutlierClassification{},
+ 0.0
+ };
+ }
+ }
+ } // namespace Detail
+ } // namespace Benchmark
+} // namespace Catch
diff --git a/src/Progmasoft/Catch3/Benchmark/Detail/Analyse.hpp b/src/Progmasoft/Catch3/Benchmark/Detail/Analyse.hpp
new file mode 100644
index 00000000..1310a582
--- /dev/null
+++ b/src/Progmasoft/Catch3/Benchmark/Detail/Analyse.hpp
@@ -0,0 +1,25 @@
+
+// Copyright Catch2 Authors