| // Copyright 2015 Google Inc. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| #ifndef BENCHMARK_REPORTER_H_ |
| #define BENCHMARK_REPORTER_H_ |
| |
| #include <cassert> |
| #include <iosfwd> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| #include <set> |
| |
| #include "benchmark_api.h" // For forward declaration of BenchmarkReporter |
| |
| namespace benchmark { |
| |
| // Interface for custom benchmark result printers. |
| // By default, benchmark reports are printed to stdout. However an application |
| // can control the destination of the reports by calling |
| // RunSpecifiedBenchmarks and passing it a custom reporter object. |
| // The reporter object must implement the following interface. |
| class BenchmarkReporter { |
| public: |
| struct Context { |
| int num_cpus; |
| double mhz_per_cpu; |
| bool cpu_scaling_enabled; |
| |
| // The number of chars in the longest benchmark name. |
| size_t name_field_width; |
| }; |
| |
| struct Run { |
| Run() |
| : error_occurred(false), |
| iterations(1), |
| time_unit(kNanosecond), |
| real_accumulated_time(0), |
| cpu_accumulated_time(0), |
| bytes_per_second(0), |
| items_per_second(0), |
| max_heapbytes_used(0), |
| complexity(oNone), |
| complexity_lambda(), |
| complexity_n(0), |
| report_big_o(false), |
| report_rms(false), |
| counters() {} |
| |
| std::string benchmark_name; |
| std::string report_label; // Empty if not set by benchmark. |
| bool error_occurred; |
| std::string error_message; |
| |
| int64_t iterations; |
| TimeUnit time_unit; |
| double real_accumulated_time; |
| double cpu_accumulated_time; |
| |
| // Return a value representing the real time per iteration in the unit |
| // specified by 'time_unit'. |
| // NOTE: If 'iterations' is zero the returned value represents the |
| // accumulated time. |
| double GetAdjustedRealTime() const; |
| |
| // Return a value representing the cpu time per iteration in the unit |
| // specified by 'time_unit'. |
| // NOTE: If 'iterations' is zero the returned value represents the |
| // accumulated time. |
| double GetAdjustedCPUTime() const; |
| |
| // Zero if not set by benchmark. |
| double bytes_per_second; |
| double items_per_second; |
| |
| // This is set to 0.0 if memory tracing is not enabled. |
| double max_heapbytes_used; |
| |
| // Keep track of arguments to compute asymptotic complexity |
| BigO complexity; |
| BigOFunc* complexity_lambda; |
| int complexity_n; |
| |
| // Inform print function whether the current run is a complexity report |
| bool report_big_o; |
| bool report_rms; |
| |
| UserCounters counters; |
| }; |
| |
| // Construct a BenchmarkReporter with the output stream set to 'std::cout' |
| // and the error stream set to 'std::cerr' |
| BenchmarkReporter(); |
| |
| // Called once for every suite of benchmarks run. |
| // The parameter "context" contains information that the |
| // reporter may wish to use when generating its report, for example the |
| // platform under which the benchmarks are running. The benchmark run is |
| // never started if this function returns false, allowing the reporter |
| // to skip runs based on the context information. |
| virtual bool ReportContext(const Context& context) = 0; |
| |
| // Called once for each group of benchmark runs, gives information about |
| // cpu-time and heap memory usage during the benchmark run. If the group |
| // of runs contained more than two entries then 'report' contains additional |
| // elements representing the mean and standard deviation of those runs. |
| // Additionally if this group of runs was the last in a family of benchmarks |
| // 'reports' contains additional entries representing the asymptotic |
| // complexity and RMS of that benchmark family. |
| virtual void ReportRuns(const std::vector<Run>& report) = 0; |
| |
| // Called once and only once after ever group of benchmarks is run and |
| // reported. |
| virtual void Finalize() {} |
| |
| // REQUIRES: The object referenced by 'out' is valid for the lifetime |
| // of the reporter. |
| void SetOutputStream(std::ostream* out) { |
| assert(out); |
| output_stream_ = out; |
| } |
| |
| // REQUIRES: The object referenced by 'err' is valid for the lifetime |
| // of the reporter. |
| void SetErrorStream(std::ostream* err) { |
| assert(err); |
| error_stream_ = err; |
| } |
| |
| std::ostream& GetOutputStream() const { return *output_stream_; } |
| |
| std::ostream& GetErrorStream() const { return *error_stream_; } |
| |
| virtual ~BenchmarkReporter(); |
| |
| // Write a human readable string to 'out' representing the specified |
| // 'context'. |
| // REQUIRES: 'out' is non-null. |
| static void PrintBasicContext(std::ostream* out, Context const& context); |
| |
| private: |
| std::ostream* output_stream_; |
| std::ostream* error_stream_; |
| }; |
| |
| // 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 = 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<Run>& reports); |
| |
| protected: |
| 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_; |
| }; |
| |
| class JSONReporter : public BenchmarkReporter { |
| public: |
| JSONReporter() : first_report_(true) {} |
| virtual bool ReportContext(const Context& context); |
| virtual void ReportRuns(const std::vector<Run>& reports); |
| virtual void Finalize(); |
| |
| private: |
| void PrintRunData(const Run& report); |
| |
| bool first_report_; |
| }; |
| |
| class CSVReporter : public BenchmarkReporter { |
| public: |
| CSVReporter() : printed_header_(false) {} |
| virtual bool ReportContext(const Context& context); |
| virtual void ReportRuns(const std::vector<Run>& reports); |
| |
| private: |
| void PrintRunData(const Run& report); |
| |
| bool printed_header_; |
| std::set< std::string > user_counter_names_; |
| }; |
| |
| inline const char* GetTimeUnitString(TimeUnit unit) { |
| switch (unit) { |
| case kMillisecond: |
| return "ms"; |
| case kMicrosecond: |
| return "us"; |
| case kNanosecond: |
| default: |
| return "ns"; |
| } |
| } |
| |
| inline double GetTimeUnitMultiplier(TimeUnit unit) { |
| switch (unit) { |
| case kMillisecond: |
| return 1e3; |
| case kMicrosecond: |
| return 1e6; |
| case kNanosecond: |
| default: |
| return 1e9; |
| } |
| } |
| |
| } // end namespace benchmark |
| #endif // BENCHMARK_REPORTER_H_ |