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