Commit 40fce80e by Eric Fiselier

Merge branch 'upstream/master' into v2

parents e63fb496 296ec569
...@@ -45,6 +45,9 @@ rules.ninja ...@@ -45,6 +45,9 @@ rules.ninja
build/ build/
_build/ _build/
# in-source dependancies # in-source dependencies
/googletest/ /googletest/
# Visual Studio 2015/2017 cache/options directory
.vs/
CMakeSettings.json
...@@ -172,6 +172,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond); ...@@ -172,6 +172,7 @@ BENCHMARK(BM_test)->Unit(benchmark::kMillisecond);
#include <stdint.h> #include <stdint.h>
#include <algorithm>
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <iosfwd> #include <iosfwd>
...@@ -481,16 +482,18 @@ class State { ...@@ -481,16 +482,18 @@ class State {
// Returns true if the benchmark should continue through another iteration. // Returns true if the benchmark should continue through another iteration.
// NOTE: A benchmark may not return from the test until KeepRunning() has // NOTE: A benchmark may not return from the test until KeepRunning() has
// returned false. // returned false.
bool KeepRunning() { bool KeepRunning();
if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) {
StartKeepRunning(); // Returns true iff the benchmark should run n more iterations.
} // NOTE: A benchmark must not return from the test until KeepRunningBatch()
bool const res = (--total_iterations_ != 0); // has returned false.
if (BENCHMARK_BUILTIN_EXPECT(!res, false)) { // NOTE: KeepRunningBatch() may overshoot by up to 'n' iterations.
FinishKeepRunning(); //
} // Intended usage:
return res; // while (state.KeepRunningBatch(1000)) {
} // // process 1000 elements
// }
bool KeepRunningBatch(size_t n);
// REQUIRES: timer is running and 'SkipWithError(...)' has not been called // REQUIRES: timer is running and 'SkipWithError(...)' has not been called
// by the current thread. // by the current thread.
...@@ -635,12 +638,16 @@ class State { ...@@ -635,12 +638,16 @@ class State {
int range_y() const { return range(1); } int range_y() const { return range(1); }
BENCHMARK_ALWAYS_INLINE BENCHMARK_ALWAYS_INLINE
size_t iterations() const { return (max_iterations - total_iterations_) + 1; } size_t iterations() const {
return (max_iterations - total_iterations_ + batch_leftover_);
}
private: private:
bool started_; bool started_;
bool finished_; bool finished_;
// When total_iterations_ is 0, KeepRunning() and friends will return false.
size_t total_iterations_; size_t total_iterations_;
// May be larger than max_iterations.
std::vector<int> range_; std::vector<int> range_;
internal::JSONPointer json_input_; internal::JSONPointer json_input_;
...@@ -653,6 +660,11 @@ class State { ...@@ -653,6 +660,11 @@ class State {
bool error_occurred_; bool error_occurred_;
// When using KeepRunningBatch(), batch_leftover_ holds the number of
// iterations beyond max_iters that were run. Used to track
// completed_iterations_ accurately.
size_t batch_leftover_;
public: public:
// Container for user-defined counters. // Container for user-defined counters.
UserCounters counters; UserCounters counters;
...@@ -675,6 +687,50 @@ class State { ...@@ -675,6 +687,50 @@ class State {
BENCHMARK_DISALLOW_COPY_AND_ASSIGN(State); BENCHMARK_DISALLOW_COPY_AND_ASSIGN(State);
}; };
inline BENCHMARK_ALWAYS_INLINE
bool State::KeepRunning() {
// total_iterations_ is set to 0 by the constructor, and always set to a
// nonzero value by StartKepRunning().
if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ != 0, true)) {
--total_iterations_;
return true;
}
if (!started_) {
StartKeepRunning();
if (!error_occurred_) {
// max_iterations > 0. The first iteration is always valid.
--total_iterations_;
return true;
}
}
FinishKeepRunning();
return false;
}
inline BENCHMARK_ALWAYS_INLINE
bool State::KeepRunningBatch(size_t n) {
// total_iterations_ is set to 0 by the constructor, and always set to a
// nonzero value by StartKepRunning().
if (BENCHMARK_BUILTIN_EXPECT(total_iterations_ >= n, true)) {
total_iterations_ -= n;
return true;
}
if (!started_) {
StartKeepRunning();
if (!error_occurred_ && total_iterations_ >= n) {
total_iterations_-= n;
return true;
}
}
if (total_iterations_ != 0) {
batch_leftover_ = n - total_iterations_;
total_iterations_ = 0;
return true;
}
FinishKeepRunning();
return false;
}
struct State::StateIterator { struct State::StateIterator {
struct BENCHMARK_UNUSED Value {}; struct BENCHMARK_UNUSED Value {};
typedef std::forward_iterator_tag iterator_category; typedef std::forward_iterator_tag iterator_category;
......
...@@ -280,7 +280,7 @@ void RunInThread(const benchmark::internal::Benchmark::Instance* b, ...@@ -280,7 +280,7 @@ void RunInThread(const benchmark::internal::Benchmark::Instance* b,
State st(iters, b->arg, internal::JSONPointer(b->json_arg), thread_id, State st(iters, b->arg, internal::JSONPointer(b->json_arg), thread_id,
b->threads, &timer, manager); b->threads, &timer, manager);
b->benchmark->Run(st); b->benchmark->Run(st);
CHECK(st.iterations() == st.max_iterations) CHECK(st.iterations() >= st.max_iterations)
<< "Benchmark returned before State::KeepRunning() returned false!"; << "Benchmark returned before State::KeepRunning() returned false!";
{ {
MutexLock l(manager->GetBenchmarkMutex()); MutexLock l(manager->GetBenchmarkMutex());
...@@ -421,7 +421,7 @@ State::State(size_t max_iters, const std::vector<int>& ranges, ...@@ -421,7 +421,7 @@ State::State(size_t max_iters, const std::vector<int>& ranges,
internal::ThreadManager* manager) internal::ThreadManager* manager)
: started_(false), : started_(false),
finished_(false), finished_(false),
total_iterations_(max_iters + 1), total_iterations_(0),
range_(ranges), range_(ranges),
json_input_(std::move(json_ptr)), json_input_(std::move(json_ptr)),
json_output_(json::object_t{}), json_output_(json::object_t{}),
...@@ -429,6 +429,7 @@ State::State(size_t max_iters, const std::vector<int>& ranges, ...@@ -429,6 +429,7 @@ State::State(size_t max_iters, const std::vector<int>& ranges,
items_processed_(0), items_processed_(0),
complexity_n_(0), complexity_n_(0),
error_occurred_(false), error_occurred_(false),
batch_leftover_(0),
counters(), counters(),
thread_index(thread_i), thread_index(thread_i),
threads(n_threads), threads(n_threads),
...@@ -436,7 +437,6 @@ State::State(size_t max_iters, const std::vector<int>& ranges, ...@@ -436,7 +437,6 @@ State::State(size_t max_iters, const std::vector<int>& ranges,
timer_(timer), timer_(timer),
manager_(manager) { manager_(manager) {
CHECK(max_iterations != 0) << "At least one iteration must be run"; CHECK(max_iterations != 0) << "At least one iteration must be run";
CHECK(total_iterations_ != 0) << "max iterations wrapped around";
CHECK_LT(thread_index, threads) << "thread_index must be less than threads"; CHECK_LT(thread_index, threads) << "thread_index must be less than threads";
} }
...@@ -461,7 +461,7 @@ void State::SkipWithError(const char* msg) { ...@@ -461,7 +461,7 @@ void State::SkipWithError(const char* msg) {
manager_->results.has_error_ = true; manager_->results.has_error_ = true;
} }
} }
total_iterations_ = 1; total_iterations_ = 0;
if (timer_->running()) timer_->StopTimer(); if (timer_->running()) timer_->StopTimer();
} }
...@@ -477,6 +477,7 @@ void State::SetLabel(const char* label) { ...@@ -477,6 +477,7 @@ void State::SetLabel(const char* label) {
void State::StartKeepRunning() { void State::StartKeepRunning() {
CHECK(!started_ && !finished_); CHECK(!started_ && !finished_);
started_ = true; started_ = true;
total_iterations_ = error_occurred_ ? 0 : max_iterations;
manager_->StartStopBarrier(); manager_->StartStopBarrier();
if (!error_occurred_) ResumeTiming(); if (!error_occurred_) ResumeTiming();
} }
...@@ -486,8 +487,8 @@ void State::FinishKeepRunning() { ...@@ -486,8 +487,8 @@ void State::FinishKeepRunning() {
if (!error_occurred_) { if (!error_occurred_) {
PauseTiming(); PauseTiming();
} }
// Total iterations has now wrapped around zero. Fix this. // Total iterations has now wrapped around past 0. Fix this.
total_iterations_ = 1; total_iterations_ = 0;
finished_ = true; finished_ = true;
manager_->StartStopBarrier(); manager_->StartStopBarrier();
} }
......
...@@ -11,29 +11,35 @@ ...@@ -11,29 +11,35 @@
#endif #endif
#if defined(__clang__) #if defined(__clang__)
#define COMPILER_CLANG #if !defined(COMPILER_CLANG)
#define COMPILER_CLANG
#endif
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define COMPILER_MSVC #if !defined(COMPILER_MSVC)
#define COMPILER_MSVC
#endif
#elif defined(__GNUC__) #elif defined(__GNUC__)
#define COMPILER_GCC #if !defined(COMPILER_GCC)
#define COMPILER_GCC
#endif
#endif #endif
#if __has_feature(cxx_attributes) #if __has_feature(cxx_attributes)
#define BENCHMARK_NORETURN [[noreturn]] #define BENCHMARK_NORETURN [[noreturn]]
#elif defined(__GNUC__) #elif defined(__GNUC__)
#define BENCHMARK_NORETURN __attribute__((noreturn)) #define BENCHMARK_NORETURN __attribute__((noreturn))
#elif defined(COMPILER_MSVC) #elif defined(COMPILER_MSVC)
#define BENCHMARK_NORETURN __declspec(noreturn) #define BENCHMARK_NORETURN __declspec(noreturn)
#else #else
#define BENCHMARK_NORETURN #define BENCHMARK_NORETURN
#endif #endif
#if defined(__CYGWIN__) #if defined(__CYGWIN__)
#define BENCHMARK_OS_CYGWIN 1 #define BENCHMARK_OS_CYGWIN 1
#elif defined(_WIN32) #elif defined(_WIN32)
#define BENCHMARK_OS_WINDOWS 1 #define BENCHMARK_OS_WINDOWS 1
#elif defined(__APPLE__) #elif defined(__APPLE__)
#include "TargetConditionals.h" #include "TargetConditionals.h"
#if defined(TARGET_OS_MAC) #if defined(TARGET_OS_MAC)
#define BENCHMARK_OS_MACOSX 1 #define BENCHMARK_OS_MACOSX 1
#if defined(TARGET_OS_IPHONE) #if defined(TARGET_OS_IPHONE)
...@@ -41,36 +47,36 @@ ...@@ -41,36 +47,36 @@
#endif #endif
#endif #endif
#elif defined(__FreeBSD__) #elif defined(__FreeBSD__)
#define BENCHMARK_OS_FREEBSD 1 #define BENCHMARK_OS_FREEBSD 1
#elif defined(__NetBSD__) #elif defined(__NetBSD__)
#define BENCHMARK_OS_NETBSD 1 #define BENCHMARK_OS_NETBSD 1
#elif defined(__linux__) #elif defined(__linux__)
#define BENCHMARK_OS_LINUX 1 #define BENCHMARK_OS_LINUX 1
#elif defined(__native_client__) #elif defined(__native_client__)
#define BENCHMARK_OS_NACL 1 #define BENCHMARK_OS_NACL 1
#elif defined(EMSCRIPTEN) #elif defined(EMSCRIPTEN)
#define BENCHMARK_OS_EMSCRIPTEN 1 #define BENCHMARK_OS_EMSCRIPTEN 1
#elif defined(__rtems__) #elif defined(__rtems__)
#define BENCHMARK_OS_RTEMS 1 #define BENCHMARK_OS_RTEMS 1
#endif #endif
#if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \ #if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \
&& !defined(__EXCEPTIONS) && !defined(__EXCEPTIONS)
#define BENCHMARK_HAS_NO_EXCEPTIONS #define BENCHMARK_HAS_NO_EXCEPTIONS
#endif #endif
#if defined(COMPILER_CLANG) || defined(COMPILER_GCC) #if defined(COMPILER_CLANG) || defined(COMPILER_GCC)
#define BENCHMARK_MAYBE_UNUSED __attribute__((unused)) #define BENCHMARK_MAYBE_UNUSED __attribute__((unused))
#else #else
#define BENCHMARK_MAYBE_UNUSED #define BENCHMARK_MAYBE_UNUSED
#endif #endif
#if defined(COMPILER_GCC) || __has_builtin(__builtin_unreachable) #if defined(COMPILER_GCC) || __has_builtin(__builtin_unreachable)
#define BENCHMARK_UNREACHABLE() __builtin_unreachable() #define BENCHMARK_UNREACHABLE() __builtin_unreachable()
#elif defined(COMPILER_MSVC) #elif defined(COMPILER_MSVC)
#define BENCHMARK_UNREACHABLE() __assume(false) #define BENCHMARK_UNREACHABLE() __assume(false)
#else #else
#define BENCHMARK_UNREACHABLE() ((void)0) #define BENCHMARK_UNREACHABLE() ((void)0)
#endif #endif
#endif // BENCHMARK_INTERNAL_MACROS_H_ #endif // BENCHMARK_INTERNAL_MACROS_H_
...@@ -30,7 +30,7 @@ auto StatisticsSum = [](const std::vector<double>& v) { ...@@ -30,7 +30,7 @@ auto StatisticsSum = [](const std::vector<double>& v) {
}; };
double StatisticsMean(const std::vector<double>& v) { double StatisticsMean(const std::vector<double>& v) {
if (v.size() == 0) return 0.0; if (v.empty()) return 0.0;
return StatisticsSum(v) * (1.0 / v.size()); return StatisticsSum(v) * (1.0 / v.size());
} }
...@@ -62,7 +62,7 @@ auto Sqrt = [](const double dat) { ...@@ -62,7 +62,7 @@ auto Sqrt = [](const double dat) {
double StatisticsStdDev(const std::vector<double>& v) { double StatisticsStdDev(const std::vector<double>& v) {
const auto mean = StatisticsMean(v); const auto mean = StatisticsMean(v);
if (v.size() == 0) return mean; if (v.empty()) return mean;
// Sample standard deviation is undefined for n = 1 // Sample standard deviation is undefined for n = 1
if (v.size() == 1) if (v.size() == 1)
......
...@@ -303,7 +303,7 @@ std::vector<CPUInfo::CacheInfo> GetCacheSizesWindows() { ...@@ -303,7 +303,7 @@ std::vector<CPUInfo::CacheInfo> GetCacheSizesWindows() {
if (!B.test(0)) continue; if (!B.test(0)) continue;
CInfo* Cache = &it->Cache; CInfo* Cache = &it->Cache;
CPUInfo::CacheInfo C; CPUInfo::CacheInfo C;
C.num_sharing = B.count(); C.num_sharing = static_cast<int>(B.count());
C.level = Cache->Level; C.level = Cache->Level;
C.size = Cache->Size; C.size = Cache->Size;
switch (Cache->Type) { switch (Cache->Type) {
......
...@@ -102,10 +102,21 @@ void BM_KeepRunning(benchmark::State& state) { ...@@ -102,10 +102,21 @@ void BM_KeepRunning(benchmark::State& state) {
while (state.KeepRunning()) { while (state.KeepRunning()) {
++iter_count; ++iter_count;
} }
assert(iter_count == state.max_iterations); assert(iter_count == state.iterations());
} }
BENCHMARK(BM_KeepRunning); BENCHMARK(BM_KeepRunning);
void BM_KeepRunningBatch(benchmark::State& state) {
// Choose a prime batch size to avoid evenly dividing max_iterations.
const size_t batch_size = 101;
size_t iter_count = 0;
while (state.KeepRunningBatch(batch_size)) {
iter_count += batch_size;
}
assert(state.iterations() == iter_count);
}
BENCHMARK(BM_KeepRunningBatch);
void BM_RangedFor(benchmark::State& state) { void BM_RangedFor(benchmark::State& state) {
size_t iter_count = 0; size_t iter_count = 0;
for (auto _ : state) { for (auto _ : state) {
......
...@@ -70,6 +70,16 @@ void BM_error_before_running(benchmark::State& state) { ...@@ -70,6 +70,16 @@ void BM_error_before_running(benchmark::State& state) {
BENCHMARK(BM_error_before_running); BENCHMARK(BM_error_before_running);
ADD_CASES("BM_error_before_running", {{"", true, "error message"}}); ADD_CASES("BM_error_before_running", {{"", true, "error message"}});
void BM_error_before_running_batch(benchmark::State& state) {
state.SkipWithError("error message");
while (state.KeepRunningBatch(17)) {
assert(false);
}
}
BENCHMARK(BM_error_before_running_batch);
ADD_CASES("BM_error_before_running_batch", {{"", true, "error message"}});
void BM_error_before_running_range_for(benchmark::State& state) { void BM_error_before_running_range_for(benchmark::State& state) {
state.SkipWithError("error message"); state.SkipWithError("error message");
for (auto _ : state) { for (auto _ : state) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment