diff --git a/include/benchmark/reporter.h b/include/benchmark/reporter.h index 789124ba..8821ebfa 100644 --- a/include/benchmark/reporter.h +++ b/include/benchmark/reporter.h @@ -157,10 +157,17 @@ class BenchmarkReporter { // Simple reporter that outputs benchmark data to the console. This is the // default reporter used by RunSpecifiedBenchmarks(). class ConsoleReporter : public BenchmarkReporter { - public: - enum OutputOptions { OO_None, OO_Color }; - explicit ConsoleReporter(OutputOptions color_output = OO_Color) - : name_field_width_(0), color_output_(color_output == OO_Color) {} +public: + enum OutputOptions { + OO_None = 0, + OO_Color = 1, + OO_Tabular = 2, + OO_ColorTabular = OO_Color|OO_Tabular, + OO_Defaults = OO_ColorTabular + }; + explicit ConsoleReporter(OutputOptions opts_ = OO_Defaults) + : output_options_(opts_), name_field_width_(0), + prev_counters_(), printed_header_(false) {} virtual bool ReportContext(const Context& context); virtual void ReportRuns(const std::vector& reports); @@ -169,11 +176,10 @@ class ConsoleReporter : public BenchmarkReporter { virtual void PrintRunData(const Run& report); virtual void PrintHeader(const Run& report); + OutputOptions output_options_; size_t name_field_width_; + UserCounters prev_counters_; bool printed_header_; - - private: - bool color_output_; }; class JSONReporter : public BenchmarkReporter { diff --git a/src/benchmark.cc b/src/benchmark.cc index a93a83de..0638a160 100644 --- a/src/benchmark.cc +++ b/src/benchmark.cc @@ -91,6 +91,11 @@ DEFINE_string(benchmark_color, "auto", "environment variable is set to a terminal type that supports " "colors."); +DEFINE_bool(benchmark_counters_tabular, false, + "Whether to use tabular format when printing user counters to " + "the console. Valid values: 'true'/'yes'/1, 'false'/'no'/0." + "Defaults to false."); + DEFINE_int32(v, 0, "The level of verbose logging to output"); namespace benchmark { @@ -510,10 +515,10 @@ void RunBenchmarks(const std::vector& benchmarks, } std::unique_ptr CreateReporter( - std::string const& name, ConsoleReporter::OutputOptions allow_color) { + std::string const& name, ConsoleReporter::OutputOptions output_opts) { typedef std::unique_ptr PtrType; if (name == "console") { - return PtrType(new ConsoleReporter(allow_color)); + return PtrType(new ConsoleReporter(output_opts)); } else if (name == "json") { return PtrType(new JSONReporter); } else if (name == "csv") { @@ -546,16 +551,20 @@ size_t RunSpecifiedBenchmarks(BenchmarkReporter* console_reporter, std::unique_ptr default_console_reporter; std::unique_ptr default_file_reporter; if (!console_reporter) { - auto output_opts = ConsoleReporter::OO_None; - if (FLAGS_benchmark_color == "auto") - output_opts = IsColorTerminal() ? ConsoleReporter::OO_Color - : ConsoleReporter::OO_None; - else - output_opts = IsTruthyFlagValue(FLAGS_benchmark_color) - ? ConsoleReporter::OO_Color - : ConsoleReporter::OO_None; - default_console_reporter = - internal::CreateReporter(FLAGS_benchmark_format, output_opts); + int output_opts = ConsoleReporter::OO_Defaults; + if ((FLAGS_benchmark_color == "auto" && IsColorTerminal()) || + IsTruthyFlagValue(FLAGS_benchmark_color)) { + output_opts |= ConsoleReporter::OO_Color; + } else { + output_opts &= ~ConsoleReporter::OO_Color; + } + if(FLAGS_benchmark_counters_tabular) { + output_opts |= ConsoleReporter::OO_Tabular; + } else { + output_opts &= ~ConsoleReporter::OO_Tabular; + } + default_console_reporter = internal::CreateReporter( + FLAGS_benchmark_format, (ConsoleReporter::OutputOptions)output_opts); console_reporter = default_console_reporter.get(); } auto& Out = console_reporter->GetOutputStream(); @@ -614,6 +623,7 @@ void PrintUsageAndExit() { " [--benchmark_out=]\n" " [--benchmark_out_format=]\n" " [--benchmark_color={auto|true|false}]\n" + " [--benchmark_counters_tabular={true|false}]\n" " [--v=]\n"); exit(0); } @@ -638,6 +648,8 @@ void ParseCommandLineFlags(int* argc, char** argv) { // "color_print" is the deprecated name for "benchmark_color". // TODO: Remove this. ParseStringFlag(argv[i], "color_print", &FLAGS_benchmark_color) || + ParseBoolFlag(argv[i], "benchmark_counters_tabular", + &FLAGS_benchmark_counters_tabular) || ParseInt32Flag(argv[i], "v", &FLAGS_v)) { for (int j = i; j != *argc - 1; ++j) argv[j] = argv[j + 1]; diff --git a/src/console_reporter.cc b/src/console_reporter.cc index 3f3de029..da36a0ca 100644 --- a/src/console_reporter.cc +++ b/src/console_reporter.cc @@ -36,6 +36,7 @@ namespace benchmark { bool ConsoleReporter::ReportContext(const Context& context) { name_field_width_ = context.name_field_width; printed_header_ = false; + prev_counters_.clear(); PrintBasicContext(&GetErrorStream(), context); @@ -64,13 +65,21 @@ void ConsoleReporter::PrintHeader(const Run& run) { void ConsoleReporter::ReportRuns(const std::vector& reports) { for (const auto& run : reports) { - // print the header if none was printed yet - if (!printed_header_) { + // print the header: + // --- if none was printed yet + bool print_header = !printed_header_; + // --- or if the format is tabular and this run + // has different fields from the prev header + print_header |= (output_options_ & OO_Tabular) && + (!internal::SameNames(run.counters, prev_counters_)); + if (print_header) { printed_header_ = true; + prev_counters_ = run.counters; PrintHeader(run); } // As an alternative to printing the headers like this, we could sort - // the benchmarks by header and then print like that. + // the benchmarks by header and then print. But this would require + // waiting for the full results before printing, or printing twice. PrintRunData(run); } } @@ -86,8 +95,8 @@ static void IgnoreColorPrint(std::ostream& out, LogColor, const char* fmt, void ConsoleReporter::PrintRunData(const Run& result) { typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...); auto& Out = GetOutputStream(); - PrinterFn* printer = - color_output_ ? (PrinterFn*)ColorPrintf : IgnoreColorPrint; + PrinterFn* printer = (output_options_ & OO_Color) ? + (PrinterFn*)ColorPrintf : IgnoreColorPrint; auto name_color = (result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN; printer(Out, name_color, "%-*s ", name_field_width_, @@ -134,7 +143,11 @@ void ConsoleReporter::PrintRunData(const Run& result) { for (auto& c : result.counters) { auto const& s = HumanReadableNumber(c.second.value); - printer(Out, COLOR_DEFAULT, " %s=%s", c.first.c_str(), s.c_str()); + if(output_options_ & OO_Tabular) { + printer(Out, COLOR_DEFAULT, " %10s", s.c_str()); + } else { + printer(Out, COLOR_DEFAULT, " %s=%s", c.first.c_str(), s.c_str()); + } } if (!rate.empty()) { diff --git a/src/counter.cc b/src/counter.cc index 307863d3..8b0a8eeb 100644 --- a/src/counter.cc +++ b/src/counter.cc @@ -57,7 +57,7 @@ bool SameNames(UserCounters const& l, UserCounters const& r) { return false; } for (auto const& c : l) { - if ( r.find(c.first) == r.end()) { + if (r.find(c.first) == r.end()) { return false; } }