Merge branch 'upstream/master' into v2
diff --git a/.gitignore b/.gitignore
index bfc6b57..93d5ced 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,6 +45,9 @@
build/
_build/
-# in-source dependancies
+# in-source dependencies
/googletest/
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+CMakeSettings.json
diff --git a/include/benchmark/benchmark.h b/include/benchmark/benchmark.h
index a59bd6e..1946d30 100644
--- a/include/benchmark/benchmark.h
+++ b/include/benchmark/benchmark.h
@@ -172,6 +172,7 @@
#include <stdint.h>
+#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iosfwd>
@@ -481,16 +482,18 @@
// Returns true if the benchmark should continue through another iteration.
// NOTE: A benchmark may not return from the test until KeepRunning() has
// returned false.
- bool KeepRunning() {
- if (BENCHMARK_BUILTIN_EXPECT(!started_, false)) {
- StartKeepRunning();
- }
- bool const res = (--total_iterations_ != 0);
- if (BENCHMARK_BUILTIN_EXPECT(!res, false)) {
- FinishKeepRunning();
- }
- return res;
- }
+ bool KeepRunning();
+
+ // Returns true iff the benchmark should run n more iterations.
+ // NOTE: A benchmark must not return from the test until KeepRunningBatch()
+ // has returned false.
+ // NOTE: KeepRunningBatch() may overshoot by up to 'n' iterations.
+ //
+ // Intended usage:
+ // while (state.KeepRunningBatch(1000)) {
+ // // process 1000 elements
+ // }
+ bool KeepRunningBatch(size_t n);
// REQUIRES: timer is running and 'SkipWithError(...)' has not been called
// by the current thread.
@@ -635,12 +638,16 @@
int range_y() const { return range(1); }
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:
bool started_;
bool finished_;
+ // When total_iterations_ is 0, KeepRunning() and friends will return false.
size_t total_iterations_;
+ // May be larger than max_iterations.
std::vector<int> range_;
internal::JSONPointer json_input_;
@@ -653,6 +660,11 @@
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:
// Container for user-defined counters.
UserCounters counters;
@@ -675,6 +687,50 @@
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 BENCHMARK_UNUSED Value {};
typedef std::forward_iterator_tag iterator_category;
diff --git a/src/benchmark.cc b/src/benchmark.cc
index 43d4f8f..f04e2f7 100644
--- a/src/benchmark.cc
+++ b/src/benchmark.cc
@@ -280,7 +280,7 @@
State st(iters, b->arg, internal::JSONPointer(b->json_arg), thread_id,
b->threads, &timer, manager);
b->benchmark->Run(st);
- CHECK(st.iterations() == st.max_iterations)
+ CHECK(st.iterations() >= st.max_iterations)
<< "Benchmark returned before State::KeepRunning() returned false!";
{
MutexLock l(manager->GetBenchmarkMutex());
@@ -421,7 +421,7 @@
internal::ThreadManager* manager)
: started_(false),
finished_(false),
- total_iterations_(max_iters + 1),
+ total_iterations_(0),
range_(ranges),
json_input_(std::move(json_ptr)),
json_output_(json::object_t{}),
@@ -429,6 +429,7 @@
items_processed_(0),
complexity_n_(0),
error_occurred_(false),
+ batch_leftover_(0),
counters(),
thread_index(thread_i),
threads(n_threads),
@@ -436,7 +437,6 @@
timer_(timer),
manager_(manager) {
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";
}
@@ -461,7 +461,7 @@
manager_->results.has_error_ = true;
}
}
- total_iterations_ = 1;
+ total_iterations_ = 0;
if (timer_->running()) timer_->StopTimer();
}
@@ -477,6 +477,7 @@
void State::StartKeepRunning() {
CHECK(!started_ && !finished_);
started_ = true;
+ total_iterations_ = error_occurred_ ? 0 : max_iterations;
manager_->StartStopBarrier();
if (!error_occurred_) ResumeTiming();
}
@@ -486,8 +487,8 @@
if (!error_occurred_) {
PauseTiming();
}
- // Total iterations has now wrapped around zero. Fix this.
- total_iterations_ = 1;
+ // Total iterations has now wrapped around past 0. Fix this.
+ total_iterations_ = 0;
finished_ = true;
manager_->StartStopBarrier();
}
diff --git a/src/internal_macros.h b/src/internal_macros.h
index 6cdb3c2..c34f571 100644
--- a/src/internal_macros.h
+++ b/src/internal_macros.h
@@ -11,29 +11,35 @@
#endif
#if defined(__clang__)
-#define COMPILER_CLANG
+ #if !defined(COMPILER_CLANG)
+ #define COMPILER_CLANG
+ #endif
#elif defined(_MSC_VER)
-#define COMPILER_MSVC
+ #if !defined(COMPILER_MSVC)
+ #define COMPILER_MSVC
+ #endif
#elif defined(__GNUC__)
-#define COMPILER_GCC
+ #if !defined(COMPILER_GCC)
+ #define COMPILER_GCC
+ #endif
#endif
#if __has_feature(cxx_attributes)
-#define BENCHMARK_NORETURN [[noreturn]]
+ #define BENCHMARK_NORETURN [[noreturn]]
#elif defined(__GNUC__)
-#define BENCHMARK_NORETURN __attribute__((noreturn))
+ #define BENCHMARK_NORETURN __attribute__((noreturn))
#elif defined(COMPILER_MSVC)
-#define BENCHMARK_NORETURN __declspec(noreturn)
+ #define BENCHMARK_NORETURN __declspec(noreturn)
#else
-#define BENCHMARK_NORETURN
+ #define BENCHMARK_NORETURN
#endif
#if defined(__CYGWIN__)
-#define BENCHMARK_OS_CYGWIN 1
+ #define BENCHMARK_OS_CYGWIN 1
#elif defined(_WIN32)
-#define BENCHMARK_OS_WINDOWS 1
+ #define BENCHMARK_OS_WINDOWS 1
#elif defined(__APPLE__)
-#include "TargetConditionals.h"
+ #include "TargetConditionals.h"
#if defined(TARGET_OS_MAC)
#define BENCHMARK_OS_MACOSX 1
#if defined(TARGET_OS_IPHONE)
@@ -41,36 +47,36 @@
#endif
#endif
#elif defined(__FreeBSD__)
-#define BENCHMARK_OS_FREEBSD 1
+ #define BENCHMARK_OS_FREEBSD 1
#elif defined(__NetBSD__)
-#define BENCHMARK_OS_NETBSD 1
+ #define BENCHMARK_OS_NETBSD 1
#elif defined(__linux__)
-#define BENCHMARK_OS_LINUX 1
+ #define BENCHMARK_OS_LINUX 1
#elif defined(__native_client__)
-#define BENCHMARK_OS_NACL 1
+ #define BENCHMARK_OS_NACL 1
#elif defined(EMSCRIPTEN)
-#define BENCHMARK_OS_EMSCRIPTEN 1
+ #define BENCHMARK_OS_EMSCRIPTEN 1
#elif defined(__rtems__)
-#define BENCHMARK_OS_RTEMS 1
+ #define BENCHMARK_OS_RTEMS 1
#endif
#if !__has_feature(cxx_exceptions) && !defined(__cpp_exceptions) \
&& !defined(__EXCEPTIONS)
-#define BENCHMARK_HAS_NO_EXCEPTIONS
+ #define BENCHMARK_HAS_NO_EXCEPTIONS
#endif
#if defined(COMPILER_CLANG) || defined(COMPILER_GCC)
-#define BENCHMARK_MAYBE_UNUSED __attribute__((unused))
+ #define BENCHMARK_MAYBE_UNUSED __attribute__((unused))
#else
-#define BENCHMARK_MAYBE_UNUSED
+ #define BENCHMARK_MAYBE_UNUSED
#endif
#if defined(COMPILER_GCC) || __has_builtin(__builtin_unreachable)
-#define BENCHMARK_UNREACHABLE() __builtin_unreachable()
+ #define BENCHMARK_UNREACHABLE() __builtin_unreachable()
#elif defined(COMPILER_MSVC)
-#define BENCHMARK_UNREACHABLE() __assume(false)
+ #define BENCHMARK_UNREACHABLE() __assume(false)
#else
-#define BENCHMARK_UNREACHABLE() ((void)0)
+ #define BENCHMARK_UNREACHABLE() ((void)0)
#endif
#endif // BENCHMARK_INTERNAL_MACROS_H_
diff --git a/src/statistics.cc b/src/statistics.cc
index 5932ad4..d284367 100644
--- a/src/statistics.cc
+++ b/src/statistics.cc
@@ -30,7 +30,7 @@
};
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());
}
@@ -62,7 +62,7 @@
double StatisticsStdDev(const std::vector<double>& 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
if (v.size() == 1)
diff --git a/src/sysinfo.cc b/src/sysinfo.cc
index 2520ad5..90be166 100644
--- a/src/sysinfo.cc
+++ b/src/sysinfo.cc
@@ -303,7 +303,7 @@
if (!B.test(0)) continue;
CInfo* Cache = &it->Cache;
CPUInfo::CacheInfo C;
- C.num_sharing = B.count();
+ C.num_sharing = static_cast<int>(B.count());
C.level = Cache->Level;
C.size = Cache->Size;
switch (Cache->Type) {
diff --git a/test/basic_test.cc b/test/basic_test.cc
index 3348781..12579c0 100644
--- a/test/basic_test.cc
+++ b/test/basic_test.cc
@@ -102,10 +102,21 @@
while (state.KeepRunning()) {
++iter_count;
}
- assert(iter_count == state.max_iterations);
+ assert(iter_count == state.iterations());
}
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) {
size_t iter_count = 0;
for (auto _ : state) {
diff --git a/test/skip_with_error_test.cc b/test/skip_with_error_test.cc
index 0c2f348..8d2c342 100644
--- a/test/skip_with_error_test.cc
+++ b/test/skip_with_error_test.cc
@@ -70,6 +70,16 @@
BENCHMARK(BM_error_before_running);
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) {
state.SkipWithError("error message");
for (auto _ : state) {