-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewrite complexity_test to use (hardcoded) manual time #1757
Changes from all commits
4aa8882
e703685
13e8159
8f64ed2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -186,8 +186,19 @@ std::vector<BenchmarkReporter::Run> ComputeBigO( | |
result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity_lambda); | ||
result_real = MinimalLeastSq(n, real_time, reports[0].complexity_lambda); | ||
} else { | ||
result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity); | ||
result_real = MinimalLeastSq(n, real_time, result_cpu.complexity); | ||
const BigO* InitialBigO = &reports[0].complexity; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this section needs some comments. maybe there's a way to simplify the logic? |
||
const bool use_real_time_for_initial_big_o = | ||
reports[0].use_real_time_for_initial_big_o; | ||
if (use_real_time_for_initial_big_o) { | ||
result_real = MinimalLeastSq(n, real_time, *InitialBigO); | ||
InitialBigO = &result_real.complexity; | ||
// The Big-O complexity for CPU time must have the same Big-O function! | ||
} | ||
result_cpu = MinimalLeastSq(n, cpu_time, *InitialBigO); | ||
InitialBigO = &result_cpu.complexity; | ||
if (!use_real_time_for_initial_big_o) { | ||
result_real = MinimalLeastSq(n, real_time, *InitialBigO); | ||
} | ||
} | ||
|
||
// Drop the 'args' when reporting complexity. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,35 +69,44 @@ int AddComplexityTest(const std::string &test_name, | |
|
||
void BM_Complexity_O1(benchmark::State &state) { | ||
for (auto _ : state) { | ||
for (int i = 0; i < 1024; ++i) { | ||
benchmark::DoNotOptimize(i); | ||
// This test requires a non-zero CPU time to avoid divide-by-zero | ||
benchmark::DoNotOptimize(state.iterations()); | ||
double tmp = state.iterations(); | ||
benchmark::DoNotOptimize(tmp); | ||
for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { | ||
benchmark::DoNotOptimize(state.iterations()); | ||
tmp *= state.iterations(); | ||
benchmark::DoNotOptimize(tmp); | ||
} | ||
|
||
// always 1ns per iteration | ||
state.SetIterationTime(42 * 1e-9); | ||
} | ||
state.SetComplexityN(state.range(0)); | ||
} | ||
BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(benchmark::o1); | ||
BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->Complexity(); | ||
BENCHMARK(BM_Complexity_O1) | ||
->Range(1, 1 << 18) | ||
->UseManualTime() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does this mean complexity only works for manual time? do we have any tests where we use complexity with real time? |
||
->Complexity(benchmark::o1); | ||
BENCHMARK(BM_Complexity_O1)->Range(1, 1 << 18)->UseManualTime()->Complexity(); | ||
BENCHMARK(BM_Complexity_O1) | ||
->Range(1, 1 << 18) | ||
->UseManualTime() | ||
->Complexity([](benchmark::IterationCount) { return 1.0; }); | ||
|
||
const char *one_test_name = "BM_Complexity_O1"; | ||
const char *big_o_1_test_name = "BM_Complexity_O1_BigO"; | ||
const char *rms_o_1_test_name = "BM_Complexity_O1_RMS"; | ||
const char *enum_big_o_1 = "\\([0-9]+\\)"; | ||
// FIXME: Tolerate both '(1)' and 'lgN' as output when the complexity is auto | ||
// deduced. | ||
// See https://github.com/google/benchmark/issues/272 | ||
const char *auto_big_o_1 = "(\\([0-9]+\\))|(lgN)|(N\\^2)"; | ||
const char *one_test_name = "BM_Complexity_O1/manual_time"; | ||
const char *big_o_1_test_name = "BM_Complexity_O1/manual_time_BigO"; | ||
const char *rms_o_1_test_name = "BM_Complexity_O1/manual_time_RMS"; | ||
const char *enum_auto_big_o_1 = "\\([0-9]+\\)"; | ||
const 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_big_o_1, /*family_index=*/0); | ||
enum_auto_big_o_1, /*family_index=*/0); | ||
|
||
// Add auto enum tests | ||
// Add auto tests | ||
ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, | ||
auto_big_o_1, /*family_index=*/1); | ||
enum_auto_big_o_1, /*family_index=*/1); | ||
|
||
// Add lambda tests | ||
ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, | ||
|
@@ -107,84 +116,102 @@ ADD_COMPLEXITY_CASES(one_test_name, big_o_1_test_name, rms_o_1_test_name, | |
// --------------------------- Testing BigO O(N) --------------------------- // | ||
// ========================================================================= // | ||
|
||
std::vector<int> ConstructRandomVector(int64_t size) { | ||
std::vector<int> v; | ||
v.reserve(static_cast<size_t>(size)); | ||
for (int i = 0; i < size; ++i) { | ||
v.push_back(static_cast<int>(std::rand() % size)); | ||
} | ||
return v; | ||
} | ||
|
||
void BM_Complexity_O_N(benchmark::State &state) { | ||
auto v = ConstructRandomVector(state.range(0)); | ||
// Test worst case scenario (item not in vector) | ||
const int64_t item_not_in_vector = state.range(0) * 2; | ||
for (auto _ : state) { | ||
auto it = std::find(v.begin(), v.end(), item_not_in_vector); | ||
benchmark::DoNotOptimize(it); | ||
// This test requires a non-zero CPU time to avoid divide-by-zero | ||
benchmark::DoNotOptimize(state.iterations()); | ||
double tmp = state.iterations(); | ||
benchmark::DoNotOptimize(tmp); | ||
for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { | ||
benchmark::DoNotOptimize(state.iterations()); | ||
tmp *= state.iterations(); | ||
benchmark::DoNotOptimize(tmp); | ||
} | ||
|
||
// 1ns per iteration per entry | ||
state.SetIterationTime(state.range(0) * 42 * 1e-9); | ||
} | ||
state.SetComplexityN(state.range(0)); | ||
} | ||
BENCHMARK(BM_Complexity_O_N) | ||
->RangeMultiplier(2) | ||
->Range(1 << 10, 1 << 16) | ||
->Range(1 << 10, 1 << 20) | ||
->UseManualTime() | ||
->Complexity(benchmark::oN); | ||
BENCHMARK(BM_Complexity_O_N) | ||
->RangeMultiplier(2) | ||
->Range(1 << 10, 1 << 16) | ||
->Range(1 << 10, 1 << 20) | ||
->UseManualTime() | ||
->Complexity(); | ||
BENCHMARK(BM_Complexity_O_N) | ||
->RangeMultiplier(2) | ||
->Range(1 << 10, 1 << 20) | ||
->UseManualTime() | ||
->Complexity([](benchmark::IterationCount n) -> double { | ||
return static_cast<double>(n); | ||
}); | ||
BENCHMARK(BM_Complexity_O_N) | ||
->RangeMultiplier(2) | ||
->Range(1 << 10, 1 << 16) | ||
->Complexity(); | ||
|
||
const char *n_test_name = "BM_Complexity_O_N"; | ||
const char *big_o_n_test_name = "BM_Complexity_O_N_BigO"; | ||
const char *rms_o_n_test_name = "BM_Complexity_O_N_RMS"; | ||
const char *n_test_name = "BM_Complexity_O_N/manual_time"; | ||
const char *big_o_n_test_name = "BM_Complexity_O_N/manual_time_BigO"; | ||
const char *rms_o_n_test_name = "BM_Complexity_O_N/manual_time_RMS"; | ||
const char *enum_auto_big_o_n = "N"; | ||
const 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); | ||
|
||
// 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); | ||
|
||
// 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=*/4); | ||
lambda_big_o_n, /*family_index=*/5); | ||
|
||
// ========================================================================= // | ||
// ------------------------- Testing BigO O(N*lgN) ------------------------- // | ||
// ------------------------- Testing BigO O(NlgN) ------------------------- // | ||
// ========================================================================= // | ||
|
||
static const double kLog2E = 1.44269504088896340736; | ||
static void BM_Complexity_O_N_log_N(benchmark::State &state) { | ||
auto v = ConstructRandomVector(state.range(0)); | ||
for (auto _ : state) { | ||
std::sort(v.begin(), v.end()); | ||
// This test requires a non-zero CPU time to avoid divide-by-zero | ||
benchmark::DoNotOptimize(state.iterations()); | ||
double tmp = state.iterations(); | ||
benchmark::DoNotOptimize(tmp); | ||
for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { | ||
benchmark::DoNotOptimize(state.iterations()); | ||
tmp *= state.iterations(); | ||
benchmark::DoNotOptimize(tmp); | ||
} | ||
|
||
state.SetIterationTime(state.range(0) * kLog2E * std::log(state.range(0)) * | ||
42 * 1e-9); | ||
} | ||
state.SetComplexityN(state.range(0)); | ||
} | ||
static const double kLog2E = 1.44269504088896340736; | ||
BENCHMARK(BM_Complexity_O_N_log_N) | ||
->RangeMultiplier(2) | ||
->Range(1 << 10, 1 << 16) | ||
->Range(1 << 10, 1U << 24) | ||
->UseManualTime() | ||
->Complexity(benchmark::oNLogN); | ||
BENCHMARK(BM_Complexity_O_N_log_N) | ||
->RangeMultiplier(2) | ||
->Range(1 << 10, 1 << 16) | ||
->Range(1 << 10, 1U << 24) | ||
->UseManualTime() | ||
->Complexity(); | ||
BENCHMARK(BM_Complexity_O_N_log_N) | ||
->RangeMultiplier(2) | ||
->Range(1 << 10, 1U << 24) | ||
->UseManualTime() | ||
->Complexity([](benchmark::IterationCount n) { | ||
return kLog2E * static_cast<double>(n) * std::log(static_cast<double>(n)); | ||
}); | ||
BENCHMARK(BM_Complexity_O_N_log_N) | ||
->RangeMultiplier(2) | ||
->Range(1 << 10, 1 << 16) | ||
->Complexity(); | ||
|
||
const char *n_lg_n_test_name = "BM_Complexity_O_N_log_N"; | ||
const char *big_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_BigO"; | ||
const char *rms_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N_RMS"; | ||
const char *n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time"; | ||
const char *big_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time_BigO"; | ||
const char *rms_o_n_lg_n_test_name = "BM_Complexity_O_N_log_N/manual_time_RMS"; | ||
const char *enum_auto_big_o_n_lg_n = "NlgN"; | ||
const char *lambda_big_o_n_lg_n = "f\\(N\\)"; | ||
|
||
|
@@ -193,33 +220,48 @@ 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); | ||
|
||
// Add lambda tests | ||
// 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, lambda_big_o_n_lg_n, | ||
rms_o_n_lg_n_test_name, enum_auto_big_o_n_lg_n, | ||
/*family_index=*/7); | ||
|
||
//// 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); | ||
|
||
// ========================================================================= // | ||
// -------- Testing formatting of Complexity with captured args ------------ // | ||
// ========================================================================= // | ||
|
||
void BM_ComplexityCaptureArgs(benchmark::State &state, int n) { | ||
for (auto _ : state) { | ||
// This test requires a non-zero CPU time to avoid divide-by-zero | ||
auto iterations = state.iterations(); | ||
benchmark::DoNotOptimize(iterations); | ||
benchmark::DoNotOptimize(state.iterations()); | ||
double tmp = state.iterations(); | ||
benchmark::DoNotOptimize(tmp); | ||
for (benchmark::IterationCount i = 0; i < state.iterations(); ++i) { | ||
benchmark::DoNotOptimize(state.iterations()); | ||
tmp *= state.iterations(); | ||
benchmark::DoNotOptimize(tmp); | ||
} | ||
|
||
state.SetIterationTime(state.range(0) * 42 * 1e-9); | ||
} | ||
state.SetComplexityN(n); | ||
} | ||
|
||
BENCHMARK_CAPTURE(BM_ComplexityCaptureArgs, capture_test, 100) | ||
->UseManualTime() | ||
->Complexity(benchmark::oN) | ||
->Ranges({{1, 2}, {3, 4}}); | ||
|
||
const std::string complexity_capture_name = | ||
"BM_ComplexityCaptureArgs/capture_test"; | ||
"BM_ComplexityCaptureArgs/capture_test/manual_time"; | ||
|
||
ADD_COMPLEXITY_CASES(complexity_capture_name, complexity_capture_name + "_BigO", | ||
complexity_capture_name + "_RMS", "N", /*family_index=*/9); | ||
complexity_capture_name + "_RMS", "N", | ||
/*family_index=*/9); | ||
|
||
// ========================================================================= // | ||
// --------------------------- TEST CASES END ------------------------------ // | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to check this logic:
if we're using manual time, we'll report manual time as "real" but then use "real" time for bigO.
if we're not using manual time, then we'll report real time as "real" but use "cpu" time for bigO.
maybe this could be a comment somewhere just to track the interaction between manual, real, and cpu times for bigO.