Skip to content

Commit

Permalink
Add --benchmark_human_readable flag
Browse files Browse the repository at this point in the history
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
  • Loading branch information
DiegoKrupitza committed Jun 19, 2023
1 parent 604f6fd commit 47ce92d
Show file tree
Hide file tree
Showing 13 changed files with 466 additions and 5 deletions.
3 changes: 2 additions & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ Colin Braley <[email protected]>
Daniel Harvey <[email protected]>
David Coeurjolly <[email protected]>
Deniz Evrenci <[email protected]>
Dirac Research
Dirac Research
Diego Krupitza <[email protected]>
Dominik Czarnota <[email protected]>
Dominik Korman <[email protected]>
Donald Aingworth <[email protected]>
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Cyrille Faucheux <[email protected]>
Daniel Harvey <[email protected]>
David Coeurjolly <[email protected]>
Deniz Evrenci <[email protected]>
Diego Krupitza <[email protected]>
Dominic Hamon <[email protected]> <[email protected]>
Dominik Czarnota <[email protected]>
Dominik Korman <[email protected]>
Expand Down
51 changes: 51 additions & 0 deletions docs/user_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,57 @@ BM_memcpy/32 12 ns 12 ns 54687500
BM_memcpy/32k 1834 ns 1837 ns 357143
```

<a name="running-with-human-readable-format" />

## Human Readable Format

The `--benchmark_human_readable={true|false}` option can be used to display
args in a more human friendly format. Meaning numbers that are power of 2
will be formatted as `2^x`. Furthermore, for numbers that are the power of
10 special formatting abbreviations are used. For instance, `1000` will be
formatted to `1k`, `32000` to `32k`, `1000000` to `1m` and so on.

By default `benchmark_human_readable` is disabled.


```bash
$ ./run_benchmarks.x
Run on (1 X 2300 MHz CPU )
2016-06-25 19:34:24
BM_base_two_args/1 2.22 ns 2.22 ns 6280843
BM_base_two_args/2 2.20 ns 2.20 ns 6278027
BM_base_two_args/64 2.14 ns 2.14 ns 6263982
BM_base_two_args/128 2.22 ns 2.22 ns 6286484
BM_base_ten_args/1 2.25 ns 2.25 ns 6349206
BM_base_ten_args/10 2.18 ns 2.18 ns 6241641
BM_base_ten_args/100 2.24 ns 2.24 ns 6167401
BM_base_ten_args/1000 2.25 ns 2.25 ns 6137659
BM_base_ten_args/10000 2.24 ns 2.24 ns 6068487
BM_base_ten_args/32000 2.26 ns 2.26 ns 6063231
BM_base_ten_args/100000 2.25 ns 2.25 ns 6105539
BM_base_ten_args/1000000 2.21 ns 2.21 ns 6766554
BM_base_ten_args/1000000000 2.23 ns 2.23 ns 6233304
```

```bash
$ ./run_benchmarks.x --benchmark_human_readable
Run on (1 X 2300 MHz CPU )
2016-06-25 19:34:24
BM_base_two_args/1 2.18 ns 2.18 ns 6222222
BM_base_two_args/2^1 2.24 ns 2.24 ns 6208426
BM_base_two_args/2^6 2.24 ns 2.24 ns 6159261
BM_base_two_args/2^7 2.25 ns 2.25 ns 6337709
BM_base_ten_args/1 2.27 ns 2.27 ns 6071119
BM_base_ten_args/10 2.32 ns 2.32 ns 6278027
BM_base_ten_args/100 2.28 ns 2.27 ns 6029285
BM_base_ten_args/1k 2.27 ns 2.26 ns 5845511
BM_base_ten_args/10k 2.27 ns 2.26 ns 6252791
BM_base_ten_args/32k 2.27 ns 2.26 ns 6208426
BM_base_ten_args/100k 2.27 ns 2.26 ns 6129597
BM_base_ten_args/1m 2.28 ns 2.28 ns 5988024
BM_base_ten_args/1bn 2.25 ns 2.25 ns 6211180
```

## Disabling Benchmarks

It is possible to temporarily disable benchmarks by renaming the benchmark
Expand Down
8 changes: 7 additions & 1 deletion src/benchmark.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ BM_DEFINE_string(benchmark_time_unit, "");
// The level of verbose logging to output
BM_DEFINE_int32(v, 0);

// defines whether to use human-readable format or not
BM_DEFINE_bool(benchmark_human_readable, false);

namespace internal {

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

--(*argc);
Expand Down Expand Up @@ -743,6 +748,7 @@ void PrintDefaultHelp() {
#endif
" [--benchmark_context=<key>=<value>,...]\n"
" [--benchmark_time_unit={ns|us|ms|s}]\n"
" [--benchmark_human_readable={true|false}]\n"
" [--v=<verbosity>]\n");
}

Expand Down
20 changes: 19 additions & 1 deletion src/benchmark_api_internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
#include "string_util.h"

namespace benchmark {

BM_DECLARE_bool(benchmark_human_readable);

namespace internal {

BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx,
Expand Down Expand Up @@ -43,7 +46,13 @@ BenchmarkInstance::BenchmarkInstance(Benchmark* benchmark, int family_idx,
}
}

name_.args += StrFormat("%" PRId64, arg);
// formatting args either in default mode or in human-readable
if (FLAGS_benchmark_human_readable) {
name_.args += FormatHumanReadable(arg);
} else {
name_.args += StrFormat("%" PRId64, arg);
}

++arg_i;
}

Expand Down Expand Up @@ -114,5 +123,14 @@ void BenchmarkInstance::Teardown() const {
teardown_(st);
}
}

/**
* Check whether the given value is a power of two or not.
* @param val the value to check
*/
bool IsPowerOfTwo(const int64_t& val) {
return (val & (val - 1)) == 0 && (val > 1);
}

} // namespace internal
} // namespace benchmark
3 changes: 3 additions & 0 deletions src/benchmark_api_internal.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef BENCHMARK_API_INTERNAL_H
#define BENCHMARK_API_INTERNAL_H

#include <array>
#include <cinttypes>
#include <cmath>
#include <iosfwd>
#include <limits>
Expand All @@ -10,6 +12,7 @@

#include "benchmark/benchmark.h"
#include "commandlineflags.h"
#include "string_util.h"

namespace benchmark {
namespace internal {
Expand Down
43 changes: 41 additions & 2 deletions src/string_util.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "string_util.h"

#include <array>
#include <cinttypes>
#ifdef BENCHMARK_STL_ANDROID_GNUSTL
#include <cerrno>
#endif
Expand All @@ -15,6 +16,11 @@
namespace benchmark {
namespace {

// Thousands, Millions, Billions, Trillions, Quadrillions, Quintillions,
// Sextillions, Septillions.
const std::array<std::string, 8> base10Units = {"k", "M", "B", "T",
"Q", "Qi", "Sx", "Sp"};

// kilo, Mega, Giga, Tera, Peta, Exa, Zetta, Yotta.
const char kBigSIUnits[] = "kMGTPEZY";
// Kibi, Mebi, Gibi, Tebi, Pebi, Exbi, Zebi, Yobi.
Expand All @@ -32,7 +38,8 @@ static const int64_t kUnitsSize = arraysize(kBigSIUnits);

void ToExponentAndMantissa(double val, double thresh, int precision,
double one_k, std::string* mantissa,
int64_t* exponent) {
int64_t* exponent,
bool inclusiveBigThreshhold = false) {
std::stringstream mantissa_stream;

if (val < 0) {
Expand All @@ -44,7 +51,8 @@ void ToExponentAndMantissa(double val, double thresh, int precision,
// in 'precision' digits.
const double adjusted_threshold =
std::max(thresh, 1.0 / std::pow(10.0, precision));
const double big_threshold = adjusted_threshold * one_k;
const double big_threshold =
(adjusted_threshold * one_k) - inclusiveBigThreshhold;
const double small_threshold = adjusted_threshold;
// Values in ]simple_threshold,small_threshold[ will be printed as-is
const double simple_threshold = 0.01;
Expand Down Expand Up @@ -262,4 +270,35 @@ double stod(const std::string& str, size_t* pos) {
}
#endif

std::string ExponentToBase10Prefix(int64_t exponent) {
if (exponent == 0) return "";

const int64_t index = (exponent > 0 ? exponent - 1 : -exponent - 1);
if (index >= kUnitsSize) return "";

return base10Units[index];
}

std::string Base10HumanReadableFormat(const int64_t& arg) {
std::string mantissa;
int64_t exponent;
ToExponentAndMantissa(arg, 1, 1, 1000, &mantissa, &exponent, true);
return mantissa + ExponentToBase10Prefix(exponent);
}

bool IsPowerOfTwo(const int64_t& val) {
return (val & (val - 1)) == 0 && (val > 1);
}

std::string Base2HumanReadableFormat(const int64_t& arg) {
return StrFormat("2^%.0f", std::log2(arg));
}

std::string FormatHumanReadable(const int64_t& arg) {
if (IsPowerOfTwo(arg)) {
return Base2HumanReadableFormat(arg);
}
return Base10HumanReadableFormat(arg);
}

} // end namespace benchmark
29 changes: 29 additions & 0 deletions src/string_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,35 @@ using std::stoul; // NOLINT(misc-unused-using-decls)
#endif
// NOLINTEND

/**
* Check whether the given value is a power of two or not.
* @param val the value to check
*/
bool IsPowerOfTwo(const int64_t& val);

/**
* Gets the human readable format for a given base10 value.
* In other words converts 1_000 to 1k, 40_000_000 to 40m etc
* @param arg the positive value to convert
* @return human readable formatted string
*/
std::string Base10HumanReadableFormat(const int64_t& arg);

/**
* Gets the human readable format for a given base2 value.
* In other words converts 64 to 2^6, 1024 to 2^10 etc
* @param arg the positive value to convert
* @return human readable formatted string
*/
std::string Base2HumanReadableFormat(const int64_t& arg);

/**
* Formats an argument into a human readable format.
* @param arg the argument to format
* @return the argument formatted as human readable
*/
std::string FormatHumanReadable(const int64_t& arg);

} // end namespace benchmark

#endif // BENCHMARK_STRING_UTIL_H_
1 change: 1 addition & 0 deletions test/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ PER_SRC_TEST_ARGS = {
"repetitions_test.cc": [" --benchmark_repetitions=3"],
"spec_arg_test.cc": ["--benchmark_filter=BM_NotChosen"],
"spec_arg_verbosity_test.cc": ["--v=42"],
"human_readable_formatting_test.cc": ["--benchmark_human_readable"]
}

cc_library(
Expand Down
7 changes: 7 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,12 @@ add_test(NAME user_counters_thousands_test COMMAND user_counters_thousands_test
compile_output_test(memory_manager_test)
add_test(NAME memory_manager_test COMMAND memory_manager_test --benchmark_min_time=0.01s)

compile_benchmark_test(human_readable_formatting_test)
add_test(NAME human_readable_formatting_test COMMAND human_readable_formatting_test --benchmark_min_time=0.01s --benchmark_human_readable)

compile_benchmark_test(non_human_readable_formatting_test)
add_test(NAME non_human_readable_formatting_test COMMAND non_human_readable_formatting_test --benchmark_min_time=0.01s --benchmark_human_readable=false)

# MSVC does not allow to set the language standard to C++98/03.
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
compile_benchmark_test(cxx03_test)
Expand Down Expand Up @@ -237,6 +243,7 @@ if (BENCHMARK_ENABLE_GTEST_TESTS)
add_gtest(perf_counters_gtest)
add_gtest(time_unit_gtest)
add_gtest(min_time_parse_gtest)
add_gtest(human_readable_gtest)
endif(BENCHMARK_ENABLE_GTEST_TESTS)

###############################################################################
Expand Down
Loading

0 comments on commit 47ce92d

Please sign in to comment.