mirror of
https://github.com/google/benchmark.git
synced 2025-03-27 04:27:12 +08:00
implemented Complexity for O(1)
This commit is contained in:
parent
27f0baa190
commit
b73dc22944
@ -48,7 +48,10 @@ class BenchmarkReporter {
|
|||||||
cpu_accumulated_time(0),
|
cpu_accumulated_time(0),
|
||||||
bytes_per_second(0),
|
bytes_per_second(0),
|
||||||
items_per_second(0),
|
items_per_second(0),
|
||||||
max_heapbytes_used(0) {}
|
max_heapbytes_used(0),
|
||||||
|
complexity(O_1),
|
||||||
|
arg1(0),
|
||||||
|
arg2(0) {}
|
||||||
|
|
||||||
std::string benchmark_name;
|
std::string benchmark_name;
|
||||||
std::string report_label; // Empty if not set by benchmark.
|
std::string report_label; // Empty if not set by benchmark.
|
||||||
@ -63,6 +66,11 @@ class BenchmarkReporter {
|
|||||||
|
|
||||||
// This is set to 0.0 if memory tracing is not enabled.
|
// This is set to 0.0 if memory tracing is not enabled.
|
||||||
double max_heapbytes_used;
|
double max_heapbytes_used;
|
||||||
|
|
||||||
|
// Keep track of arguments to compute asymptotic complexity
|
||||||
|
BigO complexity;
|
||||||
|
int arg1;
|
||||||
|
int arg2;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Called once for every suite of benchmarks run.
|
// Called once for every suite of benchmarks run.
|
||||||
@ -78,6 +86,12 @@ class BenchmarkReporter {
|
|||||||
// Note that all the grouped benchmark runs should refer to the same
|
// Note that all the grouped benchmark runs should refer to the same
|
||||||
// benchmark, thus have the same name.
|
// benchmark, thus have the same name.
|
||||||
virtual void ReportRuns(const std::vector<Run>& report) = 0;
|
virtual void ReportRuns(const std::vector<Run>& report) = 0;
|
||||||
|
|
||||||
|
// Called once at the last instance of a benchmark range, gives information about
|
||||||
|
// asymptotic complexity and RMS.
|
||||||
|
// Note that all the benchmark runs in a range should refer to the same benchmark,
|
||||||
|
// thus have the same name.
|
||||||
|
virtual void ReportComplexity(const std::vector<Run>& complexity_reports) = 0;
|
||||||
|
|
||||||
// Called once and only once after ever group of benchmarks is run and
|
// Called once and only once after ever group of benchmarks is run and
|
||||||
// reported.
|
// reported.
|
||||||
@ -85,7 +99,8 @@ class BenchmarkReporter {
|
|||||||
|
|
||||||
virtual ~BenchmarkReporter();
|
virtual ~BenchmarkReporter();
|
||||||
protected:
|
protected:
|
||||||
static void ComputeStats(std::vector<Run> const& reports, Run* mean, Run* stddev);
|
static void ComputeStats(const std::vector<Run> & reports, Run& mean, Run& stddev);
|
||||||
|
static void ComputeBigO(const std::vector<Run> & reports, Run& bigO, Run& rms);
|
||||||
static TimeUnitMultiplier GetTimeUnitAndMultiplier(TimeUnit unit);
|
static TimeUnitMultiplier GetTimeUnitAndMultiplier(TimeUnit unit);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,6 +110,7 @@ class ConsoleReporter : public BenchmarkReporter {
|
|||||||
public:
|
public:
|
||||||
virtual bool ReportContext(const Context& context);
|
virtual bool ReportContext(const Context& context);
|
||||||
virtual void ReportRuns(const std::vector<Run>& reports);
|
virtual void ReportRuns(const std::vector<Run>& reports);
|
||||||
|
virtual void ReportComplexity(const std::vector<Run>& complexity_reports);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void PrintRunData(const Run& report);
|
virtual void PrintRunData(const Run& report);
|
||||||
@ -107,6 +123,7 @@ public:
|
|||||||
JSONReporter() : first_report_(true) {}
|
JSONReporter() : first_report_(true) {}
|
||||||
virtual bool ReportContext(const Context& context);
|
virtual bool ReportContext(const Context& context);
|
||||||
virtual void ReportRuns(const std::vector<Run>& reports);
|
virtual void ReportRuns(const std::vector<Run>& reports);
|
||||||
|
virtual void ReportComplexity(const std::vector<Run>& complexity_reports);
|
||||||
virtual void Finalize();
|
virtual void Finalize();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -119,6 +136,7 @@ class CSVReporter : public BenchmarkReporter {
|
|||||||
public:
|
public:
|
||||||
virtual bool ReportContext(const Context& context);
|
virtual bool ReportContext(const Context& context);
|
||||||
virtual void ReportRuns(const std::vector<Run>& reports);
|
virtual void ReportRuns(const std::vector<Run>& reports);
|
||||||
|
virtual void ReportComplexity(const std::vector<Run>& complexity_reports);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void PrintRunData(const Run& report);
|
void PrintRunData(const Run& report);
|
||||||
|
@ -291,6 +291,7 @@ struct Benchmark::Instance {
|
|||||||
bool use_real_time;
|
bool use_real_time;
|
||||||
bool use_manual_time;
|
bool use_manual_time;
|
||||||
BigO complexity;
|
BigO complexity;
|
||||||
|
bool last_benchmark_instance;
|
||||||
double min_time;
|
double min_time;
|
||||||
int threads; // Number of concurrent threads to use
|
int threads; // Number of concurrent threads to use
|
||||||
bool multithreaded; // Is benchmark multi-threaded?
|
bool multithreaded; // Is benchmark multi-threaded?
|
||||||
@ -414,6 +415,7 @@ bool BenchmarkFamilies::FindBenchmarks(
|
|||||||
instance.min_time = family->min_time_;
|
instance.min_time = family->min_time_;
|
||||||
instance.use_real_time = family->use_real_time_;
|
instance.use_real_time = family->use_real_time_;
|
||||||
instance.use_manual_time = family->use_manual_time_;
|
instance.use_manual_time = family->use_manual_time_;
|
||||||
|
instance.last_benchmark_instance = (args == family->args_.back());
|
||||||
instance.complexity = family->complexity_;
|
instance.complexity = family->complexity_;
|
||||||
instance.threads = num_threads;
|
instance.threads = num_threads;
|
||||||
instance.multithreaded = !(family->thread_counts_.empty());
|
instance.multithreaded = !(family->thread_counts_.empty());
|
||||||
@ -697,7 +699,8 @@ void RunInThread(const benchmark::internal::Benchmark::Instance* b,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
|
void RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
|
||||||
BenchmarkReporter* br) EXCLUDES(GetBenchmarkLock()) {
|
BenchmarkReporter* br,
|
||||||
|
std::vector<BenchmarkReporter::Run>& complexity_reports) EXCLUDES(GetBenchmarkLock()) {
|
||||||
size_t iters = 1;
|
size_t iters = 1;
|
||||||
|
|
||||||
std::vector<BenchmarkReporter::Run> reports;
|
std::vector<BenchmarkReporter::Run> reports;
|
||||||
@ -795,7 +798,14 @@ void RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
|
|||||||
report.cpu_accumulated_time = cpu_accumulated_time;
|
report.cpu_accumulated_time = cpu_accumulated_time;
|
||||||
report.bytes_per_second = bytes_per_second;
|
report.bytes_per_second = bytes_per_second;
|
||||||
report.items_per_second = items_per_second;
|
report.items_per_second = items_per_second;
|
||||||
|
report.arg1 = b.arg1;
|
||||||
|
report.arg2 = b.arg2;
|
||||||
|
report.complexity = b.complexity;
|
||||||
reports.push_back(report);
|
reports.push_back(report);
|
||||||
|
|
||||||
|
if(report.complexity != O_None)
|
||||||
|
complexity_reports.push_back(report);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,6 +829,12 @@ void RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
br->ReportRuns(reports);
|
br->ReportRuns(reports);
|
||||||
|
|
||||||
|
if((b.complexity != O_None) && b.last_benchmark_instance) {
|
||||||
|
br->ReportComplexity(complexity_reports);
|
||||||
|
complexity_reports.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (b.multithreaded) {
|
if (b.multithreaded) {
|
||||||
for (std::thread& thread : pool)
|
for (std::thread& thread : pool)
|
||||||
thread.join();
|
thread.join();
|
||||||
@ -903,9 +919,12 @@ void RunMatchingBenchmarks(const std::string& spec,
|
|||||||
context.cpu_scaling_enabled = CpuScalingEnabled();
|
context.cpu_scaling_enabled = CpuScalingEnabled();
|
||||||
context.name_field_width = name_field_width;
|
context.name_field_width = name_field_width;
|
||||||
|
|
||||||
|
// Keep track of runing times of all instances of current benchmark
|
||||||
|
std::vector<BenchmarkReporter::Run> complexity_reports;
|
||||||
|
|
||||||
if (reporter->ReportContext(context)) {
|
if (reporter->ReportContext(context)) {
|
||||||
for (const auto& benchmark : benchmarks) {
|
for (const auto& benchmark : benchmarks) {
|
||||||
RunBenchmark(benchmark, reporter);
|
RunBenchmark(benchmark, reporter, complexity_reports);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,13 +72,28 @@ void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
|
|||||||
|
|
||||||
Run mean_data;
|
Run mean_data;
|
||||||
Run stddev_data;
|
Run stddev_data;
|
||||||
BenchmarkReporter::ComputeStats(reports, &mean_data, &stddev_data);
|
BenchmarkReporter::ComputeStats(reports, mean_data, stddev_data);
|
||||||
|
|
||||||
// Output using PrintRun.
|
// Output using PrintRun.
|
||||||
PrintRunData(mean_data);
|
PrintRunData(mean_data);
|
||||||
PrintRunData(stddev_data);
|
PrintRunData(stddev_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConsoleReporter::ReportComplexity(const std::vector<Run> & complexity_reports) {
|
||||||
|
if (complexity_reports.size() < 2) {
|
||||||
|
// We don't report asymptotic complexity data if there was a single run.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Run bigO_data;
|
||||||
|
Run rms_data;
|
||||||
|
BenchmarkReporter::ComputeBigO(complexity_reports, bigO_data, rms_data);
|
||||||
|
|
||||||
|
// Output using PrintRun.
|
||||||
|
PrintRunData(bigO_data);
|
||||||
|
PrintRunData(rms_data);
|
||||||
|
}
|
||||||
|
|
||||||
void ConsoleReporter::PrintRunData(const Run& result) {
|
void ConsoleReporter::PrintRunData(const Run& result) {
|
||||||
// Format bytes per second
|
// Format bytes per second
|
||||||
std::string rate;
|
std::string rate;
|
||||||
|
@ -48,7 +48,7 @@ bool CSVReporter::ReportContext(const Context& context) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVReporter::ReportRuns(std::vector<Run> const& reports) {
|
void CSVReporter::ReportRuns(const std::vector<Run> & reports) {
|
||||||
if (reports.empty()) {
|
if (reports.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -57,7 +57,7 @@ void CSVReporter::ReportRuns(std::vector<Run> const& reports) {
|
|||||||
if (reports.size() >= 2) {
|
if (reports.size() >= 2) {
|
||||||
Run mean_data;
|
Run mean_data;
|
||||||
Run stddev_data;
|
Run stddev_data;
|
||||||
BenchmarkReporter::ComputeStats(reports, &mean_data, &stddev_data);
|
BenchmarkReporter::ComputeStats(reports, mean_data, stddev_data);
|
||||||
reports_cp.push_back(mean_data);
|
reports_cp.push_back(mean_data);
|
||||||
reports_cp.push_back(stddev_data);
|
reports_cp.push_back(stddev_data);
|
||||||
}
|
}
|
||||||
@ -66,7 +66,22 @@ void CSVReporter::ReportRuns(std::vector<Run> const& reports) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CSVReporter::PrintRunData(Run const& run) {
|
void CSVReporter::ReportComplexity(const std::vector<Run> & complexity_reports) {
|
||||||
|
if (complexity_reports.size() < 2) {
|
||||||
|
// We don't report asymptotic complexity data if there was a single run.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Run bigO_data;
|
||||||
|
Run rms_data;
|
||||||
|
BenchmarkReporter::ComputeBigO(complexity_reports, bigO_data, rms_data);
|
||||||
|
|
||||||
|
// Output using PrintRun.
|
||||||
|
PrintRunData(bigO_data);
|
||||||
|
PrintRunData(rms_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSVReporter::PrintRunData(const Run & run) {
|
||||||
double multiplier;
|
double multiplier;
|
||||||
const char* timeLabel;
|
const char* timeLabel;
|
||||||
std::tie(timeLabel, multiplier) = GetTimeUnitAndMultiplier(run.time_unit);
|
std::tie(timeLabel, multiplier) = GetTimeUnitAndMultiplier(run.time_unit);
|
||||||
|
@ -100,7 +100,7 @@ void JSONReporter::ReportRuns(std::vector<Run> const& reports) {
|
|||||||
if (reports.size() >= 2) {
|
if (reports.size() >= 2) {
|
||||||
Run mean_data;
|
Run mean_data;
|
||||||
Run stddev_data;
|
Run stddev_data;
|
||||||
BenchmarkReporter::ComputeStats(reports, &mean_data, &stddev_data);
|
BenchmarkReporter::ComputeStats(reports, mean_data, stddev_data);
|
||||||
reports_cp.push_back(mean_data);
|
reports_cp.push_back(mean_data);
|
||||||
reports_cp.push_back(stddev_data);
|
reports_cp.push_back(stddev_data);
|
||||||
}
|
}
|
||||||
@ -115,6 +115,21 @@ void JSONReporter::ReportRuns(std::vector<Run> const& reports) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JSONReporter::ReportComplexity(const std::vector<Run> & complexity_reports) {
|
||||||
|
if (complexity_reports.size() < 2) {
|
||||||
|
// We don't report asymptotic complexity data if there was a single run.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Run bigO_data;
|
||||||
|
Run rms_data;
|
||||||
|
BenchmarkReporter::ComputeBigO(complexity_reports, bigO_data, rms_data);
|
||||||
|
|
||||||
|
// Output using PrintRun.
|
||||||
|
PrintRunData(bigO_data);
|
||||||
|
PrintRunData(rms_data);
|
||||||
|
}
|
||||||
|
|
||||||
void JSONReporter::Finalize() {
|
void JSONReporter::Finalize() {
|
||||||
// Close the list of benchmarks and the top level object.
|
// Close the list of benchmarks and the top level object.
|
||||||
std::cout << "\n ]\n}\n";
|
std::cout << "\n ]\n}\n";
|
||||||
|
@ -24,7 +24,7 @@ namespace benchmark {
|
|||||||
|
|
||||||
void BenchmarkReporter::ComputeStats(
|
void BenchmarkReporter::ComputeStats(
|
||||||
const std::vector<Run>& reports,
|
const std::vector<Run>& reports,
|
||||||
Run* mean_data, Run* stddev_data) {
|
Run& mean_data, Run& stddev_data) {
|
||||||
CHECK(reports.size() >= 2) << "Cannot compute stats for less than 2 reports";
|
CHECK(reports.size() >= 2) << "Cannot compute stats for less than 2 reports";
|
||||||
// Accumulators.
|
// Accumulators.
|
||||||
Stat1_d real_accumulated_time_stat;
|
Stat1_d real_accumulated_time_stat;
|
||||||
@ -48,33 +48,69 @@ void BenchmarkReporter::ComputeStats(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the data from the accumulator to BenchmarkReporter::Run's.
|
// Get the data from the accumulator to BenchmarkReporter::Run's.
|
||||||
mean_data->benchmark_name = reports[0].benchmark_name + "_mean";
|
mean_data.benchmark_name = reports[0].benchmark_name + "_mean";
|
||||||
mean_data->iterations = run_iterations;
|
mean_data.iterations = run_iterations;
|
||||||
mean_data->real_accumulated_time = real_accumulated_time_stat.Mean() *
|
mean_data.real_accumulated_time = real_accumulated_time_stat.Mean() *
|
||||||
run_iterations;
|
run_iterations;
|
||||||
mean_data->cpu_accumulated_time = cpu_accumulated_time_stat.Mean() *
|
mean_data.cpu_accumulated_time = cpu_accumulated_time_stat.Mean() *
|
||||||
run_iterations;
|
run_iterations;
|
||||||
mean_data->bytes_per_second = bytes_per_second_stat.Mean();
|
mean_data.bytes_per_second = bytes_per_second_stat.Mean();
|
||||||
mean_data->items_per_second = items_per_second_stat.Mean();
|
mean_data.items_per_second = items_per_second_stat.Mean();
|
||||||
|
|
||||||
// Only add label to mean/stddev if it is same for all runs
|
// Only add label to mean/stddev if it is same for all runs
|
||||||
mean_data->report_label = reports[0].report_label;
|
mean_data.report_label = reports[0].report_label;
|
||||||
for (std::size_t i = 1; i < reports.size(); i++) {
|
for (std::size_t i = 1; i < reports.size(); i++) {
|
||||||
if (reports[i].report_label != reports[0].report_label) {
|
if (reports[i].report_label != reports[0].report_label) {
|
||||||
mean_data->report_label = "";
|
mean_data.report_label = "";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stddev_data->benchmark_name = reports[0].benchmark_name + "_stddev";
|
stddev_data.benchmark_name = reports[0].benchmark_name + "_stddev";
|
||||||
stddev_data->report_label = mean_data->report_label;
|
stddev_data.report_label = mean_data.report_label;
|
||||||
stddev_data->iterations = 0;
|
stddev_data.iterations = 0;
|
||||||
stddev_data->real_accumulated_time =
|
stddev_data.real_accumulated_time =
|
||||||
real_accumulated_time_stat.StdDev();
|
real_accumulated_time_stat.StdDev();
|
||||||
stddev_data->cpu_accumulated_time =
|
stddev_data.cpu_accumulated_time =
|
||||||
|
cpu_accumulated_time_stat.StdDev();
|
||||||
|
stddev_data.bytes_per_second = bytes_per_second_stat.StdDev();
|
||||||
|
stddev_data.items_per_second = items_per_second_stat.StdDev();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BenchmarkReporter::ComputeBigO(
|
||||||
|
const std::vector<Run>& reports,
|
||||||
|
Run& bigO, Run& rms) {
|
||||||
|
CHECK(reports.size() >= 2) << "Cannot compute asymptotic complexity for less than 2 reports";
|
||||||
|
// Accumulators.
|
||||||
|
Stat1_d real_accumulated_time_stat;
|
||||||
|
Stat1_d cpu_accumulated_time_stat;
|
||||||
|
|
||||||
|
// Populate the accumulators.
|
||||||
|
for (Run const& run : reports) {
|
||||||
|
real_accumulated_time_stat +=
|
||||||
|
Stat1_d(run.real_accumulated_time/run.iterations, run.iterations);
|
||||||
|
cpu_accumulated_time_stat +=
|
||||||
|
Stat1_d(run.cpu_accumulated_time/run.iterations, run.iterations);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string benchmark_name = reports[0].benchmark_name.substr(0, reports[0].benchmark_name.find('/'));
|
||||||
|
|
||||||
|
// Get the data from the accumulator to BenchmarkReporter::Run's.
|
||||||
|
bigO.benchmark_name = benchmark_name + "_BigO";
|
||||||
|
bigO.iterations = 0;
|
||||||
|
bigO.real_accumulated_time = real_accumulated_time_stat.Mean();
|
||||||
|
bigO.cpu_accumulated_time = cpu_accumulated_time_stat.Mean();
|
||||||
|
|
||||||
|
// Only add label to mean/stddev if it is same for all runs
|
||||||
|
bigO.report_label = reports[0].report_label;
|
||||||
|
|
||||||
|
rms.benchmark_name = benchmark_name + "_RMS";
|
||||||
|
rms.report_label = bigO.report_label;
|
||||||
|
rms.iterations = 0;
|
||||||
|
rms.real_accumulated_time =
|
||||||
|
real_accumulated_time_stat.StdDev();
|
||||||
|
rms.cpu_accumulated_time =
|
||||||
cpu_accumulated_time_stat.StdDev();
|
cpu_accumulated_time_stat.StdDev();
|
||||||
stddev_data->bytes_per_second = bytes_per_second_stat.StdDev();
|
|
||||||
stddev_data->items_per_second = items_per_second_stat.StdDev();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeUnitMultiplier BenchmarkReporter::GetTimeUnitAndMultiplier(TimeUnit unit) {
|
TimeUnitMultiplier BenchmarkReporter::GetTimeUnitAndMultiplier(TimeUnit unit) {
|
||||||
|
@ -101,7 +101,7 @@ void BM_Extreme_Cases(benchmark::State& state) {
|
|||||||
while (state.KeepRunning()) {
|
while (state.KeepRunning()) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BENCHMARK(BM_Extreme_Cases);
|
BENCHMARK(BM_Extreme_Cases) -> Complexity(benchmark::O_N_log_N);
|
||||||
BENCHMARK(BM_Extreme_Cases)->Arg(42);
|
BENCHMARK(BM_Extreme_Cases)->Arg(42) -> Complexity(benchmark::O_Auto);
|
||||||
|
|
||||||
BENCHMARK_MAIN()
|
BENCHMARK_MAIN()
|
Loading…
Reference in New Issue
Block a user