| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| |
|
| | #include "benchmark/benchmark.h" |
| |
|
| | #include <algorithm> |
| | #include <cmath> |
| | #include "check.h" |
| | #include "complexity.h" |
| |
|
| | namespace benchmark { |
| |
|
| | |
| | BigOFunc* FittingCurve(BigO complexity) { |
| | static const double kLog2E = 1.44269504088896340736; |
| | switch (complexity) { |
| | case oN: |
| | return [](int64_t n) -> double { return static_cast<double>(n); }; |
| | case oNSquared: |
| | return [](int64_t n) -> double { return std::pow(n, 2); }; |
| | case oNCubed: |
| | return [](int64_t n) -> double { return std::pow(n, 3); }; |
| | case oLogN: |
| | |
| | return [](int64_t n) { return kLog2E * log(static_cast<double>(n)); }; |
| | case oNLogN: |
| | |
| | return [](int64_t n) { return kLog2E * n * log(static_cast<double>(n)); }; |
| | case o1: |
| | default: |
| | return [](int64_t) { return 1.0; }; |
| | } |
| | } |
| |
|
| | |
| | std::string GetBigOString(BigO complexity) { |
| | switch (complexity) { |
| | case oN: |
| | return "N"; |
| | case oNSquared: |
| | return "N^2"; |
| | case oNCubed: |
| | return "N^3"; |
| | case oLogN: |
| | return "lgN"; |
| | case oNLogN: |
| | return "NlgN"; |
| | case o1: |
| | return "(1)"; |
| | default: |
| | return "f(N)"; |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| |
|
| | LeastSq MinimalLeastSq(const std::vector<int64_t>& n, |
| | const std::vector<double>& time, |
| | BigOFunc* fitting_curve) { |
| | double sigma_gn = 0.0; |
| | double sigma_gn_squared = 0.0; |
| | double sigma_time = 0.0; |
| | double sigma_time_gn = 0.0; |
| |
|
| | |
| | for (size_t i = 0; i < n.size(); ++i) { |
| | double gn_i = fitting_curve(n[i]); |
| | sigma_gn += gn_i; |
| | sigma_gn_squared += gn_i * gn_i; |
| | sigma_time += time[i]; |
| | sigma_time_gn += time[i] * gn_i; |
| | } |
| |
|
| | LeastSq result; |
| | result.complexity = oLambda; |
| |
|
| | |
| | result.coef = sigma_time_gn / sigma_gn_squared; |
| |
|
| | |
| | double rms = 0.0; |
| | for (size_t i = 0; i < n.size(); ++i) { |
| | double fit = result.coef * fitting_curve(n[i]); |
| | rms += pow((time[i] - fit), 2); |
| | } |
| |
|
| | |
| | double mean = sigma_time / n.size(); |
| | result.rms = sqrt(rms / n.size()) / mean; |
| |
|
| | return result; |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | LeastSq MinimalLeastSq(const std::vector<int64_t>& n, |
| | const std::vector<double>& time, const BigO complexity) { |
| | CHECK_EQ(n.size(), time.size()); |
| | CHECK_GE(n.size(), 2); |
| | |
| | CHECK_NE(complexity, oNone); |
| |
|
| | LeastSq best_fit; |
| |
|
| | if (complexity == oAuto) { |
| | std::vector<BigO> fit_curves = {oLogN, oN, oNLogN, oNSquared, oNCubed}; |
| |
|
| | |
| | best_fit = MinimalLeastSq(n, time, FittingCurve(o1)); |
| | best_fit.complexity = o1; |
| |
|
| | |
| | for (const auto& fit : fit_curves) { |
| | LeastSq current_fit = MinimalLeastSq(n, time, FittingCurve(fit)); |
| | if (current_fit.rms < best_fit.rms) { |
| | best_fit = current_fit; |
| | best_fit.complexity = fit; |
| | } |
| | } |
| | } else { |
| | best_fit = MinimalLeastSq(n, time, FittingCurve(complexity)); |
| | best_fit.complexity = complexity; |
| | } |
| |
|
| | return best_fit; |
| | } |
| |
|
| | std::vector<BenchmarkReporter::Run> ComputeBigO( |
| | const std::vector<BenchmarkReporter::Run>& reports) { |
| | typedef BenchmarkReporter::Run Run; |
| | std::vector<Run> results; |
| |
|
| | if (reports.size() < 2) return results; |
| |
|
| | |
| | std::vector<int64_t> n; |
| | std::vector<double> real_time; |
| | std::vector<double> cpu_time; |
| |
|
| | |
| | for (const Run& run : reports) { |
| | CHECK_GT(run.complexity_n, 0) << "Did you forget to call SetComplexityN?"; |
| | n.push_back(run.complexity_n); |
| | real_time.push_back(run.real_accumulated_time / run.iterations); |
| | cpu_time.push_back(run.cpu_accumulated_time / run.iterations); |
| | } |
| |
|
| | LeastSq result_cpu; |
| | LeastSq result_real; |
| |
|
| | if (reports[0].complexity == oLambda) { |
| | 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); |
| | } |
| |
|
| | std::string run_name = reports[0].benchmark_name().substr( |
| | 0, reports[0].benchmark_name().find('/')); |
| |
|
| | |
| | Run big_o; |
| | big_o.run_name = run_name; |
| | big_o.run_type = BenchmarkReporter::Run::RT_Aggregate; |
| | big_o.aggregate_name = "BigO"; |
| | big_o.iterations = 0; |
| | big_o.real_accumulated_time = result_real.coef; |
| | big_o.cpu_accumulated_time = result_cpu.coef; |
| | big_o.report_big_o = true; |
| | big_o.complexity = result_cpu.complexity; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | double multiplier = GetTimeUnitMultiplier(reports[0].time_unit); |
| |
|
| | |
| | Run rms; |
| | rms.run_name = run_name; |
| | big_o.report_label = reports[0].report_label; |
| | rms.run_type = BenchmarkReporter::Run::RT_Aggregate; |
| | rms.aggregate_name = "RMS"; |
| | rms.report_label = big_o.report_label; |
| | rms.iterations = 0; |
| | rms.real_accumulated_time = result_real.rms / multiplier; |
| | rms.cpu_accumulated_time = result_cpu.rms / multiplier; |
| | rms.report_rms = true; |
| | rms.complexity = result_cpu.complexity; |
| | |
| | |
| | rms.time_unit = reports[0].time_unit; |
| |
|
| | results.push_back(big_o); |
| | results.push_back(rms); |
| | return results; |
| | } |
| |
|
| | } |
| |
|