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.
15 #include "benchmark/benchmark.h"
16 #include "complexity.h"
24 #include <iomanip> // for setprecision
27 #include "string_util.h"
34 std::string
FormatKV(std::string
const& key
, std::string
const& value
) {
35 return StrFormat("\"%s\": \"%s\"", key
.c_str(), value
.c_str());
38 std::string
FormatKV(std::string
const& key
, const char* value
) {
39 return StrFormat("\"%s\": \"%s\"", key
.c_str(), value
);
42 std::string
FormatKV(std::string
const& key
, bool value
) {
43 return StrFormat("\"%s\": %s", key
.c_str(), value
? "true" : "false");
46 std::string
FormatKV(std::string
const& key
, int64_t value
) {
48 ss
<< '"' << key
<< "\": " << value
;
52 std::string
FormatKV(std::string
const& key
, double value
) {
54 ss
<< '"' << key
<< "\": ";
56 const auto max_digits10
= std::numeric_limits
<decltype (value
)>::max_digits10
;
57 const auto max_fractional_digits10
= max_digits10
- 1;
59 ss
<< std::scientific
<< std::setprecision(max_fractional_digits10
) << value
;
63 int64_t RoundDouble(double v
) { return static_cast<int64_t>(v
+ 0.5); }
67 bool JSONReporter::ReportContext(const Context
& context
) {
68 std::ostream
& out
= GetOutputStream();
71 std::string
inner_indent(2, ' ');
73 // Open context block and print context information.
74 out
<< inner_indent
<< "\"context\": {\n";
75 std::string
indent(4, ' ');
77 std::string walltime_value
= LocalDateTimeString();
78 out
<< indent
<< FormatKV("date", walltime_value
) << ",\n";
80 if (Context::executable_name
) {
81 out
<< indent
<< FormatKV("executable", Context::executable_name
) << ",\n";
84 CPUInfo
const& info
= context
.cpu_info
;
85 out
<< indent
<< FormatKV("num_cpus", static_cast<int64_t>(info
.num_cpus
))
88 << FormatKV("mhz_per_cpu",
89 RoundDouble(info
.cycles_per_second
/ 1000000.0))
91 out
<< indent
<< FormatKV("cpu_scaling_enabled", info
.scaling_enabled
)
94 out
<< indent
<< "\"caches\": [\n";
95 indent
= std::string(6, ' ');
96 std::string
cache_indent(8, ' ');
97 for (size_t i
= 0; i
< info
.caches
.size(); ++i
) {
98 auto& CI
= info
.caches
[i
];
99 out
<< indent
<< "{\n";
100 out
<< cache_indent
<< FormatKV("type", CI
.type
) << ",\n";
101 out
<< cache_indent
<< FormatKV("level", static_cast<int64_t>(CI
.level
))
104 << FormatKV("size", static_cast<int64_t>(CI
.size
) * 1000u) << ",\n";
106 << FormatKV("num_sharing", static_cast<int64_t>(CI
.num_sharing
))
108 out
<< indent
<< "}";
109 if (i
!= info
.caches
.size() - 1) out
<< ",";
112 indent
= std::string(4, ' ');
113 out
<< indent
<< "],\n";
116 const char build_type
[] = "release";
118 const char build_type
[] = "debug";
120 out
<< indent
<< FormatKV("library_build_type", build_type
) << "\n";
121 // Close context block and open the list of benchmarks.
122 out
<< inner_indent
<< "},\n";
123 out
<< inner_indent
<< "\"benchmarks\": [\n";
127 void JSONReporter::ReportRuns(std::vector
<Run
> const& reports
) {
128 if (reports
.empty()) {
131 std::string
indent(4, ' ');
132 std::ostream
& out
= GetOutputStream();
133 if (!first_report_
) {
136 first_report_
= false;
138 for (auto it
= reports
.begin(); it
!= reports
.end(); ++it
) {
139 out
<< indent
<< "{\n";
141 out
<< indent
<< '}';
143 if (++it_cp
!= reports
.end()) {
149 void JSONReporter::Finalize() {
150 // Close the list of benchmarks and the top level object.
151 GetOutputStream() << "\n ]\n}\n";
154 void JSONReporter::PrintRunData(Run
const& run
) {
155 std::string
indent(6, ' ');
156 std::ostream
& out
= GetOutputStream();
157 out
<< indent
<< FormatKV("name", run
.benchmark_name
) << ",\n";
158 if (run
.error_occurred
) {
159 out
<< indent
<< FormatKV("error_occurred", run
.error_occurred
) << ",\n";
160 out
<< indent
<< FormatKV("error_message", run
.error_message
) << ",\n";
162 if (!run
.report_big_o
&& !run
.report_rms
) {
163 out
<< indent
<< FormatKV("iterations", run
.iterations
) << ",\n";
165 << FormatKV("real_time", run
.GetAdjustedRealTime())
168 << FormatKV("cpu_time", run
.GetAdjustedCPUTime());
170 << indent
<< FormatKV("time_unit", GetTimeUnitString(run
.time_unit
));
171 } else if (run
.report_big_o
) {
173 << FormatKV("cpu_coefficient", run
.GetAdjustedCPUTime())
176 << FormatKV("real_coefficient", run
.GetAdjustedRealTime())
178 out
<< indent
<< FormatKV("big_o", GetBigOString(run
.complexity
)) << ",\n";
179 out
<< indent
<< FormatKV("time_unit", GetTimeUnitString(run
.time_unit
));
180 } else if (run
.report_rms
) {
182 << FormatKV("rms", run
.GetAdjustedCPUTime());
184 if (run
.bytes_per_second
> 0.0) {
187 << FormatKV("bytes_per_second", run
.bytes_per_second
);
189 if (run
.items_per_second
> 0.0) {
192 << FormatKV("items_per_second", run
.items_per_second
);
194 for(auto &c
: run
.counters
) {
197 << FormatKV(c
.first
, c
.second
);
199 if (!run
.report_label
.empty()) {
200 out
<< ",\n" << indent
<< FormatKV("label", run
.report_label
);
205 } // end namespace benchmark