Skip to content

Commit 47ce92d

Browse files
committed
Add --benchmark_human_readable flag
Allows used to add a command line flag called `--benchmark_human_readable`. By adding this flag the arguments passed to benchmarks are formatted in a human friendly format. This means that numbers that are the power of 2 are formatted as `2^x` (e.g., 64 will be `2^6`). For numbers that are the power of 10 a different formatting style is used. Numbers 0-999 no formatting is used. For numbers 1000-999999 the format `k` is used (e.g., `32000` -> `32k`). This also works for millions, billions, trillions, ... For numbers greater than septillions no special formatting is used. The design is rather simple allowing to by easily extendable. Closes: google#1006
1 parent 604f6fd commit 47ce92d

13 files changed

+466
-5
lines changed

AUTHORS

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ Colin Braley <[email protected]>
2020
Daniel Harvey <[email protected]>
2121
David Coeurjolly <[email protected]>
2222
Deniz Evrenci <[email protected]>
23-
Dirac Research
23+
Dirac Research
24+
Diego Krupitza <[email protected]>
2425
Dominik Czarnota <[email protected]>
2526
Dominik Korman <[email protected]>
2627
Donald Aingworth <[email protected]>

CONTRIBUTORS

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Cyrille Faucheux <[email protected]>
3838
Daniel Harvey <[email protected]>
3939
David Coeurjolly <[email protected]>
4040
Deniz Evrenci <[email protected]>
41+
Diego Krupitza <[email protected]>
4142
4243
Dominik Czarnota <[email protected]>
4344
Dominik Korman <[email protected]>

docs/user_guide.md

