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