// 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 #include #include #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(bytes), Counter::kIsRate, Counter::kIs1024); } BENCHMARK_ALWAYS_INLINE int64_t bytes_processed() const { if (counters.find("bytes_per_second") != counters.end()) return static_cast(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(items), benchmark::Counter::kIsRate); } BENCHMARK_ALWAYS_INLINE int64_t items_processed() const { if (counters.find("items_per_second") != counters.end()) return static_cast(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 range_; ComplexityN complexity_n_; public: UserCounters counters; private: State(std::string name, IterationCount max_iters, const std::vector& 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_