Unverified Commit c0783374 by Paweł Bylica Committed by GitHub

Relax CHECK condition in benchmark_runner.cc (#938)

* Add State::error_occurred() * Relax CHECK condition in benchmark_runner.cc If the benchmark state contains an error, do not expect any iterations has been run. This allows using SkipWithError() and return early from the benchmark function. * README.md: document new possible usage of SkipWithError()
parent 168604d8
...@@ -1184,7 +1184,9 @@ Users must explicitly exit the loop, otherwise all iterations will be performed. ...@@ -1184,7 +1184,9 @@ Users must explicitly exit the loop, otherwise all iterations will be performed.
Users may explicitly return to exit the benchmark immediately. Users may explicitly return to exit the benchmark immediately.
The `SkipWithError(...)` function may be used at any point within the benchmark, The `SkipWithError(...)` function may be used at any point within the benchmark,
including before and after the benchmark loop. including before and after the benchmark loop. Moreover, if `SkipWithError(...)`
has been used, it is not required to reach the benchmark loop and one may return
from the benchmark function early.
For example: For example:
...@@ -1192,24 +1194,32 @@ For example: ...@@ -1192,24 +1194,32 @@ For example:
static void BM_test(benchmark::State& state) { static void BM_test(benchmark::State& state) {
auto resource = GetResource(); auto resource = GetResource();
if (!resource.good()) { if (!resource.good()) {
state.SkipWithError("Resource is not good!"); state.SkipWithError("Resource is not good!");
// KeepRunning() loop will not be entered. // KeepRunning() loop will not be entered.
} }
while (state.KeepRunning()) { while (state.KeepRunning()) {
auto data = resource.read_data(); auto data = resource.read_data();
if (!resource.good()) { if (!resource.good()) {
state.SkipWithError("Failed to read data!"); state.SkipWithError("Failed to read data!");
break; // Needed to skip the rest of the iteration. break; // Needed to skip the rest of the iteration.
} }
do_stuff(data); do_stuff(data);
} }
} }
static void BM_test_ranged_fo(benchmark::State & state) { static void BM_test_ranged_fo(benchmark::State & state) {
state.SkipWithError("test will not be entered"); auto resource = GetResource();
if (!resource.good()) {
state.SkipWithError("Resource is not good!");
return; // Early return is allowed when SkipWithError() has been used.
}
for (auto _ : state) { for (auto _ : state) {
state.SkipWithError("Failed!"); auto data = resource.read_data();
break; // REQUIRED to prevent all further iterations. if (!resource.good()) {
state.SkipWithError("Failed to read data!");
break; // REQUIRED to prevent all further iterations.
}
do_stuff(data);
} }
} }
``` ```
......
...@@ -541,6 +541,9 @@ class State { ...@@ -541,6 +541,9 @@ class State {
// responsibility to exit the scope as needed. // responsibility to exit the scope as needed.
void SkipWithError(const char* msg); void SkipWithError(const char* msg);
// Returns true if an error has been reported with 'SkipWithError(...)'.
bool error_occurred() const { return error_occurred_; }
// REQUIRES: called exactly once per iteration of the benchmarking loop. // REQUIRES: called exactly once per iteration of the benchmarking loop.
// Set the manually measured time for this benchmark iteration, which // Set the manually measured time for this benchmark iteration, which
// is used instead of automatically measured time if UseManualTime() was // is used instead of automatically measured time if UseManualTime() was
......
...@@ -117,7 +117,7 @@ void RunInThread(const BenchmarkInstance* b, IterationCount iters, ...@@ -117,7 +117,7 @@ void RunInThread(const BenchmarkInstance* b, IterationCount iters,
? internal::ThreadTimer::CreateProcessCpuTime() ? internal::ThreadTimer::CreateProcessCpuTime()
: internal::ThreadTimer::Create()); : internal::ThreadTimer::Create());
State st = b->Run(iters, thread_id, &timer, manager); State st = b->Run(iters, thread_id, &timer, manager);
CHECK(st.iterations() >= st.max_iterations) CHECK(st.error_occurred() || 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());
......
...@@ -61,6 +61,12 @@ int AddCases(const char* base_name, std::initializer_list<TestCase> const& v) { ...@@ -61,6 +61,12 @@ int AddCases(const char* base_name, std::initializer_list<TestCase> const& v) {
} // end namespace } // end namespace
void BM_error_no_running(benchmark::State& state) {
state.SkipWithError("error message");
}
BENCHMARK(BM_error_no_running);
ADD_CASES("BM_error_no_running", {{"", true, "error message"}});
void BM_error_before_running(benchmark::State& state) { void BM_error_before_running(benchmark::State& state) {
state.SkipWithError("error message"); state.SkipWithError("error message");
while (state.KeepRunning()) { while (state.KeepRunning()) {
......
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