+51
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,57 @@ BM_memcpy/32 12 ns 12 ns 54687500
185185
BM_memcpy/32k 1834 ns 1837 ns 357143
186186
```
187187

188+
<a name="running-with-human-readable-format" />
189+
190+
## Human Readable Format
191+
192+
The `--benchmark_human_readable={true|false}` option can be used to display
193+
args in a more human friendly format. Meaning numbers that are power of 2
194+
will be formatted as `2^x`. Furthermore, for numbers that are the power of
195+
10 special formatting abbreviations are used. For instance, `1000` will be
196+
formatted to `1k`, `32000` to `32k`, `1000000` to `1m` and so on.
197+
198+
By default `benchmark_human_readable` is disabled.
199+
200+
201+
```bash
202+
$ ./run_benchmarks.x
203+
Run on (1 X 2300 MHz CPU )
204+
2016-06-25 19:34:24
205+
BM_base_two_args/1 2.22 ns 2.22 ns 6280843
206+
BM_base_two_args/2 2.20 ns 2.20 ns 6278027
207+
BM_base_two_args/64 2.14 ns 2.14 ns 6263982
208+
BM_base_two_args/128 2.22 ns 2.22 ns 6286484
209+
BM_base_ten_args/1 2.25 ns 2.25 ns 6349206
210+
BM_base_ten_args/10 2.18 ns 2.18 ns 6241641
211+
BM_base_ten_args/100 2.24 ns 2.24 ns 6167401
212+
BM_base_ten_args/1000 2.25 ns 2.25 ns 6137659
213+
BM_base_ten_args/10000 2.24 ns 2.24 ns 6068487
214+
BM_base_ten_args/32000 2.26 ns 2.26 ns 6063231
215+
BM_base_ten_args/100000 2.25 ns 2.25 ns 6105539
216+
BM_base_ten_args/1000000 2.21 ns 2.21 ns 6766554
217+
BM_base_ten_args/1000000000 2.23 ns 2.23 ns 6233304
218+
```
219+
220+
```bash
221+
$ ./run_benchmarks.x --benchmark_human_readable
222+
Run on (1 X 2300 MHz CPU )
223+
2016-06-25 19:34:24
224+
BM_base_two_args/1 2.18 ns 2.18 ns 6222222
225+
BM_base_two_args/2^1 2.24 ns 2.24 ns 6208426
226+
BM_base_two_args/2^6 2.24 ns 2.24 ns 6159261
227+
BM_base_two_args/2^7 2.25 ns 2.25 ns 6337709
228+
BM_base_ten_args/1 2.27 ns 2.27 ns 6071119
229+
BM_base_ten_args/10 2.32 ns 2.32 ns 6278027
230+
BM_base_ten_args/100 2.28 ns 2.27 ns 6029285
231+
BM_base_ten_args/1k 2.27 ns 2.26 ns 5845511
232+
BM_base_ten_args/10k 2.27 ns 2.26 ns 6252791
233+
BM_base_ten_args/32k 2.27 ns 2.26 ns 6208426
234+
BM_base_ten_args/100k 2.27 ns 2.26 ns 6129597
235+
BM_base_ten_args/1m 2.28 ns 2.28 ns 5988024
236+
BM_base_ten_args/1bn 2.25 ns 2.25 ns 6211180
237+
```
238+
188239
## Disabling Benchmarks
189240

190241
It is possible to temporarily disable benchmarks by renaming the benchmark

src/benchmark.cc

+7-1
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ BM_DEFINE_string(benchmark_time_unit, "");
144144
// The level of verbose logging to output
145145
BM_DEFINE_int32(v, 0);
146146

147+
// defines whether to use human-readable format or not
148+
BM_DEFINE_bool(benchmark_human_readable, false);
149+
147150
namespace internal {
148151

149152
std::map<std::string, std::string>* global_context = nullptr;
@@ -691,7 +694,9 @@ void ParseCommandLineFlags(int* argc, char** argv) {
691694
&FLAGS_benchmark_context) ||
692695
ParseStringFlag(argv[i], "benchmark_time_unit",
693696
&FLAGS_benchmark_time_unit) ||
694-
ParseInt32Flag(argv[i], "v", &FLAGS_v)) {
697+
ParseInt32Flag(argv[i], "v", &FLAGS_v) ||
698+
ParseBoolFlag(argv[i], "benchmark_human_readable",
699+
&FLAGS_benchmark_human_readable)) {
695700
for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1];
696701

697702
--(*argc);
@@ -743,6 +748,7 @@ void PrintDefaultHelp() {
743748
#endif
744749
" [--benchmark_context=<key>=<value>,...]\n"
745750
" [--benchmark_time_unit={ns|us|ms|s}]\n"
751+
" [--benchmark_human_readable={true|false}]\n"
746752
" [--v=<verbosity>]\n");
747753
}
748754

src/benchmark_api_internal.cc

+19-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include "string_util.h"
66

77
namespace benchmark {
8+
9+
BM_DECLARE_bool(benchmark_human_readable);
10+
811
namespace internal {
912

1013
BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx,
@@ -43,7 +46,13 @@ BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx,
4346
}
4447
}
4548

46-
name_.args += StrFormat("%" PRId64, arg);
49+
// formatting args either in default mode or in human-readable
50+
if (FLAGS_benchmark_human_readable) {
51+
name_.args += FormatHumanReadable(arg);
52+
} else {
53+
name_.args += StrFormat("%" PRId64, arg);
54+
}
55+
4756
++arg_i;
4857
}
4958

@@ -114,5 +123,14 @@ void BenchmarkInstance::Teardown() const {
114123
teardown_(st);
115124
}
116125
}
126+
127+
/**
128+
* Check whether the given value is a power of two or not.
129+
* @param val the value to check
130+
*/
131+
bool IsPowerOfTwo(const int64_t& val) {
132+
return (val & (val - 1)) == 0 && (val > 1);
133+
}
134+
117135
} // namespace internal
118136
} // namespace benchmark

src/benchmark_api_internal.h

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef BENCHMARK_API_INTERNAL_H
22
#define BENCHMARK_API_INTERNAL_H
33

4+
#include <array>
5+
#include <cinttypes>
46
#include <cmath>
57
#include <iosfwd>
68
#include <limits>
@@ -10,6 +12,7 @@
1012

1113
#include "benchmark/benchmark.h"
1214
#include "commandlineflags.h"
15+
#include "string_util.h"
1316

1417
namespace benchmark {
1518
namespace internal {

src/string_util.cc

+41-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "string_util.h"
22

33
#include <array>
4+
#include <cinttypes>
45
#ifdef BENCHMARK_STL_ANDROID_GNUSTL
56
#include <cerrno>
67
#endif
@@ -15,6 +16,11 @@
1516
namespace benchmark {
1617
namespace {
1718

19+
// Thousands, Millions, Billions, Trillions, Quadrillions, Quintillions,
20+
// Sextillions, Septillions.
21+
const std::array<std::string, 8> base10Units = {"k", "M", "B", "T",
22+
"Q", "Qi", "Sx", "Sp"};
23+
1824
// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta.
1925
const char kBigSIUnits[] = "kMGTPEZY";
2026
// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
@@ -32,7 +38,8 @@ static const int64_t kUnitsSize = arraysize(kBigSIUnits);
3238

3339
void ToExponentAndMantissa(double val, double thresh, int precision,
3440
double one_k, std::string* mantissa,
35-
int64_t* exponent) {
41+
int64_t* exponent,
42+
bool inclusiveBigThreshhold = false) {
3643
std::stringstream mantissa_stream;
3744

3845
if (val < 0) {
@@ -44,7 +51,8 @@ void ToExponentAndMantissa(double val, double thresh, int precision,
4451
// in 'precision' digits.
4552
const double adjusted_threshold =
4653
std::max(thresh, 1.0 / std::pow(10.0, precision));
47-
const double big_threshold = adjusted_threshold * one_k;
54+
const double big_threshold =
55+
(adjusted_threshold * one_k) - inclusiveBigThreshhold;
4856
const double small_threshold = adjusted_threshold;
4957
// Values in ]simple_threshold,small_threshold[ will be printed as-is
5058
const double simple_threshold = 0.01;
@@ -262,4 +270,35 @@ double stod(const std::string& str, size_t* pos) {
262270
}
263271
#endif
264272

273+
std::string ExponentToBase10Prefix(int64_t exponent) {
274+
if (exponent == 0) return "";
275+
276+
const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1);
277+
if (index >= kUnitsSize) return "";
278+
279+
return base10Units[index];
280+
}
281+
282+
std::string Base10HumanReadableFormat(const int64_t& arg) {
283+
std::string mantissa;
284+
int64_t exponent;
285+
ToExponentAndMantissa(arg, 1, 1, 1000, &mantissa, &exponent, true);
286+
return mantissa + ExponentToBase10Prefix(exponent);
287+
}
288+
289+
bool IsPowerOfTwo(const int64_t& val) {
290+
return (val & (val - 1)) == 0 && (val > 1);
291+
}
292+
293+
std::string Base2HumanReadableFormat(const int64_t& arg) {
294+
return StrFormat("2^%.0f", std::log2(arg));
295+
}
296+
297+
std::string FormatHumanReadable(const int64_t& arg) {
298+
if (IsPowerOfTwo(arg)) {
299+
return Base2HumanReadableFormat(arg);
300+
}
301+
return Base10HumanReadableFormat(arg);
302+
}
303+
265304
} // end namespace benchmark

src/string_util.h

+29
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,35 @@ using std::stoul; // NOLINT(misc-unused-using-decls)
6565
#endif
6666
// NOLINTEND
6767

68+
/**
69+
* Check whether the given value is a power of two or not.
70+
* @param val the value to check
71+
*/
72+
bool IsPowerOfTwo(const int64_t& val);
73+
74+
/**
75+
* Gets the human readable format for a given base10 value.
76+
* In other words converts 1_000 to 1k, 40_000_000 to 40m etc
77+
* @param arg the positive value to convert
78+
* @return human readable formatted string
79+
*/
80+
std::string Base10HumanReadableFormat(const int64_t& arg);
81+
82+
/**
83+
* Gets the human readable format for a given base2 value.
84+
* In other words converts 64 to 2^6, 1024 to 2^10 etc
85+
* @param arg the positive value to convert
86+
* @return human readable formatted string
87+
*/
88+
std::string Base2HumanReadableFormat(const int64_t& arg);
89+
90+
/**
91+
* Formats an argument into a human readable format.
92+
* @param arg the argument to format
93+
* @return the argument formatted as human readable
94+
*/
95+
std::string FormatHumanReadable(const int64_t& arg);
96+
6897
} // end namespace benchmark
6998

7099
#endif // BENCHMARK_STRING_UTIL_H_

test/BUILD

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ PER_SRC_TEST_ARGS = {
3232
"repetitions_test.cc": [" --benchmark_repetitions=3"],
3333
"spec_arg_test.cc": ["--benchmark_filter=BM_NotChosen"],
3434
"spec_arg_verbosity_test.cc": ["--v=42"],
35+
"human_readable_formatting_test.cc": ["--benchmark_human_readable"]
3536
}
3637

3738
cc_library(

test/CMakeLists.txt

+7
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test
177177
compile_output_test(memory_manager_test)
178178
add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01s)
179179

180+
compile_benchmark_test(human_readable_formatting_test)
181+
add_test(NAME human_readable_formatting_test COMMAND human_readable_formatting_test --benchmark_min_time=0.01s --benchmark_human_readable)
182+
183+
compile_benchmark_test(non_human_readable_formatting_test)
184+
add_test(NAME non_human_readable_formatting_test COMMAND non_human_readable_formatting_test --benchmark_min_time=0.01s --benchmark_human_readable=false)
185+
180186
# MSVC does not allow to set the language standard to C++98/03.
181187
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
182188
compile_benchmark_test(cxx03_test)
@@ -237,6 +243,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS)
237243
add_gtest(perf_counters_gtest)
238244
add_gtest(time_unit_gtest)
239245
add_gtest(min_time_parse_gtest)
246+
add_gtest(human_readable_gtest)
240247
endif(BENCHMARK_ENABLE_GTEST_TESTS)
241248

242249
###############################################################################

0 commit comments

Comments
 (0)