diff --git a/docs/user_guide.md b/docs/user_guide.md
index 3fed9261d7..30f3608dea 100644
--- a/docs/user_guide.md
+++ b/docs/user_guide.md
@@ -850,6 +850,11 @@ BENCHMARK(BM_StringCompare)->RangeMultiplier(2)
->Range(1<<10, 1<<18)->Complexity([](benchmark::IterationCount n)->double{return n; });
```
+The `BigO` row reports the coefficient in the same time unit as the rest of the
+family, so a family declared with `->Unit(benchmark::kMicrosecond)` reports its
+coefficient in microseconds. The `RMS` row is a normalized quantity and is
+reported as a percentage, independent of the time unit.
+
## Custom Benchmark Name
diff --git a/src/complexity.cc b/src/complexity.cc
index 8fa3f073af..c431a3f035 100644
--- a/src/complexity.cc
+++ b/src/complexity.cc
@@ -229,6 +229,7 @@ std::vector ComputeBigO(
big_o.cpu_accumulated_time = result_cpu.coef;
big_o.report_big_o = true;
big_o.complexity = result_cpu.complexity;
+ big_o.time_unit = reports[0].time_unit;
// All the time results are reported after being multiplied by the
// time unit multiplier. But since RMS is a relative quantity it
diff --git a/test/complexity_test.cc b/test/complexity_test.cc
index 64a7e72a6d..7551abcb39 100644
--- a/test/complexity_test.cc
+++ b/test/complexity_test.cc
@@ -20,13 +20,15 @@ namespace {
int AddComplexityTest(const std::string& test_name,
const std::string& big_o_test_name,
const std::string& rms_test_name,
- const std::string& big_o, int family_index) {
+ const std::string& big_o, int family_index,
+ const std::string& time_unit) {
SetSubstitutions({{"%name", test_name},
{"%bigo_name", big_o_test_name},
{"%rms_name", rms_test_name},
{"%bigo_str", "[ ]* %float " + big_o},
{"%bigo", big_o},
- {"%rms", "[ ]*[0-9]+ %"}});
+ {"%rms", "[ ]*[0-9]+ %"},
+ {"%unit", time_unit}});
AddCases(
TC_ConsoleOut,
{{"^%bigo_name %bigo_str %bigo_str[ ]*$"},
@@ -46,7 +48,7 @@ int AddComplexityTest(const std::string& test_name,
{"\"cpu_coefficient\": %float,$", MR_Next},
{"\"real_coefficient\": %float,$", MR_Next},
{"\"big_o\": \"%bigo\",$", MR_Next},
- {"\"time_unit\": \"ns\"$", MR_Next},
+ {"\"time_unit\": \"%unit\"$", MR_Next},
{"}", MR_Next},
{"\"name\": \"%rms_name\",$"},
{"\"family_index\": " + std::to_string(family_index) + ",$", MR_Next},
@@ -104,15 +106,15 @@ constexpr char lambda_big_o_1[] = "f\\(N\\)";
// Add enum tests
ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
- enum_auto_big_o_1, /*family_index=*/0);
+ enum_auto_big_o_1, /*family_index=*/0, "ns");
// Add auto tests
ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
- enum_auto_big_o_1, /*family_index=*/1);
+ enum_auto_big_o_1, /*family_index=*/1, "ns");
// Add lambda tests
ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name,
- lambda_big_o_1, /*family_index=*/2);
+ lambda_big_o_1, /*family_index=*/2, "ns");
// ========================================================================= //
// --------------------------- Testing BigO O(N) --------------------------- //
@@ -161,15 +163,15 @@ constexpr char lambda_big_o_n[] = "f\\(N\\)";
// Add enum tests
ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name,
- enum_auto_big_o_n, /*family_index=*/3);
+ enum_auto_big_o_n, /*family_index=*/3, "ns");
// Add auto tests
ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name,
- enum_auto_big_o_n, /*family_index=*/4);
+ enum_auto_big_o_n, /*family_index=*/4, "ns");
// Add lambda tests
ADD_COMPLEXITY_CASES(n_test_name, big_o_n_test_name, rms_o_n_test_name,
- lambda_big_o_n, /*family_index=*/5);
+ lambda_big_o_n, /*family_index=*/5, "ns");
// ========================================================================= //
// ------------------------- Testing BigO O(NlgN) ------------------------- //
@@ -222,17 +224,17 @@ constexpr char lambda_big_o_n_lg_n[] = "f\\(N\\)";
// Add enum tests
ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name,
rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n,
- /*family_index=*/6);
+ /*family_index=*/6, "ns");
// NOTE: auto big-o is wron.g
ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name,
rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n,
- /*family_index=*/7);
+ /*family_index=*/7, "ns");
//// Add lambda tests
ADD_COMPLEXITY_CASES(n_lg_n_test_name, big_o_n_lg_n_test_name,
rms_o_n_lg_n_test_name, lambda_big_o_n_lg_n,
- /*family_index=*/8);
+ /*family_index=*/8, "ns");
// ========================================================================= //
// -------- Testing formatting of Complexity with captured args ------------ //
@@ -265,7 +267,34 @@ const std::string complexity_capture_name =
ADD_COMPLEXITY_CASES(complexity_capture_name, complexity_capture_name + "_BigO",
complexity_capture_name + "_RMS", "N",
- /*family_index=*/9);
+ /*family_index=*/9, "ns");
+// ========================================================================= //
+// ------------------- Testing BigO with a declared unit ------------------- //
+// ========================================================================= //
+
+void BM_Complexity_O_N_ms(benchmark::State& state) {
+ for (auto _ : state) {
+ // 1us per iteration per entry, half the sizes 50% slower so the RMS is
+ // well above zero, reported in milliseconds
+ const double skew = (state.range(0) & (1 << 11)) ? 1.5 : 1.0;
+ state.SetIterationTime(static_cast(state.range(0)) * 1e-6 * skew);
+ }
+ state.SetComplexityN(state.range(0));
+}
+BENCHMARK(BM_Complexity_O_N_ms)
+ ->RangeMultiplier(2)
+ ->Range(1 << 10, 1 << 16)
+ ->UseManualTime()
+ ->Unit(benchmark::kMillisecond)
+ ->Complexity(benchmark::oN);
+
+constexpr char n_ms_test_name[] = "BM_Complexity_O_N_ms/manual_time";
+constexpr char big_o_n_ms_test_name[] = "BM_Complexity_O_N_ms/manual_time_BigO";
+constexpr char rms_o_n_ms_test_name[] = "BM_Complexity_O_N_ms/manual_time_RMS";
+
+ADD_COMPLEXITY_CASES(n_ms_test_name, big_o_n_ms_test_name, rms_o_n_ms_test_name,
+ enum_auto_big_o_n, /*family_index=*/10, "ms");
+
} // end namespace
// ========================================================================= //