mirror of
https://github.com/google/benchmark.git
synced 2025-03-14 03:10:22 +08:00
Custom user counters: add invert modifier. (#850)
While current counters can e.g. answer the question "how many items is processed per second", it is impossible to get it to tell "how many seconds it takes to process a single item". The solution is to add a yet another modifier `kInvert`, that is *always* considered last, which simply inverts the answer. Fixes #781, #830, #848.
This commit is contained in:
parent
c408461983
commit
7d97a057e1
12
README.md
12
README.md
@ -662,9 +662,9 @@ the resulting sum is the value which will be shown for the benchmark.
|
||||
|
||||
The `Counter` constructor accepts three parameters: the value as a `double`
|
||||
; a bit flag which allows you to show counters as rates, and/or as per-thread
|
||||
iteration, and/or as per-thread averages, and/or iteration invariants;
|
||||
and a flag specifying the 'unit' - i.e. is 1k a 1000 (default,
|
||||
`benchmark::Counter::OneK::kIs1000`), or 1024
|
||||
iteration, and/or as per-thread averages, and/or iteration invariants,
|
||||
and/or finally inverting the result; and a flag specifying the 'unit' - i.e.
|
||||
is 1k a 1000 (default, `benchmark::Counter::OneK::kIs1000`), or 1024
|
||||
(`benchmark::Counter::OneK::kIs1024`)?
|
||||
|
||||
```c++
|
||||
@ -673,8 +673,14 @@ and a flag specifying the 'unit' - i.e. is 1k a 1000 (default,
|
||||
|
||||
// Set the counter as a rate. It will be presented divided
|
||||
// by the duration of the benchmark.
|
||||
// Meaning: per one second, how many 'foo's are processed?
|
||||
state.counters["FooRate"] = Counter(numFoos, benchmark::Counter::kIsRate);
|
||||
|
||||
// Set the counter as a rate. It will be presented divided
|
||||
// by the duration of the benchmark, and the result inverted.
|
||||
// Meaning: how many seconds it takes to process one 'foo'?
|
||||
state.counters["FooInvRate"] = Counter(numFoos, benchmark::Counter::kIsRate | benchmark::Counter::kInvert);
|
||||
|
||||
// Set the counter as a thread-average quantity. It will
|
||||
// be presented divided by the number of threads.
|
||||
state.counters["FooAvg"] = Counter(numFoos, benchmark::Counter::kAvgThreads);
|
||||
|
@ -368,7 +368,10 @@ class Counter {
|
||||
// It will be presented divided by the number of iterations.
|
||||
kAvgIterations = 1U << 3U,
|
||||
// Mark the counter as a iteration-average rate. See above.
|
||||
kAvgIterationsRate = kIsRate | kAvgIterations
|
||||
kAvgIterationsRate = kIsRate | kAvgIterations,
|
||||
|
||||
// In the end, invert the result. This is always done last!
|
||||
kInvert = 1U << 31U
|
||||
};
|
||||
|
||||
enum OneK {
|
||||
|
@ -12,21 +12,21 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "complexity.h"
|
||||
#include "counter.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "check.h"
|
||||
#include "colorprint.h"
|
||||
#include "commandlineflags.h"
|
||||
#include "complexity.h"
|
||||
#include "counter.h"
|
||||
#include "internal_macros.h"
|
||||
#include "string_util.h"
|
||||
#include "timers.h"
|
||||
@ -156,16 +156,14 @@ void ConsoleReporter::PrintRunData(const Run& result) {
|
||||
const std::size_t cNameLen = std::max(std::string::size_type(10),
|
||||
c.first.length());
|
||||
auto const& s = HumanReadableNumber(c.second.value, c.second.oneK);
|
||||
const char* unit = "";
|
||||
if (c.second.flags & Counter::kIsRate)
|
||||
unit = (c.second.flags & Counter::kInvert) ? "s" : "/s";
|
||||
if (output_options_ & OO_Tabular) {
|
||||
if (c.second.flags & Counter::kIsRate) {
|
||||
printer(Out, COLOR_DEFAULT, " %*s/s", cNameLen - 2, s.c_str());
|
||||
} else {
|
||||
printer(Out, COLOR_DEFAULT, " %*s", cNameLen, s.c_str());
|
||||
}
|
||||
} else {
|
||||
const char* unit = (c.second.flags & Counter::kIsRate) ? "/s" : "";
|
||||
printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(),
|
||||
printer(Out, COLOR_DEFAULT, " %*s%s", cNameLen - strlen(unit), s.c_str(),
|
||||
unit);
|
||||
} else {
|
||||
printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(), unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,10 @@ double Finish(Counter const& c, IterationCount iterations, double cpu_time,
|
||||
if (c.flags & Counter::kAvgIterations) {
|
||||
v /= iterations;
|
||||
}
|
||||
|
||||
if (c.flags & Counter::kInvert) { // Invert is *always* last.
|
||||
v = 1.0 / v;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -148,6 +148,89 @@ void CheckRate(Results const& e) {
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_Rate", &CheckRate);
|
||||
|
||||
// ========================================================================= //
|
||||
// ----------------------- Inverted Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_Invert(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] = bm::Counter{0.0001, bm::Counter::kInvert};
|
||||
state.counters["bar"] = bm::Counter{10000, bm::Counter::kInvert};
|
||||
}
|
||||
BENCHMARK(BM_Invert);
|
||||
ADD_CASES(TC_ConsoleOut,
|
||||
{{"^BM_Invert %console_report bar=%hrfloatu foo=%hrfloatk$"}});
|
||||
ADD_CASES(TC_JSONOut, {{"\"name\": \"BM_Invert\",$"},
|
||||
{"\"run_name\": \"BM_Invert\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 0,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut, {{"^\"BM_Invert\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckInvert(Results const& e) {
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 10000, 0.0001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 0.0001, 0.0001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Invert", &CheckInvert);
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- InvertedRate Counters Output
|
||||
// -------------------------- //
|
||||
// ========================================================================= //
|
||||
|
||||
void BM_Counters_InvertedRate(benchmark::State& state) {
|
||||
for (auto _ : state) {
|
||||
// This test requires a non-zero CPU time to avoid divide-by-zero
|
||||
benchmark::DoNotOptimize(state.iterations());
|
||||
}
|
||||
namespace bm = benchmark;
|
||||
state.counters["foo"] =
|
||||
bm::Counter{1, bm::Counter::kIsRate | bm::Counter::kInvert};
|
||||
state.counters["bar"] =
|
||||
bm::Counter{8192, bm::Counter::kIsRate | bm::Counter::kInvert};
|
||||
}
|
||||
BENCHMARK(BM_Counters_InvertedRate);
|
||||
ADD_CASES(TC_ConsoleOut, {{"^BM_Counters_InvertedRate %console_report "
|
||||
"bar=%hrfloats foo=%hrfloats$"}});
|
||||
ADD_CASES(TC_JSONOut,
|
||||
{{"\"name\": \"BM_Counters_InvertedRate\",$"},
|
||||
{"\"run_name\": \"BM_Counters_InvertedRate\",$", MR_Next},
|
||||
{"\"run_type\": \"iteration\",$", MR_Next},
|
||||
{"\"repetitions\": 0,$", MR_Next},
|
||||
{"\"repetition_index\": 0,$", MR_Next},
|
||||
{"\"threads\": 1,$", MR_Next},
|
||||
{"\"iterations\": %int,$", MR_Next},
|
||||
{"\"real_time\": %float,$", MR_Next},
|
||||
{"\"cpu_time\": %float,$", MR_Next},
|
||||
{"\"time_unit\": \"ns\",$", MR_Next},
|
||||
{"\"bar\": %float,$", MR_Next},
|
||||
{"\"foo\": %float$", MR_Next},
|
||||
{"}", MR_Next}});
|
||||
ADD_CASES(TC_CSVOut,
|
||||
{{"^\"BM_Counters_InvertedRate\",%csv_report,%float,%float$"}});
|
||||
// VS2013 does not allow this function to be passed as a lambda argument
|
||||
// to CHECK_BENCHMARK_RESULTS()
|
||||
void CheckInvertedRate(Results const& e) {
|
||||
double t = e.DurationCPUTime(); // this (and not real time) is the time used
|
||||
// check that the values are within 0.1% of the expected values
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, t, 0.001);
|
||||
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, t / 8192.0, 0.001);
|
||||
}
|
||||
CHECK_BENCHMARK_RESULTS("BM_Counters_InvertedRate", &CheckInvertedRate);
|
||||
|
||||
// ========================================================================= //
|
||||
// ------------------------- Thread Counters Output ------------------------ //
|
||||
// ========================================================================= //
|
||||
|
Loading…
Reference in New Issue
Block a user