From 2ed3ace17d57bf4c4c512434eddf3471e8cbdc1c Mon Sep 17 00:00:00 2001 From: devtejasx Date: Wed, 15 Jul 2026 16:27:08 +0530 Subject: [PATCH] Pass benchmark State to ProfilerManager hooks Custom profilers doing regional profiling need information about the benchmark being profiled, e.g. its name to register a named region. Add AfterSetupStart(const State&) and BeforeTeardownStop(const State&) overloads to ProfilerManager and call them with the State of the profiling run. The default implementations forward to the existing parameterless hooks, which are no longer pure virtual, so existing ProfilerManager implementations keep working unchanged. Fixes google/benchmark#2234 --- docs/user_guide.md | 9 +++++++++ include/benchmark/managers.h | 18 ++++++++++++++++-- src/benchmark.cc | 4 ++-- test/profiler_manager_gtest.cc | 3 +++ test/profiler_manager_iterations_test.cc | 3 +++ test/profiler_manager_test.cc | 14 +++++++++++++- 6 files changed, 46 insertions(+), 5 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 3fed9261d7..ff7d886476 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -1604,6 +1604,15 @@ If set, the `ProfilerManager::AfterSetupStart` and end of a separate benchmark run to allow user code to collect and report user-provided profile metrics. +Each method has two overloads: a parameterless one and one taking a +`const benchmark::State&`, which gives access to run information such as the +benchmark name (e.g. for registering named profiling regions). Override +whichever variant you need; the `State`-taking overloads forward to the +parameterless ones by default. When overriding only one overload of a pair, +add a `using benchmark::ProfilerManager::AfterSetupStart;` (respectively +`BeforeTeardownStop`) declaration to your class to avoid hiding the other +overload. + Output collected from this profiling run must be reported separately. diff --git a/include/benchmark/managers.h b/include/benchmark/managers.h index e8b6cd4749..e3444d5252 100644 --- a/include/benchmark/managers.h +++ b/include/benchmark/managers.h @@ -24,6 +24,8 @@ namespace benchmark { +class State; + class MemoryManager { public: static constexpr int64_t TombstoneValue = std::numeric_limits::max(); @@ -54,8 +56,20 @@ void RegisterMemoryManager(MemoryManager* memory_manager); class ProfilerManager { public: virtual ~ProfilerManager() {} - virtual void AfterSetupStart() = 0; - virtual void BeforeTeardownStop() = 0; + // Kept for backwards compatibility; new code should override the + // State-taking overloads below. Note that a subclass overriding only one + // overload of a pair hides the other; add + // `using benchmark::ProfilerManager::AfterSetupStart;` (respectively + // `BeforeTeardownStop`) to silence -Woverloaded-virtual. + virtual void AfterSetupStart() {} + virtual void BeforeTeardownStop() {} + // Called with the State of the benchmark run being profiled, giving + // access to e.g. the benchmark name. The default implementations forward + // to the parameterless hooks above. + virtual void AfterSetupStart(const State& /*state*/) { AfterSetupStart(); } + virtual void BeforeTeardownStop(const State& /*state*/) { + BeforeTeardownStop(); + } }; BENCHMARK_EXPORT diff --git a/src/benchmark.cc b/src/benchmark.cc index 7217fc4ed2..b6173d18b7 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -331,7 +331,7 @@ void State::StartKeepRunning() { started_ = true; total_iterations_ = skipped() ? 0 : max_iterations; if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) { - profiler_manager_->AfterSetupStart(); + profiler_manager_->AfterSetupStart(*this); } manager_->StartStopBarrier(); if (!skipped()) { @@ -349,7 +349,7 @@ void State::FinishKeepRunning() { finished_ = true; manager_->StartStopBarrier(); if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) { - profiler_manager_->BeforeTeardownStop(); + profiler_manager_->BeforeTeardownStop(*this); } } diff --git a/test/profiler_manager_gtest.cc b/test/profiler_manager_gtest.cc index 6e83e32a90..ab4adefb56 100644 --- a/test/profiler_manager_gtest.cc +++ b/test/profiler_manager_gtest.cc @@ -10,6 +10,9 @@ namespace { class TestProfilerManager : public benchmark::ProfilerManager { public: + using benchmark::ProfilerManager::AfterSetupStart; + using benchmark::ProfilerManager::BeforeTeardownStop; + void AfterSetupStart() override { ++start_called; } void BeforeTeardownStop() override { ++stop_called; } diff --git a/test/profiler_manager_iterations_test.cc b/test/profiler_manager_iterations_test.cc index 90b34a1daa..dffeb686ec 100644 --- a/test/profiler_manager_iterations_test.cc +++ b/test/profiler_manager_iterations_test.cc @@ -17,6 +17,9 @@ int iteration_count = 0; int end_profiler_iteration_count = 0; class TestProfilerManager : public benchmark::ProfilerManager { + using benchmark::ProfilerManager::AfterSetupStart; + using benchmark::ProfilerManager::BeforeTeardownStop; + void AfterSetupStart() override { iteration_count = 0; } void BeforeTeardownStop() override { end_profiler_iteration_count = iteration_count; diff --git a/test/profiler_manager_test.cc b/test/profiler_manager_test.cc index bd86d42c04..f825181c17 100644 --- a/test/profiler_manager_test.cc +++ b/test/profiler_manager_test.cc @@ -2,6 +2,7 @@ #include #include +#include #include "benchmark/benchmark_api.h" #include "benchmark/managers.h" @@ -13,11 +14,21 @@ namespace { class TestProfilerManager : public benchmark::ProfilerManager { public: - void AfterSetupStart() override { ++start_called; } + using benchmark::ProfilerManager::AfterSetupStart; + using benchmark::ProfilerManager::BeforeTeardownStop; + + // New-style hook receiving the State of the benchmark being profiled. + void AfterSetupStart(const benchmark::State& state) override { + ++start_called; + benchmark_name = state.name(); + } + // Old-style hook; must still be reached through the default forwarding of + // BeforeTeardownStop(const State&). void BeforeTeardownStop() override { ++stop_called; } int start_called = 0; int stop_called = 0; + std::string benchmark_name; }; void BM_empty(benchmark::State& state) { @@ -55,4 +66,5 @@ int main(int argc, char* argv[]) { assert(pm->start_called == 1); assert(pm->stop_called == 1); + assert(pm->benchmark_name == "BM_empty"); }