diff --git a/docs/user_guide.md b/docs/user_guide.md index c09d77554f..130319603d 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -1066,6 +1066,29 @@ BENCHMARK(BM_SetInsert_With_Timer_Control)->Ranges({{1<<10, 8<<10}, {128, 512}}) ``` +For convenience, a `ScopedPauseTiming` class is provided to manage pausing and +resuming timers within a scope. This is less error-prone than manually calling +`PauseTiming` and `ResumeTiming`. + + +```c++ +static void BM_SetInsert_With_Scoped_Timer_Control(benchmark::State& state) { + std::set data; + for (auto _ : state) { + { + benchmark::ScopedPauseTiming pause(state); // Pauses timing + data = ConstructRandomSet(state.range(0)); + } // Timing resumes automatically when 'pause' goes out of scope + + // The rest will be measured. + for (int j = 0; j < state.range(1); ++j) + data.insert(RandomNumber()); + } +} +BENCHMARK(BM_SetInsert_With_Scoped_Timer_Control)->Ranges({{1<<10, 8<<10}, {128, 512}}); +``` + + ## Manual Timing diff --git a/include/benchmark/state.h b/include/benchmark/state.h index e9cdf0571a..356c5509a0 100644 --- a/include/benchmark/state.h +++ b/include/benchmark/state.h @@ -256,6 +256,23 @@ inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() { return StateIterator(); } +class ScopedPauseTiming { + public: + explicit ScopedPauseTiming(State& state) : state_(state) { + state_.PauseTiming(); + } + ~ScopedPauseTiming() { state_.ResumeTiming(); } + + ScopedPauseTiming(const ScopedPauseTiming&) = delete; + void operator=(const ScopedPauseTiming&) = delete; + + ScopedPauseTiming(ScopedPauseTiming&&) = delete; + void operator=(ScopedPauseTiming&&) = delete; + + private: + State& state_; +}; + } // namespace benchmark #if defined(_MSC_VER) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2917efa513..374c09fa3f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -225,6 +225,9 @@ benchmark_add_test(NAME complexity_benchmark COMMAND complexity_test --benchmark compile_output_test(locale_impermeability_test) benchmark_add_test(NAME locale_impermeability_test COMMAND locale_impermeability_test) +compile_output_test(scoped_pause_test) +benchmark_add_test(NAME scoped_pause_test COMMAND scoped_pause_test) + ############################################################################### # GoogleTest Unit Tests ############################################################################### diff --git a/test/scoped_pause_test.cc b/test/scoped_pause_test.cc new file mode 100644 index 0000000000..93bcfc25a0 --- /dev/null +++ b/test/scoped_pause_test.cc @@ -0,0 +1,30 @@ + +#include +#include + +#include "benchmark/benchmark.h" +#include "output_test.h" + +// BM_ScopedPause sleeps for 10ms in a ScopedPauseTiming block. +// The reported time should be much less than 10ms. +void BM_ScopedPause(benchmark::State& state) { + for (auto _ : state) { + benchmark::ScopedPauseTiming pause(state); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + state.SetIterationTime(0.0); + } +} +BENCHMARK(BM_ScopedPause)->UseManualTime()->Iterations(1); + +void CheckResults(Results const& results) { + // Check that the real time is much less than the 10ms sleep time. + // Allow for up to 1ms of timing noise/overhead. + CHECK_FLOAT_RESULT_VALUE(results, "real_time", LT, 1e6, 0.0); +} +CHECK_BENCHMARK_RESULTS("BM_ScopedPause", &CheckResults); + +int main(int argc, char* argv[]) { + benchmark::MaybeReenterWithoutASLR(argc, argv); + RunOutputTests(argc, argv); + return 0; +}