From b96e70e2485cb852cd0e8261092d723d955feea3 Mon Sep 17 00:00:00 2001 From: Simon Gene Gottlieb Date: Tue, 25 Jun 2024 13:23:10 +0200 Subject: [PATCH 1/3] feat: using interleaved benchmarks with different ostreams do not force a new header --- src/include/nanobench.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/include/nanobench.h b/src/include/nanobench.h index d233dcc..8d83ff5 100644 --- a/src/include/nanobench.h +++ b/src/include/nanobench.h @@ -1791,7 +1791,7 @@ void gatherStabilityInformation(std::vector& warnings, std::vector< void printStabilityInformationOnce(std::ostream* outStream); // remembers the last table settings used. When it changes, a new table header is automatically written for the new entry. -uint64_t& singletonHeaderHash() noexcept; +uint64_t& singletonHeaderHash(std::ostream const& _out) noexcept; // determines resolution of the given clock. This is done by measuring multiple times and returning the minimum time difference. Clock::duration calcClockResolution(size_t numEvaluations) noexcept; @@ -2104,9 +2104,9 @@ void printStabilityInformationOnce(std::ostream* outStream) { } // remembers the last table settings used. When it changes, a new table header is automatically written for the new entry. -uint64_t& singletonHeaderHash() noexcept { - static uint64_t sHeaderHash{}; - return sHeaderHash; +uint64_t& singletonHeaderHash(std::ostream const& _out) noexcept { + static std::unordered_map sHeaderHashes; + return sHeaderHashes[&_out]; } ANKERL_NANOBENCH_NO_SANITIZE("integer", "undefined") @@ -2332,8 +2332,8 @@ struct IterationLogic::Impl { hash = hash_combine(std::hash{}(mBench.relative()), hash); hash = hash_combine(std::hash{}(mBench.performanceCounters()), hash); - if (hash != singletonHeaderHash()) { - singletonHeaderHash() = hash; + if (hash != singletonHeaderHash(os)) { + singletonHeaderHash(os) = hash; // no result yet, print header os << std::endl; From e83bf471851be7475a45c009a1c50971a21e916e Mon Sep 17 00:00:00 2001 From: Simon Gene Gottlieb Date: Tue, 25 Jun 2024 15:34:49 +0200 Subject: [PATCH 2/3] fix: race condition for printing header --- src/include/nanobench.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/include/nanobench.h b/src/include/nanobench.h index 8d83ff5..c5dc34f 100644 --- a/src/include/nanobench.h +++ b/src/include/nanobench.h @@ -1307,6 +1307,7 @@ void doNotOptimizeAway(T const& val) { # include // ifstream to parse proc files # include // setw, setprecision # include // cout +# include // mutex, lock_guard # include // accumulate # include // random_device # include // to_s in Number @@ -2105,7 +2106,10 @@ void printStabilityInformationOnce(std::ostream* outStream) { // remembers the last table settings used. When it changes, a new table header is automatically written for the new entry. uint64_t& singletonHeaderHash(std::ostream const& _out) noexcept { + static std::mutex sMutex; static std::unordered_map sHeaderHashes; + std::lock_guard guard{sMutex}; + return sHeaderHashes[&_out]; } From 940d9510e3862b956ed431da8fdc516092b082c1 Mon Sep 17 00:00:00 2001 From: Simon Gene Gottlieb Date: Tue, 25 Jun 2024 17:32:54 +0200 Subject: [PATCH 3/3] test: add unit test for multi bench --- src/test/CMakeLists.txt | 3 +- src/test/unit_multi_bench.cpp | 67 +++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/test/unit_multi_bench.cpp diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index d544752..19db77b 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -25,12 +25,13 @@ target_sources_local(nb PRIVATE tutorial_fluctuating_v1.cpp tutorial_fluctuating_v2.cpp tutorial_mustache.cpp - tutorial_render_simple.cpp + tutorial_render_simple.cpp tutorial_slow_v1.cpp tutorial_slow_v2.cpp unit_api.cpp unit_cold.cpp unit_exact_iters_and_epochs.cpp + unit_multi_bench.cpp unit_romutrio.cpp unit_templates.cpp unit_timeunit.cpp diff --git a/src/test/unit_multi_bench.cpp b/src/test/unit_multi_bench.cpp new file mode 100644 index 0000000..370dcaf --- /dev/null +++ b/src/test/unit_multi_bench.cpp @@ -0,0 +1,67 @@ +#include +#include + +#include +#include +#include +#include + + + +template +static void runTest(std::string container_name, ankerl::nanobench::Bench& bench_at, ankerl::nanobench::Bench& bench_operator) { + size_t const maxSize = 1000000; + + ankerl::nanobench::Rng rng; + + Container container; + for (size_t i{0}; i < maxSize; ++i) { + auto value = uint8_t(rng.bounded(256)); + container[i] = value; + } + bench_at.run(container_name, [&] { + ankerl::nanobench::doNotOptimizeAway(container.at(rng.bounded(maxSize))); + }); + bench_operator.run(container_name, [&] { + ankerl::nanobench::doNotOptimizeAway(container[rng.bounded(maxSize)]); + }); +} + +// NOLINTNEXTLINE +TEST_CASE("multi_bench") { + // Suppress any stability warnings for later outputs + ankerl::nanobench::Bench().run("suppress_warning", []{}); + + ankerl::nanobench::Bench bench_at; + std::stringstream output_at; + bench_at + .title("at()") + .output(&output_at); + + ankerl::nanobench::Bench bench_operator; + std::stringstream output_operator; + bench_operator + .title("operator[]") + .output(&output_operator); + + + runTest >("std::map", bench_at, bench_operator); + runTest >("std::unordered_map", bench_at, bench_operator); + + size_t linect_at{}; + size_t linect_operator{}; + { + std::string s; + while(std::getline(output_at, s)) { + linect_at += 1; + } + while(std::getline(output_operator, s)) { + linect_operator += 1; + } + } + CHECK(linect_at == 5); + CHECK(linect_operator == 5); + + std::cout << output_at.str() << '\n' + << output_operator.str() << '\n'; +}