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 #ifndef BENCHMARK_REPORTER_H_
15 #define BENCHMARK_REPORTER_H_
16 
17 #include <cassert>
18 #include <iosfwd>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "benchmark_api.h"  // For forward declaration of BenchmarkReporter
24 
25 namespace benchmark {
26 
27 // Interface for custom benchmark result printers.
28 // By default, benchmark reports are printed to stdout. However an application
29 // can control the destination of the reports by calling
30 // RunSpecifiedBenchmarks and passing it a custom reporter object.
31 // The reporter object must implement the following interface.
32 class BenchmarkReporter {
33  public:
34   struct Context {
35     int num_cpus;
36     double mhz_per_cpu;
37     bool cpu_scaling_enabled;
38 
39     // The number of chars in the longest benchmark name.
40     size_t name_field_width;
41   };
42 
43   struct Run {
RunRun44     Run()
45         : error_occurred(false),
46           iterations(1),
47           time_unit(kNanosecond),
48           real_accumulated_time(0),
49           cpu_accumulated_time(0),
50           bytes_per_second(0),
51           items_per_second(0),
52           max_heapbytes_used(0),
53           complexity(oNone),
54           complexity_lambda(),
55           complexity_n(0),
56           report_big_o(false),
57           report_rms(false) {}
58 
59     std::string benchmark_name;
60     std::string report_label;  // Empty if not set by benchmark.
61     bool error_occurred;
62     std::string error_message;
63 
64     int64_t iterations;
65     TimeUnit time_unit;
66     double real_accumulated_time;
67     double cpu_accumulated_time;
68 
69     // Return a value representing the real time per iteration in the unit
70     // specified by 'time_unit'.
71     // NOTE: If 'iterations' is zero the returned value represents the
72     // accumulated time.
73     double GetAdjustedRealTime() const;
74 
75     // Return a value representing the cpu time per iteration in the unit
76     // specified by 'time_unit'.
77     // NOTE: If 'iterations' is zero the returned value represents the
78     // accumulated time.
79     double GetAdjustedCPUTime() const;
80 
81     // Zero if not set by benchmark.
82     double bytes_per_second;
83     double items_per_second;
84 
85     // This is set to 0.0 if memory tracing is not enabled.
86     double max_heapbytes_used;
87 
88     // Keep track of arguments to compute asymptotic complexity
89     BigO complexity;
90     BigOFunc* complexity_lambda;
91     int complexity_n;
92 
93     // Inform print function whether the current run is a complexity report
94     bool report_big_o;
95     bool report_rms;
96   };
97 
98   // Construct a BenchmarkReporter with the output stream set to 'std::cout'
99   // and the error stream set to 'std::cerr'
100   BenchmarkReporter();
101 
102   // Called once for every suite of benchmarks run.
103   // The parameter "context" contains information that the
104   // reporter may wish to use when generating its report, for example the
105   // platform under which the benchmarks are running. The benchmark run is
106   // never started if this function returns false, allowing the reporter
107   // to skip runs based on the context information.
108   virtual bool ReportContext(const Context& context) = 0;
109 
110   // Called once for each group of benchmark runs, gives information about
111   // cpu-time and heap memory usage during the benchmark run. If the group
112   // of runs contained more than two entries then 'report' contains additional
113   // elements representing the mean and standard deviation of those runs.
114   // Additionally if this group of runs was the last in a family of benchmarks
115   // 'reports' contains additional entries representing the asymptotic
116   // complexity and RMS of that benchmark family.
117   virtual void ReportRuns(const std::vector<Run>& report) = 0;
118 
119   // Called once and only once after ever group of benchmarks is run and
120   // reported.
Finalize()121   virtual void Finalize() {}
122 
123   // REQUIRES: The object referenced by 'out' is valid for the lifetime
124   // of the reporter.
SetOutputStream(std::ostream * out)125   void SetOutputStream(std::ostream* out) {
126     assert(out);
127     output_stream_ = out;
128   }
129 
130   // REQUIRES: The object referenced by 'err' is valid for the lifetime
131   // of the reporter.
SetErrorStream(std::ostream * err)132   void SetErrorStream(std::ostream* err) {
133     assert(err);
134     error_stream_ = err;
135   }
136 
GetOutputStream()137   std::ostream& GetOutputStream() const { return *output_stream_; }
138 
GetErrorStream()139   std::ostream& GetErrorStream() const { return *error_stream_; }
140 
141   virtual ~BenchmarkReporter();
142 
143   // Write a human readable string to 'out' representing the specified
144   // 'context'.
145   // REQUIRES: 'out' is non-null.
146   static void PrintBasicContext(std::ostream* out, Context const& context);
147 
148  private:
149   std::ostream* output_stream_;
150   std::ostream* error_stream_;
151 };
152 
153 // Simple reporter that outputs benchmark data to the console. This is the
154 // default reporter used by RunSpecifiedBenchmarks().
155 class ConsoleReporter : public BenchmarkReporter {
156  public:
157   enum OutputOptions { OO_None, OO_Color };
158   explicit ConsoleReporter(OutputOptions color_output = OO_Color)
159       : name_field_width_(0), color_output_(color_output == OO_Color) {}
160 
161   virtual bool ReportContext(const Context& context);
162   virtual void ReportRuns(const std::vector<Run>& reports);
163 
164  protected:
165   virtual void PrintRunData(const Run& report);
166   size_t name_field_width_;
167 
168  private:
169   bool color_output_;
170 };
171 
172 class JSONReporter : public BenchmarkReporter {
173  public:
JSONReporter()174   JSONReporter() : first_report_(true) {}
175   virtual bool ReportContext(const Context& context);
176   virtual void ReportRuns(const std::vector<Run>& reports);
177   virtual void Finalize();
178 
179  private:
180   void PrintRunData(const Run& report);
181 
182   bool first_report_;
183 };
184 
185 class CSVReporter : public BenchmarkReporter {
186  public:
187   virtual bool ReportContext(const Context& context);
188   virtual void ReportRuns(const std::vector<Run>& reports);
189 
190  private:
191   void PrintRunData(const Run& report);
192 };
193 
GetTimeUnitString(TimeUnit unit)194 inline const char* GetTimeUnitString(TimeUnit unit) {
195   switch (unit) {
196     case kMillisecond:
197       return "ms";
198     case kMicrosecond:
199       return "us";
200     case kNanosecond:
201     default:
202       return "ns";
203   }
204 }
205 
GetTimeUnitMultiplier(TimeUnit unit)206 inline double GetTimeUnitMultiplier(TimeUnit unit) {
207   switch (unit) {
208     case kMillisecond:
209       return 1e3;
210     case kMicrosecond:
211       return 1e6;
212     case kNanosecond:
213     default:
214       return 1e9;
215   }
216 }
217 
218 }  // end namespace benchmark
219 #endif  // BENCHMARK_REPORTER_H_
220