diff --git a/docs/user_guide.md b/docs/user_guide.md
index 3fed9261d7..e37c19bfe2 100644
--- a/docs/user_guide.md
+++ b/docs/user_guide.md
@@ -1604,6 +1604,11 @@ If set, the `ProfilerManager::AfterSetupStart` and
end of a separate benchmark run to allow user code to collect and report
user-provided profile metrics.
+From within either hook, `ProfilerManager::GetState()` returns a pointer to
+the `benchmark::State` of the run being profiled, which gives access to run
+information such as the benchmark name (e.g. for registering named profiling
+regions). Outside of the two hooks it returns `nullptr`.
+
Output collected from this profiling run must be reported separately.
diff --git a/include/benchmark/managers.h b/include/benchmark/managers.h
index e8b6cd4749..e6784738f0 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();
@@ -56,6 +58,17 @@ class ProfilerManager {
virtual ~ProfilerManager() {}
virtual void AfterSetupStart() = 0;
virtual void BeforeTeardownStop() = 0;
+
+ protected:
+ // The State of the benchmark run being profiled, giving access to e.g. the
+ // benchmark name (for a named profiling region). Non-null only while
+ // AfterSetupStart() or BeforeTeardownStop() is executing; any other caller
+ // observes nullptr.
+ const State* GetState() const { return state_; }
+
+ private:
+ friend class State;
+ const State* state_ = nullptr;
};
BENCHMARK_EXPORT
diff --git a/src/benchmark.cc b/src/benchmark.cc
index 91280295e8..55e5faadc7 100644
--- a/src/benchmark.cc
+++ b/src/benchmark.cc
@@ -331,7 +331,9 @@ void State::StartKeepRunning() {
started_ = true;
total_iterations_ = skipped() ? 0 : max_iterations;
if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) {
+ profiler_manager_->state_ = this;
profiler_manager_->AfterSetupStart();
+ profiler_manager_->state_ = nullptr;
}
manager_->StartStopBarrier();
if (!skipped()) {
@@ -349,7 +351,9 @@ void State::FinishKeepRunning() {
finished_ = true;
manager_->StartStopBarrier();
if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) {
+ profiler_manager_->state_ = this;
profiler_manager_->BeforeTeardownStop();
+ profiler_manager_->state_ = nullptr;
}
}
diff --git a/test/profiler_manager_test.cc b/test/profiler_manager_test.cc
index bd86d42c04..25b239b649 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; }
+ void AfterSetupStart() override {
+ ++start_called;
+ if (GetState() != nullptr) {
+ benchmark_name = GetState()->name();
+ }
+ }
void BeforeTeardownStop() override { ++stop_called; }
+ // Expose the protected accessor so the harness can verify it yields
+ // nullptr outside the hooks.
+ const benchmark::State* StateOutsideHooks() const { return GetState(); }
+
int start_called = 0;
int stop_called = 0;
+ std::string benchmark_name;
};
void BM_empty(benchmark::State& state) {
@@ -55,4 +66,7 @@ int main(int argc, char* argv[]) {
assert(pm->start_called == 1);
assert(pm->stop_called == 1);
+ assert(pm->benchmark_name == "BM_empty");
+ // Outside the hooks the state must not be observable.
+ assert(pm->StateOutsideHooks() == nullptr);
}