blob: 356c5509a0a2d0b2c00eb6a9431d3f9254640a8d [file]
// 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_