1// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <algorithm>
16#include <cstdint>
17#include <cstdio>
18#include <cstring>
19#include <iostream>
20#include <string>
21#include <tuple>
22#include <vector>
23
24#include "benchmark/benchmark.h"
25#include "check.h"
26#include "colorprint.h"
27#include "commandlineflags.h"
28#include "complexity.h"
29#include "counter.h"
30#include "internal_macros.h"
31#include "string_util.h"
32#include "timers.h"
33
34namespace benchmark {
35
36bool ConsoleReporter::ReportContext(const Context& context) {
37 name_field_width_ = context.name_field_width;
38 printed_header_ = false;
39 prev_counters_.clear();
40
41 PrintBasicContext(&GetErrorStream(), context);
42
43#ifdef BENCHMARK_OS_WINDOWS
44 if ((output_options_ & OO_Color) && &std::cout != &GetOutputStream()) {
45 GetErrorStream()
46 << "Color printing is only supported for stdout on windows."
47 " Disabling color printing\n";
48 output_options_ = static_cast< OutputOptions >(output_options_ & ~OO_Color);
49 }
50#endif
51
52 return true;
53}
54
55void ConsoleReporter::PrintHeader(const Run& run) {
56 std::string str = FormatString("%-*s %13s %15s %12s", static_cast<int>(name_field_width_),
57 "Benchmark", "Time", "CPU", "Iterations");
58 if(!run.counters.empty()) {
59 if(output_options_ & OO_Tabular) {
60 for(auto const& c : run.counters) {
61 str += FormatString(" %10s", c.first.c_str());
62 }
63 } else {
64 str += " UserCounters...";
65 }
66 }
67 std::string line = std::string(str.length(), '-');
68 GetOutputStream() << line << "\n" << str << "\n" << line << "\n";
69}
70
71void ConsoleReporter::ReportRuns(const std::vector<Run>& reports) {
72 for (const auto& run : reports) {
73 // print the header:
74 // --- if none was printed yet
75 bool print_header = !printed_header_;
76 // --- or if the format is tabular and this run
77 // has different fields from the prev header
78 print_header |= (output_options_ & OO_Tabular) &&
79 (!internal::SameNames(run.counters, prev_counters_));
80 if (print_header) {
81 printed_header_ = true;
82 prev_counters_ = run.counters;
83 PrintHeader(run);
84 }
85 // As an alternative to printing the headers like this, we could sort
86 // the benchmarks by header and then print. But this would require
87 // waiting for the full results before printing, or printing twice.
88 PrintRunData(run);
89 }
90}
91
92static void IgnoreColorPrint(std::ostream& out, LogColor, const char* fmt,
93 ...) {
94 va_list args;
95 va_start(args, fmt);
96 out << FormatString(fmt, args);
97 va_end(args);
98}
99
100
101static std::string FormatTime(double time) {
102 // Align decimal places...
103 if (time < 1.0) {
104 return FormatString("%10.3f", time);
105 }
106 if (time < 10.0) {
107 return FormatString("%10.2f", time);
108 }
109 if (time < 100.0) {
110 return FormatString("%10.1f", time);
111 }
112 return FormatString("%10.0f", time);
113}
114
115void ConsoleReporter::PrintRunData(const Run& result) {
116 typedef void(PrinterFn)(std::ostream&, LogColor, const char*, ...);
117 auto& Out = GetOutputStream();
118 PrinterFn* printer = (output_options_ & OO_Color) ?
119 (PrinterFn*)ColorPrintf : IgnoreColorPrint;
120 auto name_color =
121 (result.report_big_o || result.report_rms) ? COLOR_BLUE : COLOR_GREEN;
122 printer(Out, name_color, "%-*s ", name_field_width_,
123 result.benchmark_name().c_str());
124
125 if (result.error_occurred) {
126 printer(Out, COLOR_RED, "ERROR OCCURRED: \'%s\'",
127 result.error_message.c_str());
128 printer(Out, COLOR_DEFAULT, "\n");
129 return;
130 }
131
132 const double real_time = result.GetAdjustedRealTime();
133 const double cpu_time = result.GetAdjustedCPUTime();
134 const std::string real_time_str = FormatTime(real_time);
135 const std::string cpu_time_str = FormatTime(cpu_time);
136
137
138 if (result.report_big_o) {
139 std::string big_o = GetBigOString(result.complexity);
140 printer(Out, COLOR_YELLOW, "%10.2f %-4s %10.2f %-4s ", real_time, big_o.c_str(),
141 cpu_time, big_o.c_str());
142 } else if (result.report_rms) {
143 printer(Out, COLOR_YELLOW, "%10.0f %-4s %10.0f %-4s ", real_time * 100, "%",
144 cpu_time * 100, "%");
145 } else {
146 const char* timeLabel = GetTimeUnitString(result.time_unit);
147 printer(Out, COLOR_YELLOW, "%s %-4s %s %-4s ", real_time_str.c_str(), timeLabel,
148 cpu_time_str.c_str(), timeLabel);
149 }
150
151 if (!result.report_big_o && !result.report_rms) {
152 printer(Out, COLOR_CYAN, "%10lld", result.iterations);
153 }
154
155 for (auto& c : result.counters) {
156 const std::size_t cNameLen = std::max(std::string::size_type(10),
157 c.first.length());
158 auto const& s = HumanReadableNumber(c.second.value, c.second.oneK);
159 const char* unit = "";
160 if (c.second.flags & Counter::kIsRate)
161 unit = (c.second.flags & Counter::kInvert) ? "s" : "/s";
162 if (output_options_ & OO_Tabular) {
163 printer(Out, COLOR_DEFAULT, " %*s%s", cNameLen - strlen(unit), s.c_str(),
164 unit);
165 } else {
166 printer(Out, COLOR_DEFAULT, " %s=%s%s", c.first.c_str(), s.c_str(), unit);
167 }
168 }
169
170 if (!result.report_label.empty()) {
171 printer(Out, COLOR_DEFAULT, " %s", result.report_label.c_str());
172 }
173
174 printer(Out, COLOR_DEFAULT, "\n");
175}
176
177} // end namespace benchmark
178