json_reporter.cc revision 525858e68797d053ab4c859528164974978162ba
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 "benchmark/reporter.h"
16
17#include <cstdint>
18#include <algorithm>
19#include <iostream>
20#include <string>
21#include <tuple>
22#include <vector>
23
24#include "string_util.h"
25#include "walltime.h"
26
27namespace benchmark {
28
29namespace {
30
31std::string FormatKV(std::string const& key, std::string const& value) {
32  return StringPrintF("\"%s\": \"%s\"", key.c_str(), value.c_str());
33}
34
35std::string FormatKV(std::string const& key, const char* value) {
36  return StringPrintF("\"%s\": \"%s\"", key.c_str(), value);
37}
38
39std::string FormatKV(std::string const& key, bool value) {
40  return StringPrintF("\"%s\": %s", key.c_str(), value ? "true" : "false");
41}
42
43std::string FormatKV(std::string const& key, int64_t value) {
44  std::stringstream ss;
45  ss << '"' << key << "\": " << value;
46  return ss.str();
47}
48
49int64_t RoundDouble(double v) {
50    return static_cast<int64_t>(v + 0.5);
51}
52
53} // end namespace
54
55bool JSONReporter::ReportContext(const Context& context) {
56  std::ostream& out = std::cout;
57
58  out << "{\n";
59  std::string inner_indent(2, ' ');
60
61  // Open context block and print context information.
62  out << inner_indent << "\"context\": {\n";
63  std::string indent(4, ' ');
64
65  std::string walltime_value = LocalDateTimeString();
66  out << indent << FormatKV("date", walltime_value) << ",\n";
67
68  out << indent
69      << FormatKV("num_cpus", static_cast<int64_t>(context.num_cpus))
70      << ",\n";
71  out << indent
72      << FormatKV("mhz_per_cpu", RoundDouble(context.mhz_per_cpu))
73      << ",\n";
74  out << indent
75      << FormatKV("cpu_scaling_enabled", context.cpu_scaling_enabled)
76      << ",\n";
77
78#if defined(NDEBUG)
79  const char build_type[] = "release";
80#else
81  const char build_type[] = "debug";
82#endif
83  out << indent << FormatKV("library_build_type", build_type) << "\n";
84  // Close context block and open the list of benchmarks.
85  out << inner_indent << "},\n";
86  out << inner_indent << "\"benchmarks\": [\n";
87  return true;
88}
89
90void JSONReporter::ReportRuns(std::vector<Run> const& reports) {
91  if (reports.empty()) {
92    return;
93  }
94  std::string indent(4, ' ');
95  std::ostream& out = std::cout;
96  if (!first_report_) {
97    out << ",\n";
98  }
99  first_report_ = false;
100
101  auto error_count = std::count_if(
102      reports.begin(), reports.end(),
103      [](Run const& run) {return run.error_occurred;});
104
105  std::vector<Run> reports_cp = reports;
106  if (reports.size() - error_count >= 2) {
107    Run mean_data;
108    Run stddev_data;
109    BenchmarkReporter::ComputeStats(reports, &mean_data, &stddev_data);
110    reports_cp.push_back(mean_data);
111    reports_cp.push_back(stddev_data);
112  }
113  for (auto it = reports_cp.begin(); it != reports_cp.end(); ++it) {
114     out << indent << "{\n";
115     PrintRunData(*it);
116     out << indent << '}';
117     auto it_cp = it;
118     if (++it_cp != reports_cp.end()) {
119         out << ",\n";
120     }
121  }
122}
123
124void JSONReporter::ReportComplexity(const std::vector<Run> & complexity_reports) {
125  if (complexity_reports.size() < 2) {
126    // We don't report asymptotic complexity data if there was a single run.
127    return;
128  }
129
130  std::string indent(4, ' ');
131  std::ostream& out = std::cout;
132  if (!first_report_) {
133    out << ",\n";
134  }
135
136  Run big_o_data;
137  Run rms_data;
138  BenchmarkReporter::ComputeBigO(complexity_reports, &big_o_data, &rms_data);
139
140  // Output using PrintRun.
141  out << indent << "{\n";
142  PrintRunData(big_o_data);
143  out << indent << "},\n";
144  out << indent << "{\n";
145  PrintRunData(rms_data);
146  out << indent << '}';
147}
148
149void JSONReporter::Finalize() {
150    // Close the list of benchmarks and the top level object.
151    std::cout << "\n  ]\n}\n";
152}
153
154void JSONReporter::PrintRunData(Run const& run) {
155    double multiplier;
156    const char* timeLabel;
157    std::tie(timeLabel, multiplier) = GetTimeUnitAndMultiplier(run.time_unit);
158
159    double cpu_time = run.cpu_accumulated_time * multiplier;
160    double real_time = run.real_accumulated_time * multiplier;
161    if (run.iterations != 0) {
162        real_time = real_time / static_cast<double>(run.iterations);
163        cpu_time = cpu_time / static_cast<double>(run.iterations);
164    }
165
166    std::string indent(6, ' ');
167    std::ostream& out = std::cout;
168    out << indent
169        << FormatKV("name", run.benchmark_name)
170        << ",\n";
171    if (run.error_occurred) {
172        out << indent
173            << FormatKV("error_occurred", run.error_occurred)
174            << ",\n";
175        out << indent
176            << FormatKV("error_message", run.error_message)
177            << ",\n";
178    }
179    out << indent
180        << FormatKV("iterations", run.iterations)
181        << ",\n";
182    if(!run.report_big_o && !run.report_rms) {
183        out << indent
184            << FormatKV("iterations", run.iterations)
185            << ",\n";
186    }
187    out << indent
188        << FormatKV("real_time", RoundDouble(real_time))
189        << ",\n";
190    out << indent
191        << FormatKV("cpu_time", RoundDouble(cpu_time));
192    if(!run.report_rms) {
193        out << ",\n" << indent
194            << FormatKV("time_unit", timeLabel);
195    }
196    if (run.bytes_per_second > 0.0) {
197        out << ",\n" << indent
198            << FormatKV("bytes_per_second", RoundDouble(run.bytes_per_second));
199    }
200    if (run.items_per_second > 0.0) {
201        out << ",\n" << indent
202            << FormatKV("items_per_second", RoundDouble(run.items_per_second));
203    }
204    if (!run.report_label.empty()) {
205        out << ",\n" << indent
206            << FormatKV("label", run.report_label);
207    }
208    out << '\n';
209}
210
211} // end namespace benchmark
212