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