1 // Copyright 2015 Google Inc. All rights reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <iomanip> // for setprecision
25 #include "benchmark/benchmark.h"
26 #include "complexity.h"
27 #include "string_util.h"
32 extern std::map
<std::string
, std::string
>* global_context
;
37 std::string
StrEscape(const std::string
& s
) {
39 tmp
.reserve(s
.size());
71 std::string
FormatKV(std::string
const& key
, std::string
const& value
) {
72 return StrFormat("\"%s\": \"%s\"", StrEscape(key
).c_str(),
73 StrEscape(value
).c_str());
76 std::string
FormatKV(std::string
const& key
, const char* value
) {
77 return StrFormat("\"%s\": \"%s\"", StrEscape(key
).c_str(),
78 StrEscape(value
).c_str());
81 std::string
FormatKV(std::string
const& key
, bool value
) {
82 return StrFormat("\"%s\": %s", StrEscape(key
).c_str(),
83 value
? "true" : "false");
86 std::string
FormatKV(std::string
const& key
, int64_t value
) {
88 ss
<< '"' << StrEscape(key
) << "\": " << value
;
92 std::string
FormatKV(std::string
const& key
, IterationCount value
) {
94 ss
<< '"' << StrEscape(key
) << "\": " << value
;
98 std::string
FormatKV(std::string
const& key
, double value
) {
100 ss
<< '"' << StrEscape(key
) << "\": ";
102 if (std::isnan(value
))
103 ss
<< (value
< 0 ? "-" : "") << "NaN";
104 else if (std::isinf(value
))
105 ss
<< (value
< 0 ? "-" : "") << "Infinity";
107 const auto max_digits10
=
108 std::numeric_limits
<decltype(value
)>::max_digits10
;
109 const auto max_fractional_digits10
= max_digits10
- 1;
110 ss
<< std::scientific
<< std::setprecision(max_fractional_digits10
)
116 int64_t RoundDouble(double v
) { return std::lround(v
); }
120 bool JSONReporter::ReportContext(const Context
& context
) {
121 std::ostream
& out
= GetOutputStream();
124 std::string
inner_indent(2, ' ');
126 // Open context block and print context information.
127 out
<< inner_indent
<< "\"context\": {\n";
128 std::string
indent(4, ' ');
130 std::string walltime_value
= LocalDateTimeString();
131 out
<< indent
<< FormatKV("date", walltime_value
) << ",\n";
133 out
<< indent
<< FormatKV("host_name", context
.sys_info
.name
) << ",\n";
135 if (Context::executable_name
) {
136 out
<< indent
<< FormatKV("executable", Context::executable_name
) << ",\n";
139 CPUInfo
const& info
= context
.cpu_info
;
140 out
<< indent
<< FormatKV("num_cpus", static_cast<int64_t>(info
.num_cpus
))
143 << FormatKV("mhz_per_cpu",
144 RoundDouble(info
.cycles_per_second
/ 1000000.0))
146 if (CPUInfo::Scaling::UNKNOWN
!= info
.scaling
) {
148 << FormatKV("cpu_scaling_enabled",
149 info
.scaling
== CPUInfo::Scaling::ENABLED
? true : false)
153 out
<< indent
<< "\"caches\": [\n";
154 indent
= std::string(6, ' ');
155 std::string
cache_indent(8, ' ');
156 for (size_t i
= 0; i
< info
.caches
.size(); ++i
) {
157 auto& CI
= info
.caches
[i
];
158 out
<< indent
<< "{\n";
159 out
<< cache_indent
<< FormatKV("type", CI
.type
) << ",\n";
160 out
<< cache_indent
<< FormatKV("level", static_cast<int64_t>(CI
.level
))
162 out
<< cache_indent
<< FormatKV("size", static_cast<int64_t>(CI
.size
))
165 << FormatKV("num_sharing", static_cast<int64_t>(CI
.num_sharing
))
167 out
<< indent
<< "}";
168 if (i
!= info
.caches
.size() - 1) out
<< ",";
171 indent
= std::string(4, ' ');
172 out
<< indent
<< "],\n";
173 out
<< indent
<< "\"load_avg\": [";
174 for (auto it
= info
.load_avg
.begin(); it
!= info
.load_avg
.end();) {
176 if (it
!= info
.load_avg
.end()) out
<< ",";
181 const char build_type
[] = "release";
183 const char build_type
[] = "debug";
185 out
<< indent
<< FormatKV("library_build_type", build_type
);
187 if (internal::global_context
!= nullptr) {
188 for (const auto& kv
: *internal::global_context
) {
190 out
<< indent
<< FormatKV(kv
.first
, kv
.second
);
195 // Close context block and open the list of benchmarks.
196 out
<< inner_indent
<< "},\n";
197 out
<< inner_indent
<< "\"benchmarks\": [\n";
201 void JSONReporter::ReportRuns(std::vector
<Run
> const& reports
) {
202 if (reports
.empty()) {
205 std::string
indent(4, ' ');
206 std::ostream
& out
= GetOutputStream();
207 if (!first_report_
) {
210 first_report_
= false;
212 for (auto it
= reports
.begin(); it
!= reports
.end(); ++it
) {
213 out
<< indent
<< "{\n";
215 out
<< indent
<< '}';
217 if (++it_cp
!= reports
.end()) {
223 void JSONReporter::Finalize() {
224 // Close the list of benchmarks and the top level object.
225 GetOutputStream() << "\n ]\n}\n";
228 void JSONReporter::PrintRunData(Run
const& run
) {
229 std::string
indent(6, ' ');
230 std::ostream
& out
= GetOutputStream();
231 out
<< indent
<< FormatKV("name", run
.benchmark_name()) << ",\n";
232 out
<< indent
<< FormatKV("family_index", run
.family_index
) << ",\n";
234 << FormatKV("per_family_instance_index", run
.per_family_instance_index
)
236 out
<< indent
<< FormatKV("run_name", run
.run_name
.str()) << ",\n";
237 out
<< indent
<< FormatKV("run_type", [&run
]() -> const char* {
238 switch (run
.run_type
) {
239 case BenchmarkReporter::Run::RT_Iteration
:
241 case BenchmarkReporter::Run::RT_Aggregate
:
244 BENCHMARK_UNREACHABLE();
246 out
<< indent
<< FormatKV("repetitions", run
.repetitions
) << ",\n";
247 if (run
.run_type
!= BenchmarkReporter::Run::RT_Aggregate
) {
248 out
<< indent
<< FormatKV("repetition_index", run
.repetition_index
)
251 out
<< indent
<< FormatKV("threads", run
.threads
) << ",\n";
252 if (run
.run_type
== BenchmarkReporter::Run::RT_Aggregate
) {
253 out
<< indent
<< FormatKV("aggregate_name", run
.aggregate_name
) << ",\n";
254 out
<< indent
<< FormatKV("aggregate_unit", [&run
]() -> const char* {
255 switch (run
.aggregate_unit
) {
256 case StatisticUnit::kTime
:
258 case StatisticUnit::kPercentage
:
261 BENCHMARK_UNREACHABLE();
264 if (run
.error_occurred
) {
265 out
<< indent
<< FormatKV("error_occurred", run
.error_occurred
) << ",\n";
266 out
<< indent
<< FormatKV("error_message", run
.error_message
) << ",\n";
268 if (!run
.report_big_o
&& !run
.report_rms
) {
269 out
<< indent
<< FormatKV("iterations", run
.iterations
) << ",\n";
270 if (run
.run_type
!= Run::RT_Aggregate
||
271 run
.aggregate_unit
== StatisticUnit::kTime
) {
272 out
<< indent
<< FormatKV("real_time", run
.GetAdjustedRealTime())
274 out
<< indent
<< FormatKV("cpu_time", run
.GetAdjustedCPUTime());
276 assert(run
.aggregate_unit
== StatisticUnit::kPercentage
);
277 out
<< indent
<< FormatKV("real_time", run
.real_accumulated_time
)
279 out
<< indent
<< FormatKV("cpu_time", run
.cpu_accumulated_time
);
282 << indent
<< FormatKV("time_unit", GetTimeUnitString(run
.time_unit
));
283 } else if (run
.report_big_o
) {
284 out
<< indent
<< FormatKV("cpu_coefficient", run
.GetAdjustedCPUTime())
286 out
<< indent
<< FormatKV("real_coefficient", run
.GetAdjustedRealTime())
288 out
<< indent
<< FormatKV("big_o", GetBigOString(run
.complexity
)) << ",\n";
289 out
<< indent
<< FormatKV("time_unit", GetTimeUnitString(run
.time_unit
));
290 } else if (run
.report_rms
) {
291 out
<< indent
<< FormatKV("rms", run
.GetAdjustedCPUTime());
294 for (auto& c
: run
.counters
) {
295 out
<< ",\n" << indent
<< FormatKV(c
.first
, c
.second
);
298 if (run
.memory_result
) {
299 const MemoryManager::Result memory_result
= *run
.memory_result
;
300 out
<< ",\n" << indent
<< FormatKV("allocs_per_iter", run
.allocs_per_iter
);
302 << indent
<< FormatKV("max_bytes_used", memory_result
.max_bytes_used
);
304 auto report_if_present
= [&out
, &indent
](const char* label
, int64_t val
) {
305 if (val
!= MemoryManager::TombstoneValue
)
306 out
<< ",\n" << indent
<< FormatKV(label
, val
);
309 report_if_present("total_allocated_bytes",
310 memory_result
.total_allocated_bytes
);
311 report_if_present("net_heap_growth", memory_result
.net_heap_growth
);
314 if (!run
.report_label
.empty()) {
315 out
<< ",\n" << indent
<< FormatKV("label", run
.report_label
);
320 const int64_t MemoryManager::TombstoneValue
=
321 std::numeric_limits
<int64_t>::max();
323 } // end namespace benchmark