Pass State to ProfilerManager via new WithState hooks (#2234) (#2313)

* Pass State to ProfilerManager via new WithState hooks (#2234)

* Include state.h instead of forward-declaring State; fix clang-format

---------

Co-authored-by: dominic <510002+dmah42@users.noreply.github.com>
diff --git a/AUTHORS b/AUTHORS
index 65cad40..4a14b98 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -38,6 +38,7 @@
 GergÅ‘ Szitár <szitar.gergo@gmail.com>
 Google Inc.
 Haihan Jiang <haihanj99@gmail.com>
+Harsh Chaturvedi <chaturvediharsh123@gmail.com>
 Henrique Bucher <hbucher@gmail.com>
 International Business Machines Corporation
 Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index a77788f..74e5fe9 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -59,6 +59,7 @@
 GergÅ‘ Szitár <szitar.gergo@gmail.com>
 Haihan Jiang <haihanj99@gmail.com>
 Hannes Hauswedell <h2@fsfe.org>
+Harsh Chaturvedi <chaturvediharsh123@gmail.com>
 Henrique Bucher <hbucher@gmail.com>
 Ismael Jimenez Martinez <ismael.jimenez.martinez@gmail.com>
 Iakov Sergeev <yahontu@gmail.com>
diff --git a/docs/user_guide.md b/docs/user_guide.md
index cd96baf..9e46a51 100644
--- a/docs/user_guide.md
+++ b/docs/user_guide.md
@@ -1628,6 +1628,11 @@
 end of a separate benchmark run to allow user code to collect and report
 user-provided profile metrics.
 
+If your profiler needs the current benchmark name or other run state, override
+`ProfilerManager::AfterSetupStartWithState(const State&)` and
+`ProfilerManager::BeforeTeardownStopWithState(const State&)`. The legacy
+no-argument hooks still work and remain the fallback.
+
 Output collected from this profiling run must be reported separately.
 
 <a name="using-register-benchmark" />
diff --git a/include/benchmark/managers.h b/include/benchmark/managers.h
index e8b6cd4..963bf58 100644
--- a/include/benchmark/managers.h
+++ b/include/benchmark/managers.h
@@ -20,6 +20,7 @@
 #include <limits>
 
 #include "benchmark/macros.h"
+#include "benchmark/state.h"
 #include "benchmark/types.h"
 
 namespace benchmark {
@@ -54,8 +55,12 @@
 class ProfilerManager {
  public:
   virtual ~ProfilerManager() {}
-  virtual void AfterSetupStart() = 0;
-  virtual void BeforeTeardownStop() = 0;
+  virtual void AfterSetupStart() {}
+  virtual void BeforeTeardownStop() {}
+  virtual void AfterSetupStartWithState(const State&) { AfterSetupStart(); }
+  virtual void BeforeTeardownStopWithState(const State&) {
+    BeforeTeardownStop();
+  }
 };
 
 BENCHMARK_EXPORT
diff --git a/src/benchmark.cc b/src/benchmark.cc
index 5d1e7e9..4a6789f 100644
--- a/src/benchmark.cc
+++ b/src/benchmark.cc
@@ -305,7 +305,7 @@
   started_ = true;
   total_iterations_ = skipped() ? 0 : max_iterations;
   if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) {
-    profiler_manager_->AfterSetupStart();
+    profiler_manager_->AfterSetupStartWithState(*this);
   }
   manager_->StartStopBarrier();
   if (!skipped()) {
@@ -323,7 +323,7 @@
   finished_ = true;
   manager_->StartStopBarrier();
   if (BENCHMARK_BUILTIN_EXPECT(profiler_manager_ != nullptr, false)) {
-    profiler_manager_->BeforeTeardownStop();
+    profiler_manager_->BeforeTeardownStopWithState(*this);
   }
 }
 
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index e9edd42..f33209c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -217,6 +217,9 @@
 compile_benchmark_test(profiler_manager_iterations_test)
 benchmark_add_test(NAME profiler_manager_iterations COMMAND profiler_manager_iterations_test)
 
+compile_benchmark_test(profiler_manager_state_test)
+benchmark_add_test(NAME profiler_manager_state COMMAND profiler_manager_state_test)
+
 compile_output_test(complexity_test)
 benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark_min_time=1000000x)
 
diff --git a/test/profiler_manager_state_test.cc b/test/profiler_manager_state_test.cc
new file mode 100644
index 0000000..192600e
--- /dev/null
+++ b/test/profiler_manager_state_test.cc
@@ -0,0 +1,84 @@
+#include <cassert>
+#include <string>
+#include <vector>
+
+#include "benchmark/benchmark_api.h"
+#include "benchmark/managers.h"
+#include "benchmark/registration.h"
+#include "benchmark/reporter.h"
+#include "benchmark/state.h"
+#include "benchmark/utils.h"
+
+namespace {
+
+class StateProfilerManager : public benchmark::ProfilerManager {
+ public:
+  void AfterSetupStartWithState(const benchmark::State& state) override {
+    ++start_called;
+    start_name = state.name();
+  }
+
+  void BeforeTeardownStopWithState(const benchmark::State& state) override {
+    ++stop_called;
+    stop_name = state.name();
+  }
+
+  int start_called = 0;
+  int stop_called = 0;
+  std::string start_name;
+  std::string stop_name;
+};
+
+class LegacyProfilerManager : public benchmark::ProfilerManager {
+ public:
+  void AfterSetupStart() override { ++start_called; }
+  void BeforeTeardownStop() override { ++stop_called; }
+
+  int start_called = 0;
+  int stop_called = 0;
+};
+
+class NullReporter : public benchmark::BenchmarkReporter {
+ public:
+  bool ReportContext(const Context& /*context*/) override { return true; }
+  void ReportRuns(const std::vector<Run>& /*report*/) override {}
+};
+
+void BM_Profiled(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(state.iterations());
+  }
+}
+BENCHMARK(BM_Profiled);
+
+}  // namespace
+
+int main(int argc, char* argv[]) {
+  benchmark::MaybeReenterWithoutASLR(argc, argv);
+  benchmark::Initialize(&argc, argv);
+
+  NullReporter null_reporter;
+
+  StateProfilerManager state_profiler;
+  benchmark::RegisterProfilerManager(&state_profiler);
+  size_t run_count =
+      benchmark::RunSpecifiedBenchmarks(&null_reporter, "BM_Profiled$");
+  benchmark::RegisterProfilerManager(nullptr);
+
+  assert(run_count == 1);
+  assert(state_profiler.start_called == 1);
+  assert(state_profiler.stop_called == 1);
+  assert(state_profiler.start_name == "BM_Profiled");
+  assert(state_profiler.stop_name == "BM_Profiled");
+
+  LegacyProfilerManager legacy_profiler;
+  benchmark::RegisterProfilerManager(&legacy_profiler);
+  run_count = benchmark::RunSpecifiedBenchmarks(&null_reporter, "BM_Profiled$");
+  benchmark::RegisterProfilerManager(nullptr);
+
+  assert(run_count == 1);
+  assert(legacy_profiler.start_called == 1);
+  assert(legacy_profiler.stop_called == 1);
+
+  return 0;
+}