mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-10-30 19:57:10 +01:00 
			
		
		
		
	Integrate Nonius benchmark into Catch2
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
This commit is contained in:
		 Joachim Meyer
					Joachim Meyer
				
			
				
					committed by
					
						 Martin Hořeňovský
						Martin Hořeňovský
					
				
			
			
				
	
			
			
			 Martin Hořeňovský
						Martin Hořeňovský
					
				
			
						parent
						
							00347f1e79
						
					
				
				
					commit
					ce2560ca95
				
			| @@ -18,6 +18,7 @@ set(TEST_SOURCES | ||||
|         ${SELF_TEST_DIR}/TestMain.cpp | ||||
|         ${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp | ||||
|         ${SELF_TEST_DIR}/IntrospectiveTests/GeneratorsImpl.tests.cpp | ||||
|         ${SELF_TEST_DIR}/IntrospectiveTests/InternalBenchmark.tests.cpp | ||||
|         ${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp | ||||
|         ${SELF_TEST_DIR}/IntrospectiveTests/Tag.tests.cpp | ||||
|         ${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp | ||||
| @@ -79,6 +80,28 @@ CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external) | ||||
|  | ||||
|  | ||||
| # Please keep these ordered alphabetically | ||||
| set(BENCHMARK_HEADERS | ||||
| 		${HEADER_DIR}/internal/benchmark/catch_benchmark.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_chronometer.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_clock.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_constructor.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_environment.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_estimate.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_execution_plan.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_optimizer.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_outlier_classification.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/catch_sample_analysis.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_analyse.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_benchmark_function.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_complete_invoke.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_estimate_clock.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_measure.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_repeat.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_run_for_at_least.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_stats.hpp | ||||
|         ${HEADER_DIR}/internal/benchmark/detail/catch_timing.hpp | ||||
| ) | ||||
| SOURCE_GROUP("benchmark" FILES ${BENCHMARK_HEADERS}) | ||||
| set(INTERNAL_HEADERS | ||||
|         ${HEADER_DIR}/internal/catch_approx.h | ||||
|         ${HEADER_DIR}/internal/catch_assertionhandler.h | ||||
| @@ -138,7 +161,6 @@ set(INTERNAL_HEADERS | ||||
|         ${HEADER_DIR}/internal/catch_reporter_registry.h | ||||
|         ${HEADER_DIR}/internal/catch_result_type.h | ||||
|         ${HEADER_DIR}/internal/catch_run_context.h | ||||
|         ${HEADER_DIR}/internal/catch_benchmark.h | ||||
|         ${HEADER_DIR}/internal/catch_section.h | ||||
|         ${HEADER_DIR}/internal/catch_section_info.h | ||||
|         ${HEADER_DIR}/internal/catch_session.h | ||||
| @@ -174,7 +196,6 @@ set(IMPL_SOURCES | ||||
|         ${HEADER_DIR}/internal/catch_approx.cpp | ||||
|         ${HEADER_DIR}/internal/catch_assertionhandler.cpp | ||||
|         ${HEADER_DIR}/internal/catch_assertionresult.cpp | ||||
|         ${HEADER_DIR}/internal/catch_benchmark.cpp | ||||
|         ${HEADER_DIR}/internal/catch_capture_matchers.cpp | ||||
|         ${HEADER_DIR}/internal/catch_commandline.cpp | ||||
|         ${HEADER_DIR}/internal/catch_common.cpp | ||||
| @@ -269,6 +290,7 @@ set(HEADERS | ||||
|         ${EXTERNAL_HEADERS} | ||||
|         ${INTERNAL_HEADERS} | ||||
|         ${REPORTER_HEADERS} | ||||
| 		${BENCHMARK_HEADERS} | ||||
|         ) | ||||
|  | ||||
| # Provide some groupings for IDEs | ||||
|   | ||||
| @@ -462,4 +462,32 @@ TEST_CASE( "Process can be configured on command line", "[config][command-line]" | ||||
| #endif | ||||
|         } | ||||
|     } | ||||
|  | ||||
| #ifndef CATCH_CONFIG_DISABLE_BENCHMARKING  | ||||
|     SECTION("Benchmark options") { | ||||
|         SECTION("samples") { | ||||
|             CHECK(cli.parse({ "test", "--benchmark-samples=200" })); | ||||
|  | ||||
|             REQUIRE(config.benchmarkSamples == 200); | ||||
|         } | ||||
|          | ||||
|         SECTION("resamples") { | ||||
|             CHECK(cli.parse({ "test", "--benchmark-resamples=20000" })); | ||||
|  | ||||
|             REQUIRE(config.benchmarkResamples == 20000); | ||||
|         } | ||||
|  | ||||
|         SECTION("resamples") { | ||||
|             CHECK(cli.parse({ "test", "--benchmark-confidence-interval=0.99" })); | ||||
|  | ||||
|             REQUIRE(config.benchmarkConfidenceInterval == Catch::Detail::Approx(0.99)); | ||||
|         } | ||||
|  | ||||
|         SECTION("resamples") { | ||||
|             CHECK(cli.parse({ "test", "--benchmark-no-analysis" })); | ||||
|  | ||||
|             REQUIRE(config.benchmarkNoAnalysis); | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
| } | ||||
|   | ||||
							
								
								
									
										405
									
								
								projects/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										405
									
								
								projects/SelfTest/IntrospectiveTests/InternalBenchmark.tests.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,405 @@ | ||||
| /* | ||||
|  *  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) | ||||
|  */ | ||||
|  | ||||
| #include "catch.hpp" | ||||
| #ifndef CATCH_CONFIG_DISABLE_BENCHMARKING  | ||||
| namespace { | ||||
|     struct manual_clock { | ||||
|     public: | ||||
|         using duration = std::chrono::nanoseconds; | ||||
|         using time_point = std::chrono::time_point<manual_clock, duration>; | ||||
|         using rep = duration::rep; | ||||
|         using period = duration::period; | ||||
|         enum { is_steady = true }; | ||||
|  | ||||
|         static time_point now() { | ||||
|             return time_point(duration(tick())); | ||||
|         } | ||||
|  | ||||
|         static void advance(int ticks = 1) { | ||||
|             tick() += ticks; | ||||
|         } | ||||
|  | ||||
|     private: | ||||
|         static rep& tick() { | ||||
|             static rep the_tick = 0; | ||||
|             return the_tick; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     struct counting_clock { | ||||
|     public: | ||||
|         using duration = std::chrono::nanoseconds; | ||||
|         using time_point = std::chrono::time_point<counting_clock, duration>; | ||||
|         using rep = duration::rep; | ||||
|         using period = duration::period; | ||||
|         enum { is_steady = true }; | ||||
|  | ||||
|         static time_point now() { | ||||
|             static rep ticks = 0; | ||||
|             return time_point(duration(ticks += rate())); | ||||
|         } | ||||
|  | ||||
|         static void set_rate(rep new_rate) { rate() = new_rate; } | ||||
|  | ||||
|     private: | ||||
|         static rep& rate() { | ||||
|             static rep the_rate = 1; | ||||
|             return the_rate; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     struct TestChronometerModel : Catch::Benchmark::Detail::ChronometerConcept { | ||||
|         int started = 0; | ||||
|         int finished = 0; | ||||
|  | ||||
|         void start() override { ++started; } | ||||
|         void finish() override { ++finished; } | ||||
|     }; | ||||
| } // namespace | ||||
|  | ||||
| TEST_CASE("warmup", "[benchmark]") { | ||||
|     auto rate = 1000; | ||||
|     counting_clock::set_rate(rate); | ||||
|  | ||||
|     auto start = counting_clock::now(); | ||||
|     auto iterations = Catch::Benchmark::Detail::warmup<counting_clock>(); | ||||
|     auto end = counting_clock::now(); | ||||
|  | ||||
|     REQUIRE((iterations * rate) > Catch::Benchmark::Detail::warmup_time.count()); | ||||
|     REQUIRE((end - start) > Catch::Benchmark::Detail::warmup_time); | ||||
| } | ||||
|  | ||||
| TEST_CASE("resolution", "[benchmark]") { | ||||
|     auto rate = 1000; | ||||
|     counting_clock::set_rate(rate); | ||||
|  | ||||
|     size_t count = 10; | ||||
|     auto res = Catch::Benchmark::Detail::resolution<counting_clock>(static_cast<int>(count)); | ||||
|  | ||||
|     REQUIRE(res.size() == count); | ||||
|  | ||||
|     for (size_t i = 1; i < count; ++i) { | ||||
|         REQUIRE(res[i] == rate); | ||||
|     } | ||||
| } | ||||
|  | ||||
| TEST_CASE("estimate_clock_resolution", "[benchmark]") { | ||||
|     auto rate = 1000; | ||||
|     counting_clock::set_rate(rate); | ||||
|  | ||||
|     int iters = 160000; | ||||
|     auto res = Catch::Benchmark::Detail::estimate_clock_resolution<counting_clock>(iters); | ||||
|  | ||||
|     REQUIRE(res.mean.count() == rate); | ||||
|     REQUIRE(res.outliers.total() == 0); | ||||
| } | ||||
|  | ||||
| TEST_CASE("benchmark function call", "[benchmark]") { | ||||
|     SECTION("without chronometer") { | ||||
|         auto called = 0; | ||||
|         auto model = TestChronometerModel{}; | ||||
|         auto meter = Catch::Benchmark::Chronometer{ model, 1 }; | ||||
|         auto fn = Catch::Benchmark::Detail::BenchmarkFunction{ [&] { | ||||
|                 CHECK(model.started == 1); | ||||
|                 CHECK(model.finished == 0); | ||||
|                 ++called; | ||||
|             } }; | ||||
|  | ||||
|         fn(meter); | ||||
|  | ||||
|         CHECK(model.started == 1); | ||||
|         CHECK(model.finished == 1); | ||||
|         CHECK(called == 1); | ||||
|     } | ||||
|  | ||||
|     SECTION("with chronometer") { | ||||
|         auto called = 0; | ||||
|         auto model = TestChronometerModel{}; | ||||
|         auto meter = Catch::Benchmark::Chronometer{ model, 1 }; | ||||
|         auto fn = Catch::Benchmark::Detail::BenchmarkFunction{ [&](Catch::Benchmark::Chronometer) { | ||||
|                 CHECK(model.started == 0); | ||||
|                 CHECK(model.finished == 0); | ||||
|                 ++called; | ||||
|             } }; | ||||
|  | ||||
|         fn(meter); | ||||
|  | ||||
|         CHECK(model.started == 0); | ||||
|         CHECK(model.finished == 0); | ||||
|         CHECK(called == 1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| TEST_CASE("uniform samples", "[benchmark]") { | ||||
|     std::vector<double> samples(100); | ||||
|     std::fill(samples.begin(), samples.end(), 23); | ||||
|  | ||||
|     using it = std::vector<double>::iterator; | ||||
|     auto e = Catch::Benchmark::Detail::bootstrap(0.95, samples.begin(), samples.end(), samples, [](it a, it b) { | ||||
|         auto sum = std::accumulate(a, b, 0.); | ||||
|         return sum / (b - a); | ||||
|     }); | ||||
|     CHECK(e.point == 23); | ||||
|     CHECK(e.upper_bound == 23); | ||||
|     CHECK(e.lower_bound == 23); | ||||
|     CHECK(e.confidence_interval == 0.95); | ||||
| } | ||||
|  | ||||
|  | ||||
| TEST_CASE("normal_cdf", "[benchmark]") { | ||||
|     using Catch::Benchmark::Detail::normal_cdf; | ||||
|     CHECK(normal_cdf(0.000000) == Approx(0.50000000000000000)); | ||||
|     CHECK(normal_cdf(1.000000) == Approx(0.84134474606854293)); | ||||
|     CHECK(normal_cdf(-1.000000) == Approx(0.15865525393145705)); | ||||
|     CHECK(normal_cdf(2.809729) == Approx(0.99752083845315409)); | ||||
|     CHECK(normal_cdf(-1.352570) == Approx(0.08809652095066035)); | ||||
| } | ||||
|  | ||||
| TEST_CASE("erfc_inv", "[benchmark]") { | ||||
|     using Catch::Benchmark::Detail::erfc_inv; | ||||
|     CHECK(erfc_inv(1.103560) == Approx(-0.09203687623843015)); | ||||
|     CHECK(erfc_inv(1.067400) == Approx(-0.05980291115763361)); | ||||
|     CHECK(erfc_inv(0.050000) == Approx(1.38590382434967796)); | ||||
| } | ||||
|  | ||||
| TEST_CASE("normal_quantile", "[benchmark]") { | ||||
|     using Catch::Benchmark::Detail::normal_quantile; | ||||
|     CHECK(normal_quantile(0.551780) == Approx(0.13015979861484198)); | ||||
|     CHECK(normal_quantile(0.533700) == Approx(0.08457408802851875)); | ||||
|     CHECK(normal_quantile(0.025000) == Approx(-1.95996398454005449)); | ||||
| } | ||||
|  | ||||
|  | ||||
| TEST_CASE("mean", "[benchmark]") { | ||||
|     std::vector<double> x{ 10., 20., 14., 16., 30., 24. }; | ||||
|  | ||||
|     auto m = Catch::Benchmark::Detail::mean(x.begin(), x.end()); | ||||
|  | ||||
|     REQUIRE(m == 19.); | ||||
| } | ||||
|  | ||||
| TEST_CASE("weighted_average_quantile", "[benchmark]") { | ||||
|     std::vector<double> x{ 10., 20., 14., 16., 30., 24. }; | ||||
|  | ||||
|     auto q1 = Catch::Benchmark::Detail::weighted_average_quantile(1, 4, x.begin(), x.end()); | ||||
|     auto med = Catch::Benchmark::Detail::weighted_average_quantile(1, 2, x.begin(), x.end()); | ||||
|     auto q3 = Catch::Benchmark::Detail::weighted_average_quantile(3, 4, x.begin(), x.end()); | ||||
|  | ||||
|     REQUIRE(q1 == 14.5); | ||||
|     REQUIRE(med == 18.); | ||||
|     REQUIRE(q3 == 23.); | ||||
| } | ||||
|  | ||||
| TEST_CASE("classify_outliers", "[benchmark]") { | ||||
|     auto require_outliers = [](Catch::Benchmark::OutlierClassification o, int los, int lom, int him, int his) { | ||||
|         REQUIRE(o.low_severe == los); | ||||
|         REQUIRE(o.low_mild == lom); | ||||
|         REQUIRE(o.high_mild == him); | ||||
|         REQUIRE(o.high_severe == his); | ||||
|         REQUIRE(o.total() == los + lom + him + his); | ||||
|     }; | ||||
|  | ||||
|     SECTION("none") { | ||||
|         std::vector<double> x{ 10., 20., 14., 16., 30., 24. }; | ||||
|  | ||||
|         auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); | ||||
|  | ||||
|         REQUIRE(o.samples_seen == static_cast<int>(x.size())); | ||||
|         require_outliers(o, 0, 0, 0, 0); | ||||
|     } | ||||
|     SECTION("low severe") { | ||||
|         std::vector<double> x{ -12., 20., 14., 16., 30., 24. }; | ||||
|  | ||||
|         auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); | ||||
|  | ||||
|         REQUIRE(o.samples_seen == static_cast<int>(x.size())); | ||||
|         require_outliers(o, 1, 0, 0, 0); | ||||
|     } | ||||
|     SECTION("low mild") { | ||||
|         std::vector<double> x{ 1., 20., 14., 16., 30., 24. }; | ||||
|  | ||||
|         auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); | ||||
|  | ||||
|         REQUIRE(o.samples_seen == static_cast<int>(x.size())); | ||||
|         require_outliers(o, 0, 1, 0, 0); | ||||
|     } | ||||
|     SECTION("high mild") { | ||||
|         std::vector<double> x{ 10., 20., 14., 16., 36., 24. }; | ||||
|  | ||||
|         auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); | ||||
|  | ||||
|         REQUIRE(o.samples_seen == static_cast<int>(x.size())); | ||||
|         require_outliers(o, 0, 0, 1, 0); | ||||
|     } | ||||
|     SECTION("high severe") { | ||||
|         std::vector<double> x{ 10., 20., 14., 16., 49., 24. }; | ||||
|  | ||||
|         auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); | ||||
|  | ||||
|         REQUIRE(o.samples_seen == static_cast<int>(x.size())); | ||||
|         require_outliers(o, 0, 0, 0, 1); | ||||
|     } | ||||
|     SECTION("mixed") { | ||||
|         std::vector<double> x{ -20., 20., 14., 16., 39., 24. }; | ||||
|  | ||||
|         auto o = Catch::Benchmark::Detail::classify_outliers(x.begin(), x.end()); | ||||
|  | ||||
|         REQUIRE(o.samples_seen == static_cast<int>(x.size())); | ||||
|         require_outliers(o, 1, 0, 1, 0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| TEST_CASE("analyse", "[benchmark]") { | ||||
|     Catch::ConfigData data{}; | ||||
|     data.benchmarkConfidenceInterval = 0.95; | ||||
|     data.benchmarkNoAnalysis = false; | ||||
|     data.benchmarkResamples = 1000; | ||||
|     data.benchmarkSamples = 99; | ||||
|     Catch::Config config{data}; | ||||
|  | ||||
|     using Duration = Catch::Benchmark::FloatDuration<Catch::Benchmark::default_clock>; | ||||
|  | ||||
|     Catch::Benchmark::Environment<Duration> env; | ||||
|     std::vector<Duration> samples(99); | ||||
|     for (size_t i = 0; i < samples.size(); ++i) { | ||||
|         samples[i] = Duration(23 + (i % 3 - 1)); | ||||
|     } | ||||
|  | ||||
|     auto analysis = Catch::Benchmark::Detail::analyse(config, env, samples.begin(), samples.end()); | ||||
|     CHECK(analysis.mean.point.count() == 23); | ||||
|     CHECK(analysis.mean.lower_bound.count() < 23); | ||||
|     CHECK(analysis.mean.lower_bound.count() > 22); | ||||
|     CHECK(analysis.mean.upper_bound.count() > 23); | ||||
|     CHECK(analysis.mean.upper_bound.count() < 24); | ||||
|  | ||||
|     CHECK(analysis.standard_deviation.point.count() > 0.5); | ||||
|     CHECK(analysis.standard_deviation.point.count() < 1); | ||||
|     CHECK(analysis.standard_deviation.lower_bound.count() > 0.5); | ||||
|     CHECK(analysis.standard_deviation.lower_bound.count() < 1); | ||||
|     CHECK(analysis.standard_deviation.upper_bound.count() > 0.5); | ||||
|     CHECK(analysis.standard_deviation.upper_bound.count() < 1); | ||||
|  | ||||
|     CHECK(analysis.outliers.total() == 0); | ||||
|     CHECK(analysis.outliers.low_mild == 0); | ||||
|     CHECK(analysis.outliers.low_severe == 0); | ||||
|     CHECK(analysis.outliers.high_mild == 0); | ||||
|     CHECK(analysis.outliers.high_severe == 0); | ||||
|     CHECK(analysis.outliers.samples_seen == samples.size()); | ||||
|  | ||||
|     CHECK(analysis.outlier_variance < 0.5); | ||||
|     CHECK(analysis.outlier_variance > 0); | ||||
| } | ||||
|  | ||||
| TEST_CASE("analyse no analysis", "[benchmark]") { | ||||
|     Catch::ConfigData data{}; | ||||
|     data.benchmarkConfidenceInterval = 0.95; | ||||
|     data.benchmarkNoAnalysis = true; | ||||
|     data.benchmarkResamples = 1000; | ||||
|     data.benchmarkSamples = 99; | ||||
|     Catch::Config config{ data }; | ||||
|  | ||||
|     using Duration = Catch::Benchmark::FloatDuration<Catch::Benchmark::default_clock>; | ||||
|  | ||||
|     Catch::Benchmark::Environment<Duration> env; | ||||
|     std::vector<Duration> samples(99); | ||||
|     for (size_t i = 0; i < samples.size(); ++i) { | ||||
|         samples[i] = Duration(23 + (i % 3 - 1)); | ||||
|     } | ||||
|  | ||||
|     auto analysis = Catch::Benchmark::Detail::analyse(config, env, samples.begin(), samples.end()); | ||||
|     CHECK(analysis.mean.point.count() == 23); | ||||
|     CHECK(analysis.mean.lower_bound.count() == 23); | ||||
|     CHECK(analysis.mean.upper_bound.count() == 23); | ||||
|  | ||||
|     CHECK(analysis.standard_deviation.point.count() == 0); | ||||
|     CHECK(analysis.standard_deviation.lower_bound.count() == 0); | ||||
|     CHECK(analysis.standard_deviation.upper_bound.count() == 0); | ||||
|  | ||||
|     CHECK(analysis.outliers.total() == 0); | ||||
|     CHECK(analysis.outliers.low_mild == 0); | ||||
|     CHECK(analysis.outliers.low_severe == 0); | ||||
|     CHECK(analysis.outliers.high_mild == 0); | ||||
|     CHECK(analysis.outliers.high_severe == 0); | ||||
|     CHECK(analysis.outliers.samples_seen == 0); | ||||
|  | ||||
|     CHECK(analysis.outlier_variance == 0); | ||||
| } | ||||
|  | ||||
| TEST_CASE("run_for_at_least, int", "[benchmark]") { | ||||
|     manual_clock::duration time(100); | ||||
|  | ||||
|     int old_x = 1; | ||||
|     auto Timing = Catch::Benchmark::Detail::run_for_at_least<manual_clock>(time, 1, [&old_x](int x) -> int { | ||||
|         CHECK(x >= old_x); | ||||
|         manual_clock::advance(x); | ||||
|         old_x = x; | ||||
|         return x + 17; | ||||
|     }); | ||||
|  | ||||
|     REQUIRE(Timing.elapsed >= time); | ||||
|     REQUIRE(Timing.result == Timing.iterations + 17); | ||||
|     REQUIRE(Timing.iterations >= time.count()); | ||||
| } | ||||
|  | ||||
| TEST_CASE("run_for_at_least, chronometer", "[benchmark]") { | ||||
|     manual_clock::duration time(100); | ||||
|  | ||||
|     int old_runs = 1; | ||||
|     auto Timing = Catch::Benchmark::Detail::run_for_at_least<manual_clock>(time, 1, [&old_runs](Catch::Benchmark::Chronometer meter) -> int { | ||||
|         CHECK(meter.runs() >= old_runs); | ||||
|         manual_clock::advance(100); | ||||
|         meter.measure([] { | ||||
|             manual_clock::advance(1); | ||||
|         }); | ||||
|         old_runs = meter.runs(); | ||||
|         return meter.runs() + 17; | ||||
|     }); | ||||
|  | ||||
|     REQUIRE(Timing.elapsed >= time); | ||||
|     REQUIRE(Timing.result == Timing.iterations + 17); | ||||
|     REQUIRE(Timing.iterations >= time.count()); | ||||
| } | ||||
|  | ||||
|  | ||||
| TEST_CASE("measure", "[benchmark]") { | ||||
|     auto r = Catch::Benchmark::Detail::measure<manual_clock>([](int x) -> int { | ||||
|         CHECK(x == 17); | ||||
|         manual_clock::advance(42); | ||||
|         return 23; | ||||
|     }, 17); | ||||
|     auto s = Catch::Benchmark::Detail::measure<manual_clock>([](int x) -> int { | ||||
|         CHECK(x == 23); | ||||
|         manual_clock::advance(69); | ||||
|         return 17; | ||||
|     }, 23); | ||||
|  | ||||
|     CHECK(r.elapsed.count() == 42); | ||||
|     CHECK(r.result == 23); | ||||
|     CHECK(r.iterations == 1); | ||||
|  | ||||
|     CHECK(s.elapsed.count() == 69); | ||||
|     CHECK(s.result == 17); | ||||
|     CHECK(s.iterations == 1); | ||||
| } | ||||
|  | ||||
| TEST_CASE("run benchmark", "[benchmark]") { | ||||
|     counting_clock::set_rate(1000); | ||||
|     auto start = counting_clock::now(); | ||||
|      | ||||
|     Catch::Benchmark::Benchmark bench{ "Test Benchmark", [](Catch::Benchmark::Chronometer meter) { | ||||
|         counting_clock::set_rate(100000); | ||||
|         meter.measure([] { return counting_clock::now(); }); | ||||
|     } }; | ||||
|  | ||||
|     bench.run<counting_clock>(); | ||||
|     auto end = counting_clock::now(); | ||||
|  | ||||
|     CHECK((end - start).count() == 2867251000); | ||||
| } | ||||
| #endif // CATCH_CONFIG_DISABLE_BENCHMARKING | ||||
| @@ -2,42 +2,129 @@ | ||||
|  | ||||
| #include <map> | ||||
|  | ||||
| TEST_CASE( "benchmarked", "[!benchmark]" ) { | ||||
| #ifndef CATCH_CONFIG_DISABLE_BENCHMARKING  | ||||
| std::uint64_t Fibonacci(std::uint64_t number); | ||||
|  | ||||
| std::uint64_t Fibonacci(std::uint64_t number) { | ||||
|     return number < 2 ? 1 : Fibonacci(number - 1) + Fibonacci(number - 2); | ||||
| } | ||||
|  | ||||
| TEST_CASE("Benchmark Fibonacci", "[!benchmark]") { | ||||
|     CHECK(Fibonacci(0) == 1); | ||||
|     // some more asserts.. | ||||
|     CHECK(Fibonacci(5) == 8); | ||||
|     // some more asserts.. | ||||
|  | ||||
|     BENCHMARK("Fibonacci 20") { | ||||
|         return Fibonacci(20); | ||||
|     }; | ||||
|  | ||||
|     BENCHMARK("Fibonacci 25") { | ||||
|         return Fibonacci(25); | ||||
|     }; | ||||
|  | ||||
|     BENCHMARK("Fibonacci 30") { | ||||
|         return Fibonacci(30); | ||||
|     }; | ||||
|  | ||||
|     BENCHMARK("Fibonacci 35") { | ||||
|         return Fibonacci(35); | ||||
|     }; | ||||
| } | ||||
|  | ||||
| TEST_CASE("Benchmark containers", "[!benchmark]") { | ||||
|     static const int size = 100; | ||||
|  | ||||
|     std::vector<int> v; | ||||
|     std::map<int, int> m; | ||||
|  | ||||
|     BENCHMARK( "Load up a vector" ) { | ||||
|         v = std::vector<int>(); | ||||
|         for(int i =0; i < size; ++i ) | ||||
|             v.push_back( i ); | ||||
|     } | ||||
|     REQUIRE( v.size() == size ); | ||||
|     SECTION("without generator") { | ||||
|         BENCHMARK("Load up a vector") { | ||||
|             v = std::vector<int>(); | ||||
|             for (int i = 0; i < size; ++i) | ||||
|                 v.push_back(i); | ||||
|         }; | ||||
|         REQUIRE(v.size() == size); | ||||
|  | ||||
|     BENCHMARK( "Load up a map" ) { | ||||
|         m = std::map<int, int>(); | ||||
|         for(int i =0; i < size; ++i ) | ||||
|             m.insert( { i, i+1 } ); | ||||
|     } | ||||
|     REQUIRE( m.size() == size ); | ||||
|         // test optimizer control | ||||
|         BENCHMARK("Add up a vector's content") { | ||||
|             uint64_t add = 0; | ||||
|             for (int i = 0; i < size; ++i) | ||||
|                 add += v[i]; | ||||
|             return add; | ||||
|         }; | ||||
|  | ||||
|     BENCHMARK( "Reserved vector" ) { | ||||
|         v = std::vector<int>(); | ||||
|         v.reserve(size); | ||||
|         for(int i =0; i < size; ++i ) | ||||
|             v.push_back( i ); | ||||
|     } | ||||
|     REQUIRE( v.size() == size ); | ||||
|         BENCHMARK("Load up a map") { | ||||
|             m = std::map<int, int>(); | ||||
|             for (int i = 0; i < size; ++i) | ||||
|                 m.insert({ i, i + 1 }); | ||||
|         }; | ||||
|         REQUIRE(m.size() == size); | ||||
|  | ||||
|     int array[size]; | ||||
|     BENCHMARK( "A fixed size array that should require no allocations" ) { | ||||
|         for(int i =0; i < size; ++i ) | ||||
|             array[i] = i; | ||||
|         BENCHMARK("Reserved vector") { | ||||
|             v = std::vector<int>(); | ||||
|             v.reserve(size); | ||||
|             for (int i = 0; i < size; ++i) | ||||
|                 v.push_back(i); | ||||
|         }; | ||||
|         REQUIRE(v.size() == size); | ||||
|  | ||||
|         BENCHMARK("Resized vector") { | ||||
|             v = std::vector<int>(); | ||||
|             v.resize(size); | ||||
|             for (int i = 0; i < size; ++i) | ||||
|                 v[i] = i; | ||||
|         }; | ||||
|         REQUIRE(v.size() == size); | ||||
|  | ||||
|         int array[size]; | ||||
|         BENCHMARK("A fixed size array that should require no allocations") { | ||||
|             for (int i = 0; i < size; ++i) | ||||
|                 array[i] = i; | ||||
|         }; | ||||
|         int sum = 0; | ||||
|         for (int i = 0; i < size; ++i) | ||||
|             sum += array[i]; | ||||
|         REQUIRE(sum > size); | ||||
|  | ||||
|         SECTION("XYZ") { | ||||
|  | ||||
|             BENCHMARK_ADVANCED("Load up vector with chronometer")(Catch::Benchmark::Chronometer meter) { | ||||
|                 std::vector<int> k; | ||||
|                 meter.measure([&](int idx) { | ||||
|                     k = std::vector<int>(); | ||||
|                     for (int i = 0; i < size; ++i) | ||||
|                         k.push_back(idx); | ||||
|                 }); | ||||
|                 REQUIRE(k.size() == size); | ||||
|             }; | ||||
|  | ||||
|             int runs = 0; | ||||
|             BENCHMARK("Fill vector indexed", benchmarkIndex) { | ||||
|                 v = std::vector<int>(); | ||||
|                 v.resize(size); | ||||
|                 for (int i = 0; i < size; ++i) | ||||
|                     v[i] = benchmarkIndex; | ||||
|                 runs = benchmarkIndex; | ||||
|             }; | ||||
|  | ||||
|             for (size_t i = 0; i < v.size(); ++i) { | ||||
|                 REQUIRE(v[i] == runs); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     SECTION("with generator") { | ||||
|         auto generated = GENERATE(range(0, 10)); | ||||
|         BENCHMARK("Fill vector generated") { | ||||
|             v = std::vector<int>(); | ||||
|             v.resize(size); | ||||
|             for (int i = 0; i < size; ++i) | ||||
|                 v[i] = generated; | ||||
|         }; | ||||
|         for (size_t i = 0; i < v.size(); ++i) { | ||||
|             REQUIRE(v[i] == generated); | ||||
|         } | ||||
|     } | ||||
|     int sum = 0; | ||||
|     for(int i =0; i < size; ++i ) | ||||
|         sum += array[i]; | ||||
|     REQUIRE( sum > size ); | ||||
| } | ||||
| #endif // CATCH_CONFIG_DISABLE_BENCHMARKING | ||||
|   | ||||
		Reference in New Issue
	
	Block a user