Skip to content

Commit 3e7dac6

Browse files
FRosnerLebedevRI
andauthored
#2080: Fix rate and thread rate counter aggregates (#2081)
* Update counter.cc * User counters: normalize time by thread count Fixes #2080 * docs --------- Co-authored-by: Roman Lebedev <[email protected]>
1 parent 63f16af commit 3e7dac6

File tree

5 files changed

+29
-15
lines changed

5 files changed

+29
-15
lines changed

docs/user_guide.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -749,10 +749,6 @@ and `Counter` values. The latter is a `double`-like class, via an implicit
749749
conversion to `double&`. Thus you can use all of the standard arithmetic
750750
assignment operators (`=,+=,-=,*=,/=`) to change the value of each counter.
751751

752-
In multithreaded benchmarks, each counter is set on the calling thread only.
753-
When the benchmark finishes, the counters from each thread will be summed;
754-
the resulting sum is the value which will be shown for the benchmark.
755-
756752
The `Counter` constructor accepts three parameters: the value as a `double`
757753
; a bit flag which allows you to show counters as rates, and/or as per-thread
758754
iteration, and/or as per-thread averages, and/or iteration invariants,
@@ -797,6 +793,10 @@ You can use `insert()` with `std::initializer_list`:
797793
```
798794
<!-- {% endraw %} -->
799795
796+
In multithreaded benchmarks, each counter is set on the calling thread only.
797+
When the benchmark finishes, the counters from each thread will be summed.
798+
Counters that are configured with `kIsRate`, will report the average rate across all threads, while `kAvgThreadsRate` counters will report the average rate per thread.
799+
800800
### Counter Reporting
801801
802802
When using the console reporter, by default, user counters are printed at

src/benchmark_runner.cc

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,12 @@ BenchmarkReporter::Run CreateRunReport(
123123
: 0;
124124
}
125125

126-
internal::Finish(&report.counters, results.iterations, seconds,
126+
// The CPU time is the total time taken by all thread. If we used that as
127+
// the denominator, we'd be calculating the rate per thread here. This is
128+
// why we have to divide the total cpu_time by the number of threads for
129+
// global counters to get a global rate.
130+
const double thread_seconds = seconds / b.threads();
131+
internal::Finish(&report.counters, results.iterations, thread_seconds,
127132
b.threads());
128133
}
129134
return report;

test/user_counters_tabular_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_CounterRates_Tabular/threads:%int\",%csv_report,"
418418
// VS2013 does not allow this function to be passed as a lambda argument
419419
// to CHECK_BENCHMARK_RESULTS()
420420
void CheckTabularRate(Results const& e) {
421-
double t = e.DurationCPUTime();
421+
double t = e.DurationCPUTime() / e.NumThreads();
422422
CHECK_FLOAT_COUNTER_VALUE(e, "Foo", EQ, 1. / t, 0.001);
423423
CHECK_FLOAT_COUNTER_VALUE(e, "Bar", EQ, 2. / t, 0.001);
424424
CHECK_FLOAT_COUNTER_VALUE(e, "Baz", EQ, 4. / t, 0.001);

test/user_counters_test.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,8 +381,10 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/"
381381
// VS2013 does not allow this function to be passed as a lambda argument
382382
// to CHECK_BENCHMARK_RESULTS()
383383
void CheckAvgThreadsRate(Results const& e) {
384-
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / e.DurationCPUTime(), 0.001);
385-
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / e.DurationCPUTime(), 0.001);
384+
// this (and not real time) is the time used
385+
double t = e.DurationCPUTime() / e.NumThreads();
386+
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / t, 0.001);
387+
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001);
386388
}
387389
CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int",
388390
&CheckAvgThreadsRate);

test/user_counters_threads_test.cc

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_WithBytesAndItemsPSec/threads:%int\","
107107
// VS2013 does not allow this function to be passed as a lambda argument
108108
// to CHECK_BENCHMARK_RESULTS()
109109
void CheckBytesAndItemsPSec(Results const& e) {
110-
double t = e.DurationCPUTime(); // this (and not real time) is the time used
110+
// this (and not real time) is the time used
111+
double t = e.DurationCPUTime() / e.NumThreads();
111112
CHECK_COUNTER_VALUE(e, int, "foo", EQ, 1 * e.NumThreads());
112113
// check that the values are within 0.1% of the expected values
113114
CHECK_FLOAT_RESULT_VALUE(e, "bytes_per_second", EQ,
@@ -158,7 +159,8 @@ ADD_CASES(TC_CSVOut,
158159
// VS2013 does not allow this function to be passed as a lambda argument
159160
// to CHECK_BENCHMARK_RESULTS()
160161
void CheckRate(Results const& e) {
161-
double t = e.DurationCPUTime(); // this (and not real time) is the time used
162+
// this (and not real time) is the time used
163+
double t = e.DurationCPUTime() / e.NumThreads();
162164
// check that the values are within 0.1% of the expected values
163165
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, (1. * e.NumThreads()) / t, 0.001);
164166
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, (2. * e.NumThreads()) / t, 0.001);
@@ -258,7 +260,8 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_InvertedRate/"
258260
// VS2013 does not allow this function to be passed as a lambda argument
259261
// to CHECK_BENCHMARK_RESULTS()
260262
void CheckInvertedRate(Results const& e) {
261-
double t = e.DurationCPUTime(); // this (and not real time) is the time used
263+
// this (and not real time) is the time used
264+
double t = e.DurationCPUTime() / e.NumThreads();
262265
// check that the values are within 0.1% of the expected values
263266
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, t / (e.NumThreads()), 0.001);
264267
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, t / (8192.0 * e.NumThreads()), 0.001);
@@ -394,8 +397,10 @@ ADD_CASES(TC_CSVOut, {{"^\"BM_Counters_AvgThreadsRate/"
394397
// VS2013 does not allow this function to be passed as a lambda argument
395398
// to CHECK_BENCHMARK_RESULTS()
396399
void CheckAvgThreadsRate(Results const& e) {
397-
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / e.DurationCPUTime(), 0.001);
398-
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / e.DurationCPUTime(), 0.001);
400+
// this (and not real time) is the time used
401+
double t = e.DurationCPUTime() / e.NumThreads();
402+
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. / t, 0.001);
403+
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. / t, 0.001);
399404
}
400405
CHECK_BENCHMARK_RESULTS("BM_Counters_AvgThreadsRate/threads:%int",
401406
&CheckAvgThreadsRate);
@@ -496,7 +501,8 @@ ADD_CASES(
496501
// to CHECK_BENCHMARK_RESULTS()
497502
void CheckIsIterationInvariantRate(Results const& e) {
498503
double its = e.NumIterations();
499-
double t = e.DurationCPUTime(); // this (and not real time) is the time used
504+
// this (and not real time) is the time used
505+
double t = e.DurationCPUTime() / e.NumThreads();
500506
// check that the values are within 0.1% of the expected values
501507
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, its * 1. * e.NumThreads() / t, 0.001);
502508
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, its * 2. * e.NumThreads() / t, 0.001);
@@ -596,7 +602,8 @@ ADD_CASES(TC_CSVOut,
596602
// to CHECK_BENCHMARK_RESULTS()
597603
void CheckAvgIterationsRate(Results const& e) {
598604
double its = e.NumIterations();
599-
double t = e.DurationCPUTime(); // this (and not real time) is the time used
605+
// this (and not real time) is the time used
606+
double t = e.DurationCPUTime() / e.NumThreads();
600607
// check that the values are within 0.1% of the expected values
601608
CHECK_FLOAT_COUNTER_VALUE(e, "foo", EQ, 1. * e.NumThreads() / its / t, 0.001);
602609
CHECK_FLOAT_COUNTER_VALUE(e, "bar", EQ, 2. * e.NumThreads() / its / t, 0.001);

0 commit comments

Comments
 (0)