Commit 2d088a9f by Dominic Hamon

Merge branch 'ismaelJimenez-added_lambdas'

parents 84cd50b8 e4981431
...@@ -142,6 +142,14 @@ BENCHMARK(BM_StringCompare) ...@@ -142,6 +142,14 @@ BENCHMARK(BM_StringCompare)
->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity(); ->RangeMultiplier(2)->Range(1<<10, 1<<18)->Complexity();
``` ```
The following code will specify asymptotic complexity with a lambda function,
that might be used to customize high-order term calculation.
```c++
BENCHMARK(BM_StringCompare)->RangeMultiplier(2)
->Range(1<<10, 1<<18)->Complexity([](int n)->double{return n; });
```
### Templated benchmarks ### Templated benchmarks
Templated benchmarks work the same way: This example produces and consumes Templated benchmarks work the same way: This example produces and consumes
messages of size `sizeof(v)` `range_x` times. It also outputs throughput in the messages of size `sizeof(v)` `range_x` times. It also outputs throughput in the
......
...@@ -247,9 +247,14 @@ enum BigO { ...@@ -247,9 +247,14 @@ enum BigO {
oNCubed, oNCubed,
oLogN, oLogN,
oNLogN, oNLogN,
oAuto oAuto,
oLambda
}; };
// BigOFunc is passed to a benchmark in order to specify the asymptotic
// computational complexity for the benchmark.
typedef double(BigOFunc)(int);
// State is passed to a running Benchmark and contains state for the // State is passed to a running Benchmark and contains state for the
// benchmark to use. // benchmark to use.
class State { class State {
...@@ -257,7 +262,7 @@ public: ...@@ -257,7 +262,7 @@ public:
State(size_t max_iters, bool has_x, int x, bool has_y, int y, State(size_t max_iters, bool has_x, int x, bool has_y, int y,
int thread_i, int n_threads); int thread_i, int n_threads);
// Returns true iff the benchmark should continue through another iteration. // Returns true if the benchmark should continue through another iteration.
// NOTE: A benchmark may not return from the test until KeepRunning() has // NOTE: A benchmark may not return from the test until KeepRunning() has
// returned false. // returned false.
bool KeepRunning() { bool KeepRunning() {
...@@ -358,7 +363,7 @@ public: ...@@ -358,7 +363,7 @@ public:
// family benchmark, then current benchmark will be part of the computation and complexity_n will // family benchmark, then current benchmark will be part of the computation and complexity_n will
// represent the length of N. // represent the length of N.
BENCHMARK_ALWAYS_INLINE BENCHMARK_ALWAYS_INLINE
void SetComplexityN(size_t complexity_n) { void SetComplexityN(int complexity_n) {
complexity_n_ = complexity_n; complexity_n_ = complexity_n;
} }
...@@ -439,7 +444,7 @@ private: ...@@ -439,7 +444,7 @@ private:
size_t bytes_processed_; size_t bytes_processed_;
size_t items_processed_; size_t items_processed_;
size_t complexity_n_; int complexity_n_;
public: public:
// FIXME: Make this private somehow. // FIXME: Make this private somehow.
...@@ -538,6 +543,10 @@ public: ...@@ -538,6 +543,10 @@ public:
// the asymptotic computational complexity will be shown on the output. // the asymptotic computational complexity will be shown on the output.
Benchmark* Complexity(BigO complexity = benchmark::oAuto); Benchmark* Complexity(BigO complexity = benchmark::oAuto);
// Set the asymptotic computational complexity for the benchmark. If called
// the asymptotic computational complexity will be shown on the output.
Benchmark* Complexity(BigOFunc* complexity);
// Support for running multiple copies of the same benchmark concurrently // Support for running multiple copies of the same benchmark concurrently
// in multiple threads. This may be useful when measuring the scaling // in multiple threads. This may be useful when measuring the scaling
// of some piece of code. // of some piece of code.
......
...@@ -86,6 +86,7 @@ class BenchmarkReporter { ...@@ -86,6 +86,7 @@ class BenchmarkReporter {
// Keep track of arguments to compute asymptotic complexity // Keep track of arguments to compute asymptotic complexity
BigO complexity; BigO complexity;
BigOFunc* complexity_lambda;
int complexity_n; int complexity_n;
// Inform print function whether the current run is a complexity report // Inform print function whether the current run is a complexity report
...@@ -147,7 +148,7 @@ class BenchmarkReporter { ...@@ -147,7 +148,7 @@ class BenchmarkReporter {
// REQUIRES: 'out' is non-null. // REQUIRES: 'out' is non-null.
static void PrintBasicContext(std::ostream* out, Context const& context); static void PrintBasicContext(std::ostream* out, Context const& context);
private: private:
std::ostream* output_stream_; std::ostream* output_stream_;
std::ostream* error_stream_; std::ostream* error_stream_;
}; };
...@@ -159,31 +160,31 @@ class ConsoleReporter : public BenchmarkReporter { ...@@ -159,31 +160,31 @@ class ConsoleReporter : public BenchmarkReporter {
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);
protected: protected:
virtual void PrintRunData(const Run& report); virtual void PrintRunData(const Run& report);
size_t name_field_width_; size_t name_field_width_;
}; };
class JSONReporter : public BenchmarkReporter { class JSONReporter : public BenchmarkReporter {
public: 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 Finalize(); virtual void Finalize();
private: private:
void PrintRunData(const Run& report); void PrintRunData(const Run& report);
bool first_report_; bool first_report_;
}; };
class CSVReporter : public BenchmarkReporter { 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);
private: private:
void PrintRunData(const Run& report); void PrintRunData(const Run& report);
}; };
......
...@@ -317,6 +317,7 @@ struct Benchmark::Instance { ...@@ -317,6 +317,7 @@ struct Benchmark::Instance {
bool use_real_time; bool use_real_time;
bool use_manual_time; bool use_manual_time;
BigO complexity; BigO complexity;
BigOFunc* complexity_lambda;
bool last_benchmark_instance; bool last_benchmark_instance;
int repetitions; int repetitions;
double min_time; double min_time;
...@@ -362,6 +363,7 @@ public: ...@@ -362,6 +363,7 @@ public:
void UseRealTime(); void UseRealTime();
void UseManualTime(); void UseManualTime();
void Complexity(BigO complexity); void Complexity(BigO complexity);
void ComplexityLambda(BigOFunc* complexity);
void Threads(int t); void Threads(int t);
void ThreadRange(int min_threads, int max_threads); void ThreadRange(int min_threads, int max_threads);
void ThreadPerCpu(); void ThreadPerCpu();
...@@ -382,6 +384,7 @@ private: ...@@ -382,6 +384,7 @@ private:
bool use_real_time_; bool use_real_time_;
bool use_manual_time_; bool use_manual_time_;
BigO complexity_; BigO complexity_;
BigOFunc* complexity_lambda_;
std::vector<int> thread_counts_; std::vector<int> thread_counts_;
BenchmarkImp& operator=(BenchmarkImp const&); BenchmarkImp& operator=(BenchmarkImp const&);
...@@ -446,6 +449,7 @@ bool BenchmarkFamilies::FindBenchmarks( ...@@ -446,6 +449,7 @@ bool BenchmarkFamilies::FindBenchmarks(
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.complexity = family->complexity_; instance.complexity = family->complexity_;
instance.complexity_lambda = family->complexity_lambda_;
instance.threads = num_threads; instance.threads = num_threads;
instance.multithreaded = !(family->thread_counts_.empty()); instance.multithreaded = !(family->thread_counts_.empty());
...@@ -573,6 +577,10 @@ void BenchmarkImp::Complexity(BigO complexity){ ...@@ -573,6 +577,10 @@ void BenchmarkImp::Complexity(BigO complexity){
complexity_ = complexity; complexity_ = complexity;
} }
void BenchmarkImp::ComplexityLambda(BigOFunc* complexity) {
complexity_lambda_ = complexity;
}
void BenchmarkImp::Threads(int t) { void BenchmarkImp::Threads(int t) {
CHECK_GT(t, 0); CHECK_GT(t, 0);
thread_counts_.push_back(t); thread_counts_.push_back(t);
...@@ -697,6 +705,12 @@ Benchmark* Benchmark::Complexity(BigO complexity) { ...@@ -697,6 +705,12 @@ Benchmark* Benchmark::Complexity(BigO complexity) {
return this; return this;
} }
Benchmark* Benchmark::Complexity(BigOFunc* complexity) {
imp_->Complexity(oLambda);
imp_->ComplexityLambda(complexity);
return this;
}
Benchmark* Benchmark::Threads(int t) { Benchmark* Benchmark::Threads(int t) {
imp_->Threads(t); imp_->Threads(t);
return this; return this;
...@@ -855,6 +869,7 @@ void RunBenchmark(const benchmark::internal::Benchmark::Instance& b, ...@@ -855,6 +869,7 @@ void RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
report.items_per_second = items_per_second; report.items_per_second = items_per_second;
report.complexity_n = total.complexity_n; report.complexity_n = total.complexity_n;
report.complexity = b.complexity; report.complexity = b.complexity;
report.complexity_lambda = b.complexity_lambda;
if(report.complexity != oNone) if(report.complexity != oNone)
complexity_reports.push_back(report); complexity_reports.push_back(report);
} }
......
...@@ -17,31 +17,30 @@ ...@@ -17,31 +17,30 @@
#include "benchmark/benchmark_api.h" #include "benchmark/benchmark_api.h"
#include "complexity.h" #include <algorithm>
#include <cmath>
#include "check.h" #include "check.h"
#include "complexity.h"
#include "stat.h" #include "stat.h"
#include <cmath>
#include <algorithm>
#include <functional>
namespace benchmark { namespace benchmark {
// Internal function to calculate the different scalability forms // Internal function to calculate the different scalability forms
std::function<double(int)> FittingCurve(BigO complexity) { BigOFunc* FittingCurve(BigO complexity) {
switch (complexity) { switch (complexity) {
case oN: case oN:
return [](int n) {return n; }; return [](int n) -> double { return n; };
case oNSquared: case oNSquared:
return [](int n) {return n*n; }; return [](int n) -> double { return n * n; };
case oNCubed: case oNCubed:
return [](int n) {return n*n*n; }; return [](int n) -> double { return n * n * n; };
case oLogN: case oLogN:
return [](int n) {return log2(n); }; return [](int n) { return log2(n); };
case oNLogN: case oNLogN:
return [](int n) {return n * log2(n); }; return [](int n) { return n * log2(n); };
case o1: case o1:
default: default:
return [](int) {return 1; }; return [](int) { return 1.0; };
} }
} }
...@@ -49,19 +48,19 @@ std::function<double(int)> FittingCurve(BigO complexity) { ...@@ -49,19 +48,19 @@ std::function<double(int)> FittingCurve(BigO complexity) {
std::string GetBigOString(BigO complexity) { std::string GetBigOString(BigO complexity) {
switch (complexity) { switch (complexity) {
case oN: case oN:
return "* N"; return "N";
case oNSquared: case oNSquared:
return "* N**2"; return "N^2";
case oNCubed: case oNCubed:
return "* N**3"; return "N^3";
case oLogN: case oLogN:
return "* lgN"; return "lgN";
case oNLogN: case oNLogN:
return "* NlgN"; return "NlgN";
case o1: case o1:
return "* 1"; return "(1)";
default: default:
return ""; return "f(N)";
} }
} }
...@@ -75,21 +74,9 @@ std::string GetBigOString(BigO complexity) { ...@@ -75,21 +74,9 @@ std::string GetBigOString(BigO complexity) {
// For a deeper explanation on the algorithm logic, look the README file at // For a deeper explanation on the algorithm logic, look the README file at
// http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit // http://github.com/ismaelJimenez/Minimal-Cpp-Least-Squared-Fit
// This interface is currently not used from the oustide, but it has been LeastSq MinimalLeastSq(const std::vector<int>& n,
// provided for future upgrades. If in the future it is not needed to support
// Cxx03, then all the calculations could be upgraded to use lambdas because
// they are more powerful and provide a cleaner inferface than enumerators,
// but complete implementation with lambdas will not work for Cxx03
// (e.g. lack of std::function).
// In case lambdas are implemented, the interface would be like :
// -> Complexity([](int n) {return n;};)
// and any arbitrary and valid equation would be allowed, but the option to
// calculate the best fit to the most common scalability curves will still
// be kept.
LeastSq CalculateLeastSq(const std::vector<int>& n,
const std::vector<double>& time, const std::vector<double>& time,
std::function<double(int)> fitting_curve) { BigOFunc* fitting_curve) {
double sigma_gn = 0.0; double sigma_gn = 0.0;
double sigma_gn_squared = 0.0; double sigma_gn_squared = 0.0;
double sigma_time = 0.0; double sigma_time = 0.0;
...@@ -105,6 +92,7 @@ LeastSq CalculateLeastSq(const std::vector<int>& n, ...@@ -105,6 +92,7 @@ LeastSq CalculateLeastSq(const std::vector<int>& n,
} }
LeastSq result; LeastSq result;
result.complexity = oLambda;
// Calculate complexity. // Calculate complexity.
result.coef = sigma_time_gn / sigma_gn_squared; result.coef = sigma_time_gn / sigma_gn_squared;
...@@ -134,29 +122,29 @@ LeastSq MinimalLeastSq(const std::vector<int>& n, ...@@ -134,29 +122,29 @@ LeastSq MinimalLeastSq(const std::vector<int>& n,
const std::vector<double>& time, const std::vector<double>& time,
const BigO complexity) { const BigO complexity) {
CHECK_EQ(n.size(), time.size()); CHECK_EQ(n.size(), time.size());
CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two benchmark runs are given CHECK_GE(n.size(), 2); // Do not compute fitting curve is less than two
// benchmark runs are given
CHECK_NE(complexity, oNone); CHECK_NE(complexity, oNone);
LeastSq best_fit; LeastSq best_fit;
if(complexity == oAuto) { if (complexity == oAuto) {
std::vector<BigO> fit_curves = { std::vector<BigO> fit_curves = {oLogN, oN, oNLogN, oNSquared, oNCubed};
oLogN, oN, oNLogN, oNSquared, oNCubed };
// Take o1 as default best fitting curve // Take o1 as default best fitting curve
best_fit = CalculateLeastSq(n, time, FittingCurve(o1)); best_fit = MinimalLeastSq(n, time, FittingCurve(o1));
best_fit.complexity = o1; best_fit.complexity = o1;
// Compute all possible fitting curves and stick to the best one // Compute all possible fitting curves and stick to the best one
for (const auto& fit : fit_curves) { for (const auto& fit : fit_curves) {
LeastSq current_fit = CalculateLeastSq(n, time, FittingCurve(fit)); LeastSq current_fit = MinimalLeastSq(n, time, FittingCurve(fit));
if (current_fit.rms < best_fit.rms) { if (current_fit.rms < best_fit.rms) {
best_fit = current_fit; best_fit = current_fit;
best_fit.complexity = fit; best_fit.complexity = fit;
} }
} }
} else { } else {
best_fit = CalculateLeastSq(n, time, FittingCurve(complexity)); best_fit = MinimalLeastSq(n, time, FittingCurve(complexity));
best_fit.complexity = complexity; best_fit.complexity = complexity;
} }
...@@ -164,14 +152,13 @@ LeastSq MinimalLeastSq(const std::vector<int>& n, ...@@ -164,14 +152,13 @@ LeastSq MinimalLeastSq(const std::vector<int>& n,
} }
std::vector<BenchmarkReporter::Run> ComputeStats( std::vector<BenchmarkReporter::Run> ComputeStats(
const std::vector<BenchmarkReporter::Run>& reports) const std::vector<BenchmarkReporter::Run>& reports) {
{
typedef BenchmarkReporter::Run Run; typedef BenchmarkReporter::Run Run;
std::vector<Run> results; std::vector<Run> results;
auto error_count = std::count_if( auto error_count =
reports.begin(), reports.end(), std::count_if(reports.begin(), reports.end(),
[](Run const& run) {return run.error_occurred;}); [](Run const& run) { return run.error_occurred; });
if (reports.size() - error_count < 2) { if (reports.size() - error_count < 2) {
// We don't report aggregated data if there was a single run. // We don't report aggregated data if there was a single run.
...@@ -190,12 +177,11 @@ std::vector<BenchmarkReporter::Run> ComputeStats( ...@@ -190,12 +177,11 @@ std::vector<BenchmarkReporter::Run> ComputeStats(
for (Run const& run : reports) { for (Run const& run : reports) {
CHECK_EQ(reports[0].benchmark_name, run.benchmark_name); CHECK_EQ(reports[0].benchmark_name, run.benchmark_name);
CHECK_EQ(run_iterations, run.iterations); CHECK_EQ(run_iterations, run.iterations);
if (run.error_occurred) if (run.error_occurred) continue;
continue;
real_accumulated_time_stat += real_accumulated_time_stat +=
Stat1_d(run.real_accumulated_time/run.iterations, run.iterations); Stat1_d(run.real_accumulated_time / run.iterations, run.iterations);
cpu_accumulated_time_stat += cpu_accumulated_time_stat +=
Stat1_d(run.cpu_accumulated_time/run.iterations, run.iterations); Stat1_d(run.cpu_accumulated_time / run.iterations, run.iterations);
items_per_second_stat += Stat1_d(run.items_per_second, run.iterations); items_per_second_stat += Stat1_d(run.items_per_second, run.iterations);
bytes_per_second_stat += Stat1_d(run.bytes_per_second, run.iterations); bytes_per_second_stat += Stat1_d(run.bytes_per_second, run.iterations);
} }
...@@ -204,10 +190,10 @@ std::vector<BenchmarkReporter::Run> ComputeStats( ...@@ -204,10 +190,10 @@ std::vector<BenchmarkReporter::Run> ComputeStats(
Run mean_data; Run mean_data;
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 =
run_iterations; real_accumulated_time_stat.Mean() * run_iterations;
mean_data.cpu_accumulated_time = cpu_accumulated_time_stat.Mean() * mean_data.cpu_accumulated_time =
run_iterations; cpu_accumulated_time_stat.Mean() * 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();
...@@ -224,10 +210,8 @@ std::vector<BenchmarkReporter::Run> ComputeStats( ...@@ -224,10 +210,8 @@ std::vector<BenchmarkReporter::Run> ComputeStats(
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 = cpu_accumulated_time_stat.StdDev();
stddev_data.cpu_accumulated_time =
cpu_accumulated_time_stat.StdDev();
stddev_data.bytes_per_second = bytes_per_second_stat.StdDev(); stddev_data.bytes_per_second = bytes_per_second_stat.StdDev();
stddev_data.items_per_second = items_per_second_stat.StdDev(); stddev_data.items_per_second = items_per_second_stat.StdDev();
...@@ -237,8 +221,7 @@ std::vector<BenchmarkReporter::Run> ComputeStats( ...@@ -237,8 +221,7 @@ std::vector<BenchmarkReporter::Run> ComputeStats(
} }
std::vector<BenchmarkReporter::Run> ComputeBigO( std::vector<BenchmarkReporter::Run> ComputeBigO(
const std::vector<BenchmarkReporter::Run>& reports) const std::vector<BenchmarkReporter::Run>& reports) {
{
typedef BenchmarkReporter::Run Run; typedef BenchmarkReporter::Run Run;
std::vector<Run> results; std::vector<Run> results;
...@@ -252,19 +235,22 @@ std::vector<BenchmarkReporter::Run> ComputeBigO( ...@@ -252,19 +235,22 @@ std::vector<BenchmarkReporter::Run> ComputeBigO(
// Populate the accumulators. // Populate the accumulators.
for (const Run& run : reports) { for (const Run& run : reports) {
n.push_back(run.complexity_n); n.push_back(run.complexity_n);
real_time.push_back(run.real_accumulated_time/run.iterations); real_time.push_back(run.real_accumulated_time / run.iterations);
cpu_time.push_back(run.cpu_accumulated_time/run.iterations); cpu_time.push_back(run.cpu_accumulated_time / run.iterations);
} }
LeastSq result_cpu = MinimalLeastSq(n, cpu_time, reports[0].complexity); LeastSq result_cpu;
LeastSq result_real;
// result_cpu.complexity is passed as parameter to result_real because in case
// reports[0].complexity is oAuto, the noise on the measured data could make
// the best fit function of Cpu and Real differ. In order to solve this, we
// take the best fitting function for the Cpu, and apply it to Real data.
LeastSq result_real = MinimalLeastSq(n, real_time, result_cpu.complexity);
std::string benchmark_name = reports[0].benchmark_name.substr(0, reports[0].benchmark_name.find('/')); 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 benchmark_name =
reports[0].benchmark_name.substr(0, reports[0].benchmark_name.find('/'));
// Get the data from the accumulator to BenchmarkReporter::Run's. // Get the data from the accumulator to BenchmarkReporter::Run's.
Run big_o; Run big_o;
......
...@@ -60,11 +60,5 @@ struct LeastSq { ...@@ -60,11 +60,5 @@ struct LeastSq {
// Function to return an string for the calculated complexity // Function to return an string for the calculated complexity
std::string GetBigOString(BigO complexity); std::string GetBigOString(BigO complexity);
// Find the coefficient for the high-order term in the running time, by
// minimizing the sum of squares of relative error.
LeastSq MinimalLeastSq(const std::vector<int>& n,
const std::vector<double>& time,
const BigO complexity = oAuto);
} // end namespace benchmark } // end namespace benchmark
#endif // COMPLEXITY_H_ #endif // COMPLEXITY_H_
...@@ -15,9 +15,9 @@ ...@@ -15,9 +15,9 @@
#include "benchmark/reporter.h" #include "benchmark/reporter.h"
#include "complexity.h" #include "complexity.h"
#include <algorithm>
#include <cstdint> #include <cstdint>
#include <cstdio> #include <cstdio>
#include <algorithm>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <tuple> #include <tuple>
...@@ -62,8 +62,8 @@ void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) { ...@@ -62,8 +62,8 @@ void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
void ConsoleReporter::PrintRunData(const Run& result) { void ConsoleReporter::PrintRunData(const Run& result) {
auto& Out = GetOutputStream(); auto& Out = GetOutputStream();
auto name_color = (result.report_big_o || result.report_rms) auto name_color =
? COLOR_BLUE : COLOR_GREEN; (result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN;
ColorPrintf(Out, name_color, "%-*s ", name_field_width_, ColorPrintf(Out, name_color, "%-*s ", name_field_width_,
result.benchmark_name.c_str()); result.benchmark_name.c_str());
...@@ -89,20 +89,20 @@ void ConsoleReporter::PrintRunData(const Run& result) { ...@@ -89,20 +89,20 @@ void ConsoleReporter::PrintRunData(const Run& result) {
const double real_time = result.GetAdjustedRealTime(); const double real_time = result.GetAdjustedRealTime();
const double cpu_time = result.GetAdjustedCPUTime(); const double cpu_time = result.GetAdjustedCPUTime();
if(result.report_big_o) { if (result.report_big_o) {
std::string big_o = result.report_big_o ? GetBigOString(result.complexity) : ""; std::string big_o = GetBigOString(result.complexity);
ColorPrintf(Out, COLOR_YELLOW, "%10.4f %s %10.4f %s ", ColorPrintf(Out, COLOR_YELLOW, "%10.2f %s %10.2f %s ", real_time,
real_time, big_o.c_str(), cpu_time, big_o.c_str()); big_o.c_str(), cpu_time, big_o.c_str());
} else if(result.report_rms) { } else if (result.report_rms) {
ColorPrintf(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ", ColorPrintf(Out, COLOR_YELLOW, "%10.0f %% %10.0f %% ", real_time * 100,
real_time * 100, cpu_time * 100); cpu_time * 100);
} else { } else {
const char* timeLabel = GetTimeUnitString(result.time_unit); const char* timeLabel = GetTimeUnitString(result.time_unit);
ColorPrintf(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ", ColorPrintf(Out, COLOR_YELLOW, "%10.0f %s %10.0f %s ", real_time, timeLabel,
real_time, timeLabel, cpu_time, timeLabel); cpu_time, timeLabel);
} }
if(!result.report_big_o && !result.report_rms) { if (!result.report_big_o && !result.report_rms) {
ColorPrintf(Out, COLOR_CYAN, "%10lld", result.iterations); ColorPrintf(Out, COLOR_CYAN, "%10lld", result.iterations);
} }
......
...@@ -13,9 +13,10 @@ ...@@ -13,9 +13,10 @@
// limitations under the License. // limitations under the License.
#include "benchmark/reporter.h" #include "benchmark/reporter.h"
#include "complexity.h"
#include <cstdint>
#include <algorithm> #include <algorithm>
#include <cstdint>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <tuple> #include <tuple>
...@@ -79,7 +80,7 @@ void CSVReporter::PrintRunData(const Run & run) { ...@@ -79,7 +80,7 @@ void CSVReporter::PrintRunData(const Run & run) {
} }
// Do not print iteration on bigO and RMS report // Do not print iteration on bigO and RMS report
if(!run.report_big_o && !run.report_rms) { if (!run.report_big_o && !run.report_rms) {
Out << run.iterations; Out << run.iterations;
} }
Out << ","; Out << ",";
...@@ -87,8 +88,10 @@ void CSVReporter::PrintRunData(const Run & run) { ...@@ -87,8 +88,10 @@ void CSVReporter::PrintRunData(const Run & run) {
Out << run.GetAdjustedRealTime() << ","; Out << run.GetAdjustedRealTime() << ",";
Out << run.GetAdjustedCPUTime() << ","; Out << run.GetAdjustedCPUTime() << ",";
// Do not print timeLabel on RMS report // Do not print timeLabel on bigO and RMS report
if(!run.report_rms) { if (run.report_big_o) {
Out << GetBigOString(run.complexity);
} else if (!run.report_rms) {
Out << GetTimeUnitString(run.time_unit); Out << GetTimeUnitString(run.time_unit);
} }
Out << ","; Out << ",";
......
...@@ -13,9 +13,10 @@ ...@@ -13,9 +13,10 @@
// limitations under the License. // limitations under the License.
#include "benchmark/reporter.h" #include "benchmark/reporter.h"
#include "complexity.h"
#include <cstdint>
#include <algorithm> #include <algorithm>
#include <cstdint>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <tuple> #include <tuple>
...@@ -128,30 +129,47 @@ void JSONReporter::PrintRunData(Run const& run) { ...@@ -128,30 +129,47 @@ void JSONReporter::PrintRunData(Run const& run) {
<< FormatKV("error_message", run.error_message) << FormatKV("error_message", run.error_message)
<< ",\n"; << ",\n";
} }
if(!run.report_big_o && !run.report_rms) { if (!run.report_big_o && !run.report_rms) {
out << indent out << indent
<< FormatKV("iterations", run.iterations) << FormatKV("iterations", run.iterations)
<< ",\n"; << ",\n";
}
out << indent out << indent
<< FormatKV("real_time", RoundDouble(run.GetAdjustedRealTime())) << FormatKV("real_time", RoundDouble(run.GetAdjustedRealTime()))
<< ",\n"; << ",\n";
out << indent out << indent
<< FormatKV("cpu_time", RoundDouble(run.GetAdjustedCPUTime())); << FormatKV("cpu_time", RoundDouble(run.GetAdjustedCPUTime()));
if(!run.report_rms) {
out << ",\n" << indent out << ",\n" << indent
<< FormatKV("time_unit", GetTimeUnitString(run.time_unit)); << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
} else if (run.report_big_o) {
out << indent
<< FormatKV("cpu_coefficient", RoundDouble(run.GetAdjustedCPUTime()))
<< ",\n";
out << indent
<< FormatKV("real_coefficient", RoundDouble(run.GetAdjustedRealTime()))
<< ",\n";
out << indent
<< FormatKV("big_o", GetBigOString(run.complexity))
<< ",\n";
out << indent
<< FormatKV("time_unit", GetTimeUnitString(run.time_unit));
} else if(run.report_rms) {
out << indent
<< FormatKV("rms", RoundDouble(run.GetAdjustedCPUTime()*100))
<< '%';
} }
if (run.bytes_per_second > 0.0) { if (run.bytes_per_second > 0.0) {
out << ",\n" << indent out << ",\n"
<< indent
<< FormatKV("bytes_per_second", RoundDouble(run.bytes_per_second)); << FormatKV("bytes_per_second", RoundDouble(run.bytes_per_second));
} }
if (run.items_per_second > 0.0) { if (run.items_per_second > 0.0) {
out << ",\n" << indent out << ",\n"
<< indent
<< FormatKV("items_per_second", RoundDouble(run.items_per_second)); << FormatKV("items_per_second", RoundDouble(run.items_per_second));
} }
if (!run.report_label.empty()) { if (!run.report_label.empty()) {
out << ",\n" << indent out << ",\n"
<< indent
<< FormatKV("label", run.report_label); << FormatKV("label", run.report_label);
} }
out << '\n'; out << '\n';
......
...@@ -189,7 +189,7 @@ void BM_Complexity_O1(benchmark::State& state) { ...@@ -189,7 +189,7 @@ void BM_Complexity_O1(benchmark::State& state) {
} }
BENCHMARK(BM_Complexity_O1)->Range(1, 1<<18)->Complexity(benchmark::o1); BENCHMARK(BM_Complexity_O1)->Range(1, 1<<18)->Complexity(benchmark::o1);
std::string bigOStr = "[0-9]+\\.[0-9]+ \\* [0-9]+"; std::string bigOStr = "[0-9]+\\.[0-9]+ \\([0-9]+\\)";
ADD_CASES(&ConsoleOutputTests, { ADD_CASES(&ConsoleOutputTests, {
{join("^BM_Complexity_O1_BigO", bigOStr, bigOStr) + "[ ]*$"}, {join("^BM_Complexity_O1_BigO", bigOStr, bigOStr) + "[ ]*$"},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment