Add 'benchmark::DoNotOptimize(...)' to help users prevent optimizations
diff --git a/README.md b/README.md
index 553e34a..4c0d77a 100644
--- a/README.md
+++ b/README.md
@@ -160,6 +160,19 @@
}
}
BENCHMARK(BM_MultiThreaded)->Threads(2);
+
+To prevent a value or expression from being optimized away by the compiler
+the `benchmark::DoNotOptimize(...)` function can be used.
+
+```c++
+static void BM_test(benchmark::State& state) {
+ while (state.KeepRunning()) {
+ int x = 0;
+ for (int i=0; i < 64; ++i) {
+ benchmark::DoNotOptimize(x += i);
+ }
+ }
+}
```
diff --git a/include/benchmark/benchmark_api.h b/include/benchmark/benchmark_api.h
index 340ef6f..ed55c88 100644
--- a/include/benchmark/benchmark_api.h
+++ b/include/benchmark/benchmark_api.h
@@ -174,8 +174,27 @@
typedef int type;
};
+void UseCharPointer(char const volatile*);
+
} // end namespace internal
+// The DoNotOptimize(...) function can be used to prevent a value or
+// expression from being optimized away by the compiler. This function is
+// intented to add little to no overhead.
+// See: http://stackoverflow.com/questions/28287064
+#if defined(__GNUC__)
+template <class Tp>
+inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
+ asm volatile("" : "+r" (const_cast<Tp&>(value)));
+}
+#else
+template <class Tp>
+inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
+ internal::UseCharPointer(&reinterpret_cast<char const volatile&>(value));
+}
+#endif
+
+
// State is passed to a running Benchmark and contains state for the
// benchmark to use.
class State {
diff --git a/src/benchmark.cc b/src/benchmark.cc
index 5fc149b..9643a2a 100644
--- a/src/benchmark.cc
+++ b/src/benchmark.cc
@@ -73,6 +73,8 @@
namespace internal {
+void UseCharPointer(char const volatile*) {}
+
// NOTE: This is a dummy "mutex" type used to denote the actual mutex
// returned by GetBenchmarkLock(). This is only used to placate the thread
// safety warnings by giving the return of GetBenchmarkLock() a name.
diff --git a/test/basic_test.cc b/test/basic_test.cc
index fedcf08..f7b45be 100644
--- a/test/basic_test.cc
+++ b/test/basic_test.cc
@@ -8,8 +8,7 @@
void BM_empty(benchmark::State& state) {
while (state.KeepRunning()) {
- volatile std::size_t x = state.iterations();
- ((void)x);
+ benchmark::DoNotOptimize(state.iterations());
}
}
BENCHMARK(BM_empty);
@@ -18,8 +17,7 @@
void BM_spin_empty(benchmark::State& state) {
while (state.KeepRunning()) {
for (int x = 0; x < state.range_x(); ++x) {
- volatile int dummy = x;
- ((void)dummy);
+ benchmark::DoNotOptimize(x);
}
}
}
@@ -28,13 +26,11 @@
void BM_spin_pause_before(benchmark::State& state) {
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
while(state.KeepRunning()) {
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
}
}
@@ -46,13 +42,11 @@
while(state.KeepRunning()) {
state.PauseTiming();
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
state.ResumeTiming();
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
}
}
@@ -81,13 +75,11 @@
void BM_spin_pause_after(benchmark::State& state) {
while(state.KeepRunning()) {
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
}
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
}
BASIC_BENCHMARK_TEST(BM_spin_pause_after);
@@ -96,18 +88,15 @@
void BM_spin_pause_before_and_after(benchmark::State& state) {
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
while(state.KeepRunning()) {
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
}
for (int i = 0; i < state.range_x(); ++i) {
- volatile int dummy = i;
- ((void)dummy);
+ benchmark::DoNotOptimize(i);
}
}
BASIC_BENCHMARK_TEST(BM_spin_pause_before_and_after);
diff --git a/test/benchmark_test.cc b/test/benchmark_test.cc
index f5abe61..2fb3355 100644
--- a/test/benchmark_test.cc
+++ b/test/benchmark_test.cc
@@ -84,9 +84,8 @@
static void BM_CalculatePi(benchmark::State& state) {
static const int depth = 1024;
- double pi BENCHMARK_UNUSED = 0.0;
while (state.KeepRunning()) {
- pi = CalculatePi(depth);
+ benchmark::DoNotOptimize(CalculatePi(depth));
}
}
BENCHMARK(BM_CalculatePi)->Threads(8);
@@ -129,11 +128,8 @@
static void BM_StringCompare(benchmark::State& state) {
std::string s1(state.range_x(), '-');
std::string s2(state.range_x(), '-');
- int r = 0;
while (state.KeepRunning())
- r |= s1.compare(s2);
- // Prevent compiler optimizations
- assert(r != std::numeric_limits<int>::max());
+ benchmark::DoNotOptimize(s1.compare(s2));
}
BENCHMARK(BM_StringCompare)->Range(1, 1<<20);
@@ -159,10 +155,10 @@
static void BM_LongTest(benchmark::State& state) {
double tracker = 0.0;
- while (state.KeepRunning())
+ while (state.KeepRunning()) {
for (int i = 0; i < state.range_x(); ++i)
- tracker += i;
- assert(tracker > 1.0);
+ benchmark::DoNotOptimize(tracker += i);
+ }
}
BENCHMARK(BM_LongTest)->Range(1<<16,1<<28);