fc8a082c60
* feat: Add ScopedPauseTiming RAII helper Adds a new `benchmark::ScopedPauseTiming` class that provides a convenient RAII-style mechanism for pausing and resuming benchmark timers. This is less error-prone than manually calling `PauseTiming` and `ResumeTiming`, as it guarantees that the timer is resumed when the scope is exited. - Added `ScopedPauseTiming` to `include/benchmark/state.h`. - Added a new test `test/scoped_pause_test.cc` to verify the functionality and prevent regressions. - Updated `test/CMakeLists.txt` to include the new test. - Added documentation for the new feature in `docs/user_guide.md`. * Bump astral-sh/setup-uv from 7.6.0 to 8.0.0 (#2160) Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 7.6.0 to 8.0.0. - [Release notes](https://github.com/astral-sh/setup-uv/releases) - [Commits](https://github.com/astral-sh/setup-uv/compare/37802adc94f370d6bfd71619e3f0bf239e1f3b78...cec208311dfd045dd5311c1add060b2062131d57) --- updated-dependencies: - dependency-name: astral-sh/setup-uv dependency-version: 8.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump lukka/get-cmake from 4.3.0 to 4.3.1 (#2159) Bumps [lukka/get-cmake](https://github.com/lukka/get-cmake) from 4.3.0 to 4.3.1. - [Release notes](https://github.com/lukka/get-cmake/releases) - [Changelog](https://github.com/lukka/get-cmake/blob/main/RELEASE_PROCESS.md) - [Commits](https://github.com/lukka/get-cmake/compare/b78306120111dc2522750771cfd09ee7ca723687...ea83089aa35e08e459464341fe24ad024ee2466f) --- updated-dependencies: - dependency-name: lukka/get-cmake dependency-version: 4.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> * Bump numpy from 2.4.3 to 2.4.4 in /tools (#2158) Bumps [numpy](https://github.com/numpy/numpy) from 2.4.3 to 2.4.4. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.4.3...v2.4.4) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.4.4 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: dominic <510002+dmah42@users.noreply.github.com> * handle move operators * Use manual time instead of real time for better repeatability --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
283 lines
7.1 KiB
C++
283 lines
7.1 KiB
C++
// Copyright 2015 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef BENCHMARK_STATE_H_
|
|
#define BENCHMARK_STATE_H_
|
|
|
|
#if defined(_MSC_VER)
|
|
#pragma warning(push)
|
|
#pragma warning(disable : 4251 4324)
|
|
#endif
|
|
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "benchmark/counter.h"
|
|
#include "benchmark/macros.h"
|
|
#include "benchmark/statistics.h"
|
|
#include "benchmark/types.h"
|
|
|
|
namespace benchmark {
|
|
|
|
namespace internal {
|
|
class BenchmarkInstance;
|
|
class ThreadTimer;
|
|
class ThreadManager;
|
|
class PerfCountersMeasurement;
|
|
} // namespace internal
|
|
|
|
class ProfilerManager;
|
|
|
|
class BENCHMARK_EXPORT BENCHMARK_INTERNAL_CACHELINE_ALIGNED State {
|
|
public:
|
|
struct StateIterator;
|
|
friend struct StateIterator;
|
|
|
|
inline BENCHMARK_ALWAYS_INLINE StateIterator begin();
|
|
inline BENCHMARK_ALWAYS_INLINE StateIterator end();
|
|
|
|
inline bool KeepRunning();
|
|
|
|
inline bool KeepRunningBatch(IterationCount n);
|
|
|
|
void PauseTiming();
|
|
|
|
void ResumeTiming();
|
|
|
|
void SkipWithMessage(const std::string& msg);
|
|
|
|
void SkipWithError(const std::string& msg);
|
|
|
|
bool skipped() const { return internal::NotSkipped != skipped_; }
|
|
|
|
bool error_occurred() const { return internal::SkippedWithError == skipped_; }
|
|
|
|
void SetIterationTime(double seconds);
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
void SetBytesProcessed(int64_t bytes) {
|
|
counters["bytes_per_second"] =
|
|
Counter(static_cast<double>(bytes), Counter::kIsRate, Counter::kIs1024);
|
|
}
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
int64_t bytes_processed() const {
|
|
if (counters.find("bytes_per_second") != counters.end())
|
|
return static_cast<int64_t>(counters.at("bytes_per_second"));
|
|
return 0;
|
|
}
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
void SetComplexityN(ComplexityN complexity_n) {
|
|
complexity_n_ = complexity_n;
|
|
}
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
ComplexityN complexity_length_n() const { return complexity_n_; }
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
void SetItemsProcessed(int64_t items) {
|
|
counters["items_per_second"] =
|
|
Counter(static_cast<double>(items), benchmark::Counter::kIsRate);
|
|
}
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
int64_t items_processed() const {
|
|
if (counters.find("items_per_second") != counters.end())
|
|
return static_cast<int64_t>(counters.at("items_per_second"));
|
|
return 0;
|
|
}
|
|
|
|
void SetLabel(const std::string& label);
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
int64_t range(std::size_t pos = 0) const {
|
|
assert(range_.size() > pos);
|
|
return range_[pos];
|
|
}
|
|
|
|
BENCHMARK_DEPRECATED_MSG("use 'range(0)' instead")
|
|
int64_t range_x() const { return range(0); }
|
|
|
|
BENCHMARK_DEPRECATED_MSG("use 'range(1)' instead")
|
|
int64_t range_y() const { return range(1); }
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
int threads() const { return threads_; }
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
int thread_index() const { return thread_index_; }
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
IterationCount iterations() const {
|
|
if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) {
|
|
return 0;
|
|
}
|
|
return max_iterations - total_iterations_ + batch_leftover_;
|
|
}
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
std::string name() const { return name_; }
|
|
|
|
size_t range_size() const { return range_.size(); }
|
|
|
|
private:
|
|
IterationCount total_iterations_;
|
|
|
|
IterationCount batch_leftover_;
|
|
|
|
public:
|
|
const IterationCount max_iterations;
|
|
|
|
private:
|
|
bool started_;
|
|
bool finished_;
|
|
internal::Skipped skipped_;
|
|
|
|
std::vector<int64_t> range_;
|
|
|
|
ComplexityN complexity_n_;
|
|
|
|
public:
|
|
UserCounters counters;
|
|
|
|
private:
|
|
State(std::string name, IterationCount max_iters,
|
|
const std::vector<int64_t>& ranges, int thread_i, int n_threads,
|
|
internal::ThreadTimer* timer, internal::ThreadManager* manager,
|
|
internal::PerfCountersMeasurement* perf_counters_measurement,
|
|
ProfilerManager* profiler_manager);
|
|
|
|
void StartKeepRunning();
|
|
inline bool KeepRunningInternal(IterationCount n, bool is_batch);
|
|
void FinishKeepRunning();
|
|
|
|
const std::string name_;
|
|
const int thread_index_;
|
|
const int threads_;
|
|
|
|
internal::ThreadTimer* const timer_;
|
|
internal::ThreadManager* const manager_;
|
|
internal::PerfCountersMeasurement* const perf_counters_measurement_;
|
|
ProfilerManager* const profiler_manager_;
|
|
|
|
friend class internal::BenchmarkInstance;
|
|
};
|
|
|
|
inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunning() {
|
|
return KeepRunningInternal(1, /*is_batch=*/false);
|
|
}
|
|
|
|
inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningBatch(IterationCount n) {
|
|
return KeepRunningInternal(n, /*is_batch=*/true);
|
|
}
|
|
|
|
inline BENCHMARK_ALWAYS_INLINE bool State::KeepRunningInternal(IterationCount n,
|
|
bool is_batch) {
|
|
assert(n > 0);
|
|
assert(is_batch || n == 1);
|
|
if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) {
|
|
total_iterations_ -= n;
|
|
return true;
|
|
}
|
|
if (!started_) {
|
|
StartKeepRunning();
|
|
if (!skipped() && total_iterations_ >= n) {
|
|
total_iterations_ -= n;
|
|
return true;
|
|
}
|
|
}
|
|
if (is_batch && total_iterations_ != 0) {
|
|
batch_leftover_ = n - total_iterations_;
|
|
total_iterations_ = 0;
|
|
return true;
|
|
}
|
|
FinishKeepRunning();
|
|
return false;
|
|
}
|
|
|
|
struct State::StateIterator {
|
|
struct BENCHMARK_UNUSED Value {};
|
|
typedef std::forward_iterator_tag iterator_category;
|
|
typedef Value value_type;
|
|
typedef Value reference;
|
|
typedef Value pointer;
|
|
typedef std::ptrdiff_t difference_type;
|
|
|
|
private:
|
|
friend class State;
|
|
BENCHMARK_ALWAYS_INLINE
|
|
StateIterator() : cached_(0), parent_() {}
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
explicit StateIterator(State* st)
|
|
: cached_(st->skipped() ? 0 : st->max_iterations), parent_(st) {}
|
|
|
|
public:
|
|
BENCHMARK_ALWAYS_INLINE
|
|
Value operator*() const { return Value(); }
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
StateIterator& operator++() {
|
|
assert(cached_ > 0);
|
|
--cached_;
|
|
return *this;
|
|
}
|
|
|
|
BENCHMARK_ALWAYS_INLINE
|
|
bool operator!=(StateIterator const&) const {
|
|
if (BENCHMARK_BUILTIN_EXPECT(cached_ != 0, true)) return true;
|
|
parent_->FinishKeepRunning();
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
IterationCount cached_;
|
|
State* const parent_;
|
|
};
|
|
|
|
inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::begin() {
|
|
return StateIterator(this);
|
|
}
|
|
inline BENCHMARK_ALWAYS_INLINE State::StateIterator State::end() {
|
|
StartKeepRunning();
|
|
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)
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
#endif // BENCHMARK_STATE_H_
|