Commit 7c69b360 by Kai Wolf

Add an additional parameter for time units

parent 3a02c462
...@@ -216,6 +216,13 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) { ...@@ -216,6 +216,13 @@ inline BENCHMARK_ALWAYS_INLINE void DoNotOptimize(Tp const& value) {
} }
#endif #endif
// TimeUnit is passed to a benchmark in order to specify the order of magnitude
// for the measured time.
enum TimeUnit {
kNanosecond,
kMicrosecond,
kMillisecond
};
// 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.
...@@ -390,6 +397,9 @@ public: ...@@ -390,6 +397,9 @@ public:
// REQUIRES: The function passed to the constructor must accept an arg1. // REQUIRES: The function passed to the constructor must accept an arg1.
Benchmark* Arg(int x); Benchmark* Arg(int x);
// Run this benchmark with the given time unit for the generated output report
Benchmark* Unit(TimeUnit unit);
// Run this benchmark once for a number of values picked from the // Run this benchmark once for a number of values picked from the
// range [start..limit]. (start and limit are always picked.) // range [start..limit]. (start and limit are always picked.)
// REQUIRES: The function passed to the constructor must accept an arg1. // REQUIRES: The function passed to the constructor must accept an arg1.
...@@ -534,6 +544,7 @@ protected: ...@@ -534,6 +544,7 @@ protected:
// Old-style macros // Old-style macros
#define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a)) #define BENCHMARK_WITH_ARG(n, a) BENCHMARK(n)->Arg((a))
#define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->ArgPair((a1), (a2)) #define BENCHMARK_WITH_ARG2(n, a1, a2) BENCHMARK(n)->ArgPair((a1), (a2))
#define BENCHMARK_WITH_UNIT(n, t) BENCHMARK(n)->Unit((t))
#define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi)) #define BENCHMARK_RANGE(n, lo, hi) BENCHMARK(n)->Range((lo), (hi))
#define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \ #define BENCHMARK_RANGE2(n, l1, h1, l2, h2) \
BENCHMARK(n)->RangePair((l1), (h1), (l2), (h2)) BENCHMARK(n)->RangePair((l1), (h1), (l2), (h2))
......
...@@ -36,13 +36,12 @@ class BenchmarkReporter { ...@@ -36,13 +36,12 @@ class BenchmarkReporter {
// The number of chars in the longest benchmark name. // The number of chars in the longest benchmark name.
size_t name_field_width; size_t name_field_width;
// The time unit for displayed execution time.
std::string time_unit;
}; };
struct Run { struct Run {
Run() : Run() :
iterations(1), iterations(1),
time_unit(kNanosecond),
real_accumulated_time(0), real_accumulated_time(0),
cpu_accumulated_time(0), cpu_accumulated_time(0),
bytes_per_second(0), bytes_per_second(0),
...@@ -52,6 +51,7 @@ class BenchmarkReporter { ...@@ -52,6 +51,7 @@ class BenchmarkReporter {
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.
int64_t iterations; int64_t iterations;
TimeUnit time_unit;
double real_accumulated_time; double real_accumulated_time;
double cpu_accumulated_time; double cpu_accumulated_time;
...@@ -86,17 +86,22 @@ protected: ...@@ -86,17 +86,22 @@ protected:
static void ComputeStats(std::vector<Run> const& reports, Run* mean, Run* stddev); static void ComputeStats(std::vector<Run> const& reports, Run* mean, Run* stddev);
}; };
typedef std::pair<const char*,double> TimeUnitMultiplier;
// Simple reporter that outputs benchmark data to the console. This is the // Simple reporter that outputs benchmark data to the console. This is the
// default reporter used by RunSpecifiedBenchmarks(). // default reporter used by RunSpecifiedBenchmarks().
class ConsoleReporter : public BenchmarkReporter { 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);
protected:
protected:
virtual void PrintRunData(const Run& report); virtual void PrintRunData(const Run& report);
private:
TimeUnitMultiplier getTimeUnitAndMultiplier(TimeUnit unit);
size_t name_field_width_; size_t name_field_width_;
std::string time_unit_;
}; };
class JSONReporter : public BenchmarkReporter { class JSONReporter : public BenchmarkReporter {
......
...@@ -64,10 +64,6 @@ DEFINE_int32(benchmark_repetitions, 1, ...@@ -64,10 +64,6 @@ DEFINE_int32(benchmark_repetitions, 1,
"The number of runs of each benchmark. If greater than 1, the " "The number of runs of each benchmark. If greater than 1, the "
"mean and standard deviation of the runs will be reported."); "mean and standard deviation of the runs will be reported.");
DEFINE_string(benchmark_time_unit, "ns",
"The time unit to use for console output. Valid values are "
"'ns', or 'ms'.");
DEFINE_string(benchmark_format, "tabular", DEFINE_string(benchmark_format, "tabular",
"The format to use for console output. Valid values are " "The format to use for console output. Valid values are "
"'tabular', 'json', or 'csv'."); "'tabular', 'json', or 'csv'.");
...@@ -265,6 +261,7 @@ struct Benchmark::Instance { ...@@ -265,6 +261,7 @@ struct Benchmark::Instance {
int arg1; int arg1;
bool has_arg2; bool has_arg2;
int arg2; int arg2;
TimeUnit time_unit;
bool use_real_time; bool use_real_time;
double min_time; double min_time;
int threads; // Number of concurrent threads to use int threads; // Number of concurrent threads to use
...@@ -298,6 +295,7 @@ public: ...@@ -298,6 +295,7 @@ public:
~BenchmarkImp(); ~BenchmarkImp();
void Arg(int x); void Arg(int x);
void Unit(TimeUnit unit);
void Range(int start, int limit); void Range(int start, int limit);
void DenseRange(int start, int limit); void DenseRange(int start, int limit);
void ArgPair(int start, int limit); void ArgPair(int start, int limit);
...@@ -317,6 +315,7 @@ private: ...@@ -317,6 +315,7 @@ private:
std::string name_; std::string name_;
int arg_count_; int arg_count_;
std::vector< std::pair<int, int> > args_; // Args for all benchmark runs std::vector< std::pair<int, int> > args_; // Args for all benchmark runs
TimeUnit time_unit_;
double min_time_; double min_time_;
bool use_real_time_; bool use_real_time_;
std::vector<int> thread_counts_; std::vector<int> thread_counts_;
...@@ -376,6 +375,7 @@ bool BenchmarkFamilies::FindBenchmarks( ...@@ -376,6 +375,7 @@ bool BenchmarkFamilies::FindBenchmarks(
instance.arg1 = args.first; instance.arg1 = args.first;
instance.has_arg2 = family->arg_count_ == 2; instance.has_arg2 = family->arg_count_ == 2;
instance.arg2 = args.second; instance.arg2 = args.second;
instance.time_unit = family->time_unit_;
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.threads = num_threads; instance.threads = num_threads;
...@@ -410,7 +410,7 @@ bool BenchmarkFamilies::FindBenchmarks( ...@@ -410,7 +410,7 @@ bool BenchmarkFamilies::FindBenchmarks(
} }
BenchmarkImp::BenchmarkImp(const char* name) BenchmarkImp::BenchmarkImp(const char* name)
: name_(name), arg_count_(-1), : name_(name), arg_count_(-1), time_unit_(kNanosecond),
min_time_(0.0), use_real_time_(false) { min_time_(0.0), use_real_time_(false) {
} }
...@@ -423,6 +423,10 @@ void BenchmarkImp::Arg(int x) { ...@@ -423,6 +423,10 @@ void BenchmarkImp::Arg(int x) {
args_.emplace_back(x, -1); args_.emplace_back(x, -1);
} }
void BenchmarkImp::Unit(TimeUnit unit) {
time_unit_ = unit;
}
void BenchmarkImp::Range(int start, int limit) { void BenchmarkImp::Range(int start, int limit) {
CHECK(arg_count_ == -1 || arg_count_ == 1); CHECK(arg_count_ == -1 || arg_count_ == 1);
arg_count_ = 1; arg_count_ = 1;
...@@ -535,6 +539,11 @@ Benchmark* Benchmark::Arg(int x) { ...@@ -535,6 +539,11 @@ Benchmark* Benchmark::Arg(int x) {
return this; return this;
} }
Benchmark* Benchmark::Unit(TimeUnit unit) {
imp_->Unit(unit);
return this;
}
Benchmark* Benchmark::Range(int start, int limit) { Benchmark* Benchmark::Range(int start, int limit) {
imp_->Range(start, limit); imp_->Range(start, limit);
return this; return this;
...@@ -703,6 +712,7 @@ void RunBenchmark(const benchmark::internal::Benchmark::Instance& b, ...@@ -703,6 +712,7 @@ void RunBenchmark(const benchmark::internal::Benchmark::Instance& b,
report.report_label = label; report.report_label = label;
// Report the total iterations across all threads. // Report the total iterations across all threads.
report.iterations = static_cast<int64_t>(iters) * b.threads; report.iterations = static_cast<int64_t>(iters) * b.threads;
report.time_unit = b.time_unit;
report.real_accumulated_time = real_accumulated_time; report.real_accumulated_time = real_accumulated_time;
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;
...@@ -783,7 +793,7 @@ void PrintBenchmarkList() { ...@@ -783,7 +793,7 @@ void PrintBenchmarkList() {
} }
} }
void RunMatchingBenchmarks(const std::string& spec, const std::string& timeUnit, void RunMatchingBenchmarks(const std::string& spec,
BenchmarkReporter* reporter) { BenchmarkReporter* reporter) {
CHECK(reporter != nullptr); CHECK(reporter != nullptr);
if (spec.empty()) return; if (spec.empty()) return;
...@@ -808,7 +818,6 @@ void RunMatchingBenchmarks(const std::string& spec, const std::string& timeUnit, ...@@ -808,7 +818,6 @@ void RunMatchingBenchmarks(const std::string& spec, const std::string& timeUnit,
context.cpu_scaling_enabled = CpuScalingEnabled(); context.cpu_scaling_enabled = CpuScalingEnabled();
context.name_field_width = name_field_width; context.name_field_width = name_field_width;
context.time_unit = timeUnit;
if (reporter->ReportContext(context)) { if (reporter->ReportContext(context)) {
for (const auto& benchmark : benchmarks) { for (const auto& benchmark : benchmarks) {
...@@ -843,7 +852,6 @@ void RunSpecifiedBenchmarks(BenchmarkReporter* reporter) { ...@@ -843,7 +852,6 @@ void RunSpecifiedBenchmarks(BenchmarkReporter* reporter) {
internal::PrintBenchmarkList(); internal::PrintBenchmarkList();
return; return;
} }
std::string timeUnit = FLAGS_benchmark_time_unit;
std::string spec = FLAGS_benchmark_filter; std::string spec = FLAGS_benchmark_filter;
if (spec.empty() || spec == "all") if (spec.empty() || spec == "all")
spec = "."; // Regexp that matches all benchmarks spec = "."; // Regexp that matches all benchmarks
...@@ -853,7 +861,7 @@ void RunSpecifiedBenchmarks(BenchmarkReporter* reporter) { ...@@ -853,7 +861,7 @@ void RunSpecifiedBenchmarks(BenchmarkReporter* reporter) {
default_reporter = internal::GetDefaultReporter(); default_reporter = internal::GetDefaultReporter();
reporter = default_reporter.get(); reporter = default_reporter.get();
} }
internal::RunMatchingBenchmarks(spec, timeUnit, reporter); internal::RunMatchingBenchmarks(spec, reporter);
reporter->Finalize(); reporter->Finalize();
} }
...@@ -866,7 +874,6 @@ void PrintUsageAndExit() { ...@@ -866,7 +874,6 @@ void PrintUsageAndExit() {
" [--benchmark_filter=<regex>]\n" " [--benchmark_filter=<regex>]\n"
" [--benchmark_min_time=<min_time>]\n" " [--benchmark_min_time=<min_time>]\n"
" [--benchmark_repetitions=<num_repetitions>]\n" " [--benchmark_repetitions=<num_repetitions>]\n"
" [--benchmark_time_unit=<ns|ms>]\n"
" [--benchmark_format=<tabular|json|csv>]\n" " [--benchmark_format=<tabular|json|csv>]\n"
" [--color_print={true|false}]\n" " [--color_print={true|false}]\n"
" [--v=<verbosity>]\n"); " [--v=<verbosity>]\n");
...@@ -885,8 +892,6 @@ void ParseCommandLineFlags(int* argc, char** argv) { ...@@ -885,8 +892,6 @@ void ParseCommandLineFlags(int* argc, char** argv) {
&FLAGS_benchmark_min_time) || &FLAGS_benchmark_min_time) ||
ParseInt32Flag(argv[i], "benchmark_repetitions", ParseInt32Flag(argv[i], "benchmark_repetitions",
&FLAGS_benchmark_repetitions) || &FLAGS_benchmark_repetitions) ||
ParseStringFlag(argv[i], "benchmark_time_unit",
&FLAGS_benchmark_time_unit) ||
ParseStringFlag(argv[i], "benchmark_format", ParseStringFlag(argv[i], "benchmark_format",
&FLAGS_benchmark_format) || &FLAGS_benchmark_format) ||
ParseBoolFlag(argv[i], "color_print", ParseBoolFlag(argv[i], "color_print",
...@@ -901,11 +906,6 @@ void ParseCommandLineFlags(int* argc, char** argv) { ...@@ -901,11 +906,6 @@ void ParseCommandLineFlags(int* argc, char** argv) {
} }
} }
if (FLAGS_benchmark_time_unit != "ns" &&
FLAGS_benchmark_time_unit != "ms") {
PrintUsageAndExit();
}
if (FLAGS_benchmark_format != "tabular" && if (FLAGS_benchmark_format != "tabular" &&
FLAGS_benchmark_format != "json" && FLAGS_benchmark_format != "json" &&
FLAGS_benchmark_format != "csv") { FLAGS_benchmark_format != "csv") {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <cstdio> #include <cstdio>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <tuple>
#include <vector> #include <vector>
#include "check.h" #include "check.h"
...@@ -29,7 +30,6 @@ namespace benchmark { ...@@ -29,7 +30,6 @@ namespace benchmark {
bool ConsoleReporter::ReportContext(const Context& context) { bool ConsoleReporter::ReportContext(const Context& context) {
name_field_width_ = context.name_field_width; name_field_width_ = context.name_field_width;
time_unit_ = context.time_unit;
std::cerr << "Run on (" << context.num_cpus << " X " << context.mhz_per_cpu std::cerr << "Run on (" << context.num_cpus << " X " << context.mhz_per_cpu
<< " MHz CPU " << ((context.num_cpus > 1) ? "s" : "") << ")\n"; << " MHz CPU " << ((context.num_cpus > 1) ? "s" : "") << ")\n";
...@@ -47,11 +47,9 @@ bool ConsoleReporter::ReportContext(const Context& context) { ...@@ -47,11 +47,9 @@ bool ConsoleReporter::ReportContext(const Context& context) {
"affected.\n"; "affected.\n";
#endif #endif
std::string timeLabel = "Time(" + time_unit_ + ")"; int output_width = fprintf(stdout, "%-*s %13s %13s %10s\n",
std::string cpuLabel = "CPU(" + time_unit_ + ")";
int output_width = fprintf(stdout, "%-*s %10s %10s %10s\n",
static_cast<int>(name_field_width_), "Benchmark", static_cast<int>(name_field_width_), "Benchmark",
timeLabel.c_str(), cpuLabel.c_str(), "Iterations"); "Time", "CPU", "Iterations");
std::cout << std::string(output_width - 1, '-') << "\n"; std::cout << std::string(output_width - 1, '-') << "\n";
return true; return true;
...@@ -95,21 +93,26 @@ void ConsoleReporter::PrintRunData(const Run& result) { ...@@ -95,21 +93,26 @@ void ConsoleReporter::PrintRunData(const Run& result) {
" items/s"); " items/s");
} }
double const multiplier = time_unit_ == "ns" ? 1e9 : 1e3; // nano second or double multiplier;
// millis multiplier const char* timeLabel;
std::tie(timeLabel, multiplier) = getTimeUnitAndMultiplier(result.time_unit);
ColorPrintf(COLOR_GREEN, "%-*s ", ColorPrintf(COLOR_GREEN, "%-*s ",
name_field_width_, result.benchmark_name.c_str()); name_field_width_, result.benchmark_name.c_str());
if (result.iterations == 0) { if (result.iterations == 0) {
ColorPrintf(COLOR_YELLOW, "%10.0f %10.0f ", ColorPrintf(COLOR_YELLOW, "%10.0f %s %10.0f %s ",
result.real_accumulated_time * multiplier, result.real_accumulated_time * multiplier,
result.cpu_accumulated_time * multiplier); timeLabel,
result.cpu_accumulated_time * multiplier,
timeLabel);
} else { } else {
ColorPrintf(COLOR_YELLOW, "%10.0f %10.0f ", ColorPrintf(COLOR_YELLOW, "%10.0f %s %10.0f %s ",
(result.real_accumulated_time * multiplier) / (result.real_accumulated_time * multiplier) /
(static_cast<double>(result.iterations)), (static_cast<double>(result.iterations)),
timeLabel,
(result.cpu_accumulated_time * multiplier) / (result.cpu_accumulated_time * multiplier) /
(static_cast<double>(result.iterations))); (static_cast<double>(result.iterations)),
timeLabel);
} }
ColorPrintf(COLOR_CYAN, "%10lld", result.iterations); ColorPrintf(COLOR_CYAN, "%10lld", result.iterations);
ColorPrintf(COLOR_DEFAULT, "%*s %*s %s\n", ColorPrintf(COLOR_DEFAULT, "%*s %*s %s\n",
...@@ -118,4 +121,16 @@ void ConsoleReporter::PrintRunData(const Run& result) { ...@@ -118,4 +121,16 @@ void ConsoleReporter::PrintRunData(const Run& result) {
result.report_label.c_str()); result.report_label.c_str());
} }
TimeUnitMultiplier ConsoleReporter::getTimeUnitAndMultiplier(TimeUnit unit) {
switch (unit) {
case kMillisecond:
return std::make_pair("ms", 1e3);
case kMicrosecond:
return std::make_pair("us", 1e6);
case kNanosecond:
default:
return std::make_pair("ns", 1e9);
}
}
} // end namespace benchmark } // end namespace benchmark
# Enable the tests # Enable the tests
# Allow the source files to find headers in src/
include_directories(${PROJECT_SOURCE_DIR}/src)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
set(CXX03_FLAGS "${CMAKE_CXX_FLAGS}") set(CXX03_FLAGS "${CMAKE_CXX_FLAGS}")
......
#include "benchmark/benchmark_api.h" #include "benchmark/benchmark_api.h"
#include "sleep.h"
void BM_basic(benchmark::State& state) { void BM_basic(benchmark::State& state) {
while (state.KeepRunning()) { while (state.KeepRunning()) {
} }
} }
void BM_basic_slow(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::SleepForMilliseconds(state.range_x());
}
}
BENCHMARK(BM_basic); BENCHMARK(BM_basic);
BENCHMARK(BM_basic)->Arg(42); BENCHMARK(BM_basic)->Arg(42);
BENCHMARK(BM_basic_slow)->Arg(10)->Unit(benchmark::kNanosecond);
BENCHMARK(BM_basic_slow)->Arg(100)->Unit(benchmark::kMicrosecond);
BENCHMARK(BM_basic_slow)->Arg(1000)->Unit(benchmark::kMillisecond);
BENCHMARK(BM_basic)->Range(1, 8); BENCHMARK(BM_basic)->Range(1, 8);
BENCHMARK(BM_basic)->DenseRange(10, 15); BENCHMARK(BM_basic)->DenseRange(10, 15);
BENCHMARK(BM_basic)->ArgPair(42, 42); BENCHMARK(BM_basic)->ArgPair(42, 42);
......
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