1a8c51b3fSopenharmony_ci// Copyright 2015 Google Inc. All rights reserved.
2a8c51b3fSopenharmony_ci//
3a8c51b3fSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License");
4a8c51b3fSopenharmony_ci// you may not use this file except in compliance with the License.
5a8c51b3fSopenharmony_ci// You may obtain a copy of the License at
6a8c51b3fSopenharmony_ci//
7a8c51b3fSopenharmony_ci//     http://www.apache.org/licenses/LICENSE-2.0
8a8c51b3fSopenharmony_ci//
9a8c51b3fSopenharmony_ci// Unless required by applicable law or agreed to in writing, software
10a8c51b3fSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS,
11a8c51b3fSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12a8c51b3fSopenharmony_ci// See the License for the specific language governing permissions and
13a8c51b3fSopenharmony_ci// limitations under the License.
14a8c51b3fSopenharmony_ci
15a8c51b3fSopenharmony_ci#include <algorithm>
16a8c51b3fSopenharmony_ci#include <cmath>
17a8c51b3fSopenharmony_ci#include <cstdint>
18a8c51b3fSopenharmony_ci#include <iomanip>  // for setprecision
19a8c51b3fSopenharmony_ci#include <iostream>
20a8c51b3fSopenharmony_ci#include <limits>
21a8c51b3fSopenharmony_ci#include <string>
22a8c51b3fSopenharmony_ci#include <tuple>
23a8c51b3fSopenharmony_ci#include <vector>
24a8c51b3fSopenharmony_ci
25a8c51b3fSopenharmony_ci#include "benchmark/benchmark.h"
26a8c51b3fSopenharmony_ci#include "complexity.h"
27a8c51b3fSopenharmony_ci#include "string_util.h"
28a8c51b3fSopenharmony_ci#include "timers.h"
29a8c51b3fSopenharmony_ci
30a8c51b3fSopenharmony_cinamespace benchmark {
31a8c51b3fSopenharmony_cinamespace {
32a8c51b3fSopenharmony_ci
33a8c51b3fSopenharmony_cistd::string StrEscape(const std::string& s) {
34a8c51b3fSopenharmony_ci  std::string tmp;
35a8c51b3fSopenharmony_ci  tmp.reserve(s.size());
36a8c51b3fSopenharmony_ci  for (char c : s) {
37a8c51b3fSopenharmony_ci    switch (c) {
38a8c51b3fSopenharmony_ci      case '\b':
39a8c51b3fSopenharmony_ci        tmp += "\\b";
40a8c51b3fSopenharmony_ci        break;
41a8c51b3fSopenharmony_ci      case '\f':
42a8c51b3fSopenharmony_ci        tmp += "\\f";
43a8c51b3fSopenharmony_ci        break;
44a8c51b3fSopenharmony_ci      case '\n':
45a8c51b3fSopenharmony_ci        tmp += "\\n";
46a8c51b3fSopenharmony_ci        break;
47a8c51b3fSopenharmony_ci      case '\r':
48a8c51b3fSopenharmony_ci        tmp += "\\r";
49a8c51b3fSopenharmony_ci        break;
50a8c51b3fSopenharmony_ci      case '\t':
51a8c51b3fSopenharmony_ci        tmp += "\\t";
52a8c51b3fSopenharmony_ci        break;
53a8c51b3fSopenharmony_ci      case '\\':
54a8c51b3fSopenharmony_ci        tmp += "\\\\";
55a8c51b3fSopenharmony_ci        break;
56a8c51b3fSopenharmony_ci      case '"':
57a8c51b3fSopenharmony_ci        tmp += "\\\"";
58a8c51b3fSopenharmony_ci        break;
59a8c51b3fSopenharmony_ci      default:
60a8c51b3fSopenharmony_ci        tmp += c;
61a8c51b3fSopenharmony_ci        break;
62a8c51b3fSopenharmony_ci    }
63a8c51b3fSopenharmony_ci  }
64a8c51b3fSopenharmony_ci  return tmp;
65a8c51b3fSopenharmony_ci}
66a8c51b3fSopenharmony_ci
67a8c51b3fSopenharmony_cistd::string FormatKV(std::string const& key, std::string const& value) {
68a8c51b3fSopenharmony_ci  return StrFormat("\"%s\": \"%s\"", StrEscape(key).c_str(),
69a8c51b3fSopenharmony_ci                   StrEscape(value).c_str());
70a8c51b3fSopenharmony_ci}
71a8c51b3fSopenharmony_ci
72a8c51b3fSopenharmony_cistd::string FormatKV(std::string const& key, const char* value) {
73a8c51b3fSopenharmony_ci  return StrFormat("\"%s\": \"%s\"", StrEscape(key).c_str(),
74a8c51b3fSopenharmony_ci                   StrEscape(value).c_str());
75a8c51b3fSopenharmony_ci}
76a8c51b3fSopenharmony_ci
77a8c51b3fSopenharmony_cistd::string FormatKV(std::string const& key, bool value) {
78a8c51b3fSopenharmony_ci  return StrFormat("\"%s\": %s", StrEscape(key).c_str(),
79a8c51b3fSopenharmony_ci                   value ? "true" : "false");
80a8c51b3fSopenharmony_ci}
81a8c51b3fSopenharmony_ci
82a8c51b3fSopenharmony_cistd::string FormatKV(std::string const& key, int64_t value) {
83a8c51b3fSopenharmony_ci  std::stringstream ss;
84a8c51b3fSopenharmony_ci  ss << '"' << StrEscape(key) << "\": " << value;
85a8c51b3fSopenharmony_ci  return ss.str();
86a8c51b3fSopenharmony_ci}
87a8c51b3fSopenharmony_ci
88a8c51b3fSopenharmony_cistd::string FormatKV(std::string const& key, double value) {
89a8c51b3fSopenharmony_ci  std::stringstream ss;
90a8c51b3fSopenharmony_ci  ss << '"' << StrEscape(key) << "\": ";
91a8c51b3fSopenharmony_ci
92a8c51b3fSopenharmony_ci  if (std::isnan(value))
93a8c51b3fSopenharmony_ci    ss << (value < 0 ? "-" : "") << "NaN";
94a8c51b3fSopenharmony_ci  else if (std::isinf(value))
95a8c51b3fSopenharmony_ci    ss << (value < 0 ? "-" : "") << "Infinity";
96a8c51b3fSopenharmony_ci  else {
97a8c51b3fSopenharmony_ci    const auto max_digits10 =
98a8c51b3fSopenharmony_ci        std::numeric_limits<decltype(value)>::max_digits10;
99a8c51b3fSopenharmony_ci    const auto max_fractional_digits10 = max_digits10 - 1;
100a8c51b3fSopenharmony_ci    ss << std::scientific << std::setprecision(max_fractional_digits10)
101a8c51b3fSopenharmony_ci       << value;
102a8c51b3fSopenharmony_ci  }
103a8c51b3fSopenharmony_ci  return ss.str();
104a8c51b3fSopenharmony_ci}
105a8c51b3fSopenharmony_ci
106a8c51b3fSopenharmony_ciint64_t RoundDouble(double v) { return std::lround(v); }
107a8c51b3fSopenharmony_ci
108a8c51b3fSopenharmony_ci}  // end namespace
109a8c51b3fSopenharmony_ci
110a8c51b3fSopenharmony_cibool JSONReporter::ReportContext(const Context& context) {
111a8c51b3fSopenharmony_ci  std::ostream& out = GetOutputStream();
112a8c51b3fSopenharmony_ci
113a8c51b3fSopenharmony_ci  out << "{\n";
114a8c51b3fSopenharmony_ci  std::string inner_indent(2, ' ');
115a8c51b3fSopenharmony_ci
116a8c51b3fSopenharmony_ci  // Open context block and print context information.
117a8c51b3fSopenharmony_ci  out << inner_indent << "\"context\": {\n";
118a8c51b3fSopenharmony_ci  std::string indent(4, ' ');
119a8c51b3fSopenharmony_ci
120a8c51b3fSopenharmony_ci  std::string walltime_value = LocalDateTimeString();
121a8c51b3fSopenharmony_ci  out << indent << FormatKV("date", walltime_value) << ",\n";
122a8c51b3fSopenharmony_ci
123a8c51b3fSopenharmony_ci  out << indent << FormatKV("host_name", context.sys_info.name) << ",\n";
124a8c51b3fSopenharmony_ci
125a8c51b3fSopenharmony_ci  if (Context::executable_name) {
126a8c51b3fSopenharmony_ci    out << indent << FormatKV("executable", Context::executable_name) << ",\n";
127a8c51b3fSopenharmony_ci  }
128a8c51b3fSopenharmony_ci
129a8c51b3fSopenharmony_ci  CPUInfo const& info = context.cpu_info;
130a8c51b3fSopenharmony_ci  out << indent << FormatKV("num_cpus", static_cast<int64_t>(info.num_cpus))
131a8c51b3fSopenharmony_ci      << ",\n";
132a8c51b3fSopenharmony_ci  out << indent
133a8c51b3fSopenharmony_ci      << FormatKV("mhz_per_cpu",
134a8c51b3fSopenharmony_ci                  RoundDouble(info.cycles_per_second / 1000000.0))
135a8c51b3fSopenharmony_ci      << ",\n";
136a8c51b3fSopenharmony_ci  if (CPUInfo::Scaling::UNKNOWN != info.scaling) {
137a8c51b3fSopenharmony_ci    out << indent
138a8c51b3fSopenharmony_ci        << FormatKV("cpu_scaling_enabled",
139a8c51b3fSopenharmony_ci                    info.scaling == CPUInfo::Scaling::ENABLED ? true : false)
140a8c51b3fSopenharmony_ci        << ",\n";
141a8c51b3fSopenharmony_ci  }
142a8c51b3fSopenharmony_ci
143a8c51b3fSopenharmony_ci  out << indent << "\"caches\": [\n";
144a8c51b3fSopenharmony_ci  indent = std::string(6, ' ');
145a8c51b3fSopenharmony_ci  std::string cache_indent(8, ' ');
146a8c51b3fSopenharmony_ci  for (size_t i = 0; i < info.caches.size(); ++i) {
147a8c51b3fSopenharmony_ci    auto& CI = info.caches[i];
148a8c51b3fSopenharmony_ci    out << indent << "{\n";
149a8c51b3fSopenharmony_ci    out << cache_indent << FormatKV("type", CI.type) << ",\n";
150a8c51b3fSopenharmony_ci    out << cache_indent << FormatKV("level", static_cast<int64_t>(CI.level))
151a8c51b3fSopenharmony_ci        << ",\n";
152a8c51b3fSopenharmony_ci    out << cache_indent << FormatKV("size", static_cast<int64_t>(CI.size))
153a8c51b3fSopenharmony_ci        << ",\n";
154a8c51b3fSopenharmony_ci    out << cache_indent
155a8c51b3fSopenharmony_ci        << FormatKV("num_sharing", static_cast<int64_t>(CI.num_sharing))
156a8c51b3fSopenharmony_ci        << "\n";
157a8c51b3fSopenharmony_ci    out << indent << "}";
158a8c51b3fSopenharmony_ci    if (i != info.caches.size() - 1) out << ",";
159a8c51b3fSopenharmony_ci    out << "\n";
160a8c51b3fSopenharmony_ci  }
161a8c51b3fSopenharmony_ci  indent = std::string(4, ' ');
162a8c51b3fSopenharmony_ci  out << indent << "],\n";
163a8c51b3fSopenharmony_ci  out << indent << "\"load_avg\": [";
164a8c51b3fSopenharmony_ci  for (auto it = info.load_avg.begin(); it != info.load_avg.end();) {
165a8c51b3fSopenharmony_ci    out << *it++;
166a8c51b3fSopenharmony_ci    if (it != info.load_avg.end()) out << ",";
167a8c51b3fSopenharmony_ci  }
168a8c51b3fSopenharmony_ci  out << "],\n";
169a8c51b3fSopenharmony_ci
170a8c51b3fSopenharmony_ci#if defined(NDEBUG)
171a8c51b3fSopenharmony_ci  const char build_type[] = "release";
172a8c51b3fSopenharmony_ci#else
173a8c51b3fSopenharmony_ci  const char build_type[] = "debug";
174a8c51b3fSopenharmony_ci#endif
175a8c51b3fSopenharmony_ci  out << indent << FormatKV("library_build_type", build_type);
176a8c51b3fSopenharmony_ci
177a8c51b3fSopenharmony_ci  std::map<std::string, std::string>* global_context =
178a8c51b3fSopenharmony_ci      internal::GetGlobalContext();
179a8c51b3fSopenharmony_ci
180a8c51b3fSopenharmony_ci  if (global_context != nullptr) {
181a8c51b3fSopenharmony_ci    for (const auto& kv : *global_context) {
182a8c51b3fSopenharmony_ci      out << ",\n";
183a8c51b3fSopenharmony_ci      out << indent << FormatKV(kv.first, kv.second);
184a8c51b3fSopenharmony_ci    }
185a8c51b3fSopenharmony_ci  }
186a8c51b3fSopenharmony_ci  out << "\n";
187a8c51b3fSopenharmony_ci
188a8c51b3fSopenharmony_ci  // Close context block and open the list of benchmarks.
189a8c51b3fSopenharmony_ci  out << inner_indent << "},\n";
190a8c51b3fSopenharmony_ci  out << inner_indent << "\"benchmarks\": [\n";
191a8c51b3fSopenharmony_ci  return true;
192a8c51b3fSopenharmony_ci}
193a8c51b3fSopenharmony_ci
194a8c51b3fSopenharmony_civoid JSONReporter::ReportRuns(std::vector<Run> const& reports) {
195a8c51b3fSopenharmony_ci  if (reports.empty()) {
196a8c51b3fSopenharmony_ci    return;
197a8c51b3fSopenharmony_ci  }
198a8c51b3fSopenharmony_ci  std::string indent(4, ' ');
199a8c51b3fSopenharmony_ci  std::ostream& out = GetOutputStream();
200a8c51b3fSopenharmony_ci  if (!first_report_) {
201a8c51b3fSopenharmony_ci    out << ",\n";
202a8c51b3fSopenharmony_ci  }
203a8c51b3fSopenharmony_ci  first_report_ = false;
204a8c51b3fSopenharmony_ci
205a8c51b3fSopenharmony_ci  for (auto it = reports.begin(); it != reports.end(); ++it) {
206a8c51b3fSopenharmony_ci    out << indent << "{\n";
207a8c51b3fSopenharmony_ci    PrintRunData(*it);
208a8c51b3fSopenharmony_ci    out << indent << '}';
209a8c51b3fSopenharmony_ci    auto it_cp = it;
210a8c51b3fSopenharmony_ci    if (++it_cp != reports.end()) {
211a8c51b3fSopenharmony_ci      out << ",\n";
212a8c51b3fSopenharmony_ci    }
213a8c51b3fSopenharmony_ci  }
214a8c51b3fSopenharmony_ci}
215a8c51b3fSopenharmony_ci
216a8c51b3fSopenharmony_civoid JSONReporter::Finalize() {
217a8c51b3fSopenharmony_ci  // Close the list of benchmarks and the top level object.
218a8c51b3fSopenharmony_ci  GetOutputStream() << "\n  ]\n}\n";
219a8c51b3fSopenharmony_ci}
220a8c51b3fSopenharmony_ci
221a8c51b3fSopenharmony_civoid JSONReporter::PrintRunData(Run const& run) {
222a8c51b3fSopenharmony_ci  std::string indent(6, ' ');
223a8c51b3fSopenharmony_ci  std::ostream& out = GetOutputStream();
224a8c51b3fSopenharmony_ci  out << indent << FormatKV("name", run.benchmark_name()) << ",\n";
225a8c51b3fSopenharmony_ci  out << indent << FormatKV("family_index", run.family_index) << ",\n";
226a8c51b3fSopenharmony_ci  out << indent
227a8c51b3fSopenharmony_ci      << FormatKV("per_family_instance_index", run.per_family_instance_index)
228a8c51b3fSopenharmony_ci      << ",\n";
229a8c51b3fSopenharmony_ci  out << indent << FormatKV("run_name", run.run_name.str()) << ",\n";
230a8c51b3fSopenharmony_ci  out << indent << FormatKV("run_type", [&run]() -> const char* {
231a8c51b3fSopenharmony_ci    switch (run.run_type) {
232a8c51b3fSopenharmony_ci      case BenchmarkReporter::Run::RT_Iteration:
233a8c51b3fSopenharmony_ci        return "iteration";
234a8c51b3fSopenharmony_ci      case BenchmarkReporter::Run::RT_Aggregate:
235a8c51b3fSopenharmony_ci        return "aggregate";
236a8c51b3fSopenharmony_ci    }
237a8c51b3fSopenharmony_ci    BENCHMARK_UNREACHABLE();
238a8c51b3fSopenharmony_ci  }()) << ",\n";
239a8c51b3fSopenharmony_ci  out << indent << FormatKV("repetitions", run.repetitions) << ",\n";
240a8c51b3fSopenharmony_ci  if (run.run_type != BenchmarkReporter::Run::RT_Aggregate) {
241a8c51b3fSopenharmony_ci    out << indent << FormatKV("repetition_index", run.repetition_index)
242a8c51b3fSopenharmony_ci        << ",\n";
243a8c51b3fSopenharmony_ci  }
244a8c51b3fSopenharmony_ci  out << indent << FormatKV("threads", run.threads) << ",\n";
245a8c51b3fSopenharmony_ci  if (run.run_type == BenchmarkReporter::Run::RT_Aggregate) {
246a8c51b3fSopenharmony_ci    out << indent << FormatKV("aggregate_name", run.aggregate_name) << ",\n";
247a8c51b3fSopenharmony_ci    out << indent << FormatKV("aggregate_unit", [&run]() -> const char* {
248a8c51b3fSopenharmony_ci      switch (run.aggregate_unit) {
249a8c51b3fSopenharmony_ci        case StatisticUnit::kTime:
250a8c51b3fSopenharmony_ci          return "time";
251a8c51b3fSopenharmony_ci        case StatisticUnit::kPercentage:
252a8c51b3fSopenharmony_ci          return "percentage";
253a8c51b3fSopenharmony_ci      }
254a8c51b3fSopenharmony_ci      BENCHMARK_UNREACHABLE();
255a8c51b3fSopenharmony_ci    }()) << ",\n";
256a8c51b3fSopenharmony_ci  }
257a8c51b3fSopenharmony_ci  if (internal::SkippedWithError == run.skipped) {
258a8c51b3fSopenharmony_ci    out << indent << FormatKV("error_occurred", true) << ",\n";
259a8c51b3fSopenharmony_ci    out << indent << FormatKV("error_message", run.skip_message) << ",\n";
260a8c51b3fSopenharmony_ci  } else if (internal::SkippedWithMessage == run.skipped) {
261a8c51b3fSopenharmony_ci    out << indent << FormatKV("skipped", true) << ",\n";
262a8c51b3fSopenharmony_ci    out << indent << FormatKV("skip_message", run.skip_message) << ",\n";
263a8c51b3fSopenharmony_ci  }
264a8c51b3fSopenharmony_ci  if (!run.report_big_o && !run.report_rms) {
265a8c51b3fSopenharmony_ci    out << indent << FormatKV("iterations", run.iterations) << ",\n";
266a8c51b3fSopenharmony_ci    if (run.run_type != Run::RT_Aggregate ||
267a8c51b3fSopenharmony_ci        run.aggregate_unit == StatisticUnit::kTime) {
268a8c51b3fSopenharmony_ci      out << indent << FormatKV("real_time", run.GetAdjustedRealTime())
269a8c51b3fSopenharmony_ci          << ",\n";
270a8c51b3fSopenharmony_ci      out << indent << FormatKV("cpu_time", run.GetAdjustedCPUTime());
271a8c51b3fSopenharmony_ci    } else {
272a8c51b3fSopenharmony_ci      assert(run.aggregate_unit == StatisticUnit::kPercentage);
273a8c51b3fSopenharmony_ci      out << indent << FormatKV("real_time", run.real_accumulated_time)
274a8c51b3fSopenharmony_ci          << ",\n";
275a8c51b3fSopenharmony_ci      out << indent << FormatKV("cpu_time", run.cpu_accumulated_time);
276a8c51b3fSopenharmony_ci    }
277a8c51b3fSopenharmony_ci    out << ",\n"
278a8c51b3fSopenharmony_ci        << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
279a8c51b3fSopenharmony_ci  } else if (run.report_big_o) {
280a8c51b3fSopenharmony_ci    out << indent << FormatKV("cpu_coefficient", run.GetAdjustedCPUTime())
281a8c51b3fSopenharmony_ci        << ",\n";
282a8c51b3fSopenharmony_ci    out << indent << FormatKV("real_coefficient", run.GetAdjustedRealTime())
283a8c51b3fSopenharmony_ci        << ",\n";
284a8c51b3fSopenharmony_ci    out << indent << FormatKV("big_o", GetBigOString(run.complexity)) << ",\n";
285a8c51b3fSopenharmony_ci    out << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
286a8c51b3fSopenharmony_ci  } else if (run.report_rms) {
287a8c51b3fSopenharmony_ci    out << indent << FormatKV("rms", run.GetAdjustedCPUTime());
288a8c51b3fSopenharmony_ci  }
289a8c51b3fSopenharmony_ci
290a8c51b3fSopenharmony_ci  for (auto& c : run.counters) {
291a8c51b3fSopenharmony_ci    out << ",\n" << indent << FormatKV(c.first, c.second);
292a8c51b3fSopenharmony_ci  }
293a8c51b3fSopenharmony_ci
294a8c51b3fSopenharmony_ci  if (run.memory_result) {
295a8c51b3fSopenharmony_ci    const MemoryManager::Result memory_result = *run.memory_result;
296a8c51b3fSopenharmony_ci    out << ",\n" << indent << FormatKV("allocs_per_iter", run.allocs_per_iter);
297a8c51b3fSopenharmony_ci    out << ",\n"
298a8c51b3fSopenharmony_ci        << indent << FormatKV("max_bytes_used", memory_result.max_bytes_used);
299a8c51b3fSopenharmony_ci
300a8c51b3fSopenharmony_ci    auto report_if_present = [&out, &indent](const std::string& label,
301a8c51b3fSopenharmony_ci                                             int64_t val) {
302a8c51b3fSopenharmony_ci      if (val != MemoryManager::TombstoneValue)
303a8c51b3fSopenharmony_ci        out << ",\n" << indent << FormatKV(label, val);
304a8c51b3fSopenharmony_ci    };
305a8c51b3fSopenharmony_ci
306a8c51b3fSopenharmony_ci    report_if_present("total_allocated_bytes",
307a8c51b3fSopenharmony_ci                      memory_result.total_allocated_bytes);
308a8c51b3fSopenharmony_ci    report_if_present("net_heap_growth", memory_result.net_heap_growth);
309a8c51b3fSopenharmony_ci  }
310a8c51b3fSopenharmony_ci
311a8c51b3fSopenharmony_ci  if (!run.report_label.empty()) {
312a8c51b3fSopenharmony_ci    out << ",\n" << indent << FormatKV("label", run.report_label);
313a8c51b3fSopenharmony_ci  }
314a8c51b3fSopenharmony_ci  out << '\n';
315a8c51b3fSopenharmony_ci}
316a8c51b3fSopenharmony_ci
317a8c51b3fSopenharmony_ciconst int64_t MemoryManager::TombstoneValue =
318a8c51b3fSopenharmony_ci    std::numeric_limits<int64_t>::max();
319a8c51b3fSopenharmony_ci
320a8c51b3fSopenharmony_ci}  // end namespace benchmark
321