Home | History | Annotate | Download | only in src
      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/benchmark.h"
     16 #include "complexity.h"
     17 
     18 #include <algorithm>
     19 #include <cstdint>
     20 #include <iostream>
     21 #include <string>
     22 #include <tuple>
     23 #include <vector>
     24 #include <iomanip> // for setprecision
     25 #include <limits>
     26 
     27 #include "string_util.h"
     28 #include "timers.h"
     29 
     30 namespace benchmark {
     31 
     32 namespace {
     33 
     34 std::string FormatKV(std::string const& key, std::string const& value) {
     35   return StringPrintF("\"%s\": \"%s\"", key.c_str(), value.c_str());
     36 }
     37 
     38 std::string FormatKV(std::string const& key, const char* value) {
     39   return StringPrintF("\"%s\": \"%s\"", key.c_str(), value);
     40 }
     41 
     42 std::string FormatKV(std::string const& key, bool value) {
     43   return StringPrintF("\"%s\": %s", key.c_str(), value ? "true" : "false");
     44 }
     45 
     46 std::string FormatKV(std::string const& key, int64_t value) {
     47   std::stringstream ss;
     48   ss << '"' << key << "\": " << value;
     49   return ss.str();
     50 }
     51 
     52 std::string FormatKV(std::string const& key, double value) {
     53   std::stringstream ss;
     54   ss << '"' << key << "\": ";
     55 
     56   const auto max_digits10 = std::numeric_limits<decltype (value)>::max_digits10;
     57   const auto max_fractional_digits10 = max_digits10 - 1;
     58 
     59   ss << std::scientific << std::setprecision(max_fractional_digits10) << value;
     60   return ss.str();
     61 }
     62 
     63 int64_t RoundDouble(double v) { return static_cast<int64_t>(v + 0.5); }
     64 
     65 }  // end namespace
     66 
     67 bool JSONReporter::ReportContext(const Context& context) {
     68   std::ostream& out = GetOutputStream();
     69 
     70   out << "{\n";
     71   std::string inner_indent(2, ' ');
     72 
     73   // Open context block and print context information.
     74   out << inner_indent << "\"context\": {\n";
     75   std::string indent(4, ' ');
     76 
     77   std::string walltime_value = LocalDateTimeString();
     78   out << indent << FormatKV("date", walltime_value) << ",\n";
     79 
     80   CPUInfo const& info = context.cpu_info;
     81   out << indent << FormatKV("num_cpus", static_cast<int64_t>(info.num_cpus))
     82       << ",\n";
     83   out << indent
     84       << FormatKV("mhz_per_cpu",
     85                   RoundDouble(info.cycles_per_second / 1000000.0))
     86       << ",\n";
     87   out << indent << FormatKV("cpu_scaling_enabled", info.scaling_enabled)
     88       << ",\n";
     89 
     90   out << indent << "\"caches\": [\n";
     91   indent = std::string(6, ' ');
     92   std::string cache_indent(8, ' ');
     93   for (size_t i = 0; i < info.caches.size(); ++i) {
     94     auto& CI = info.caches[i];
     95     out << indent << "{\n";
     96     out << cache_indent << FormatKV("type", CI.type) << ",\n";
     97     out << cache_indent << FormatKV("level", static_cast<int64_t>(CI.level))
     98         << ",\n";
     99     out << cache_indent
    100         << FormatKV("size", static_cast<int64_t>(CI.size) * 1000u) << ",\n";
    101     out << cache_indent
    102         << FormatKV("num_sharing", static_cast<int64_t>(CI.num_sharing))
    103         << "\n";
    104     out << indent << "}";
    105     if (i != info.caches.size() - 1) out << ",";
    106     out << "\n";
    107   }
    108   indent = std::string(4, ' ');
    109   out << indent << "],\n";
    110 
    111 #if defined(NDEBUG)
    112   const char build_type[] = "release";
    113 #else
    114   const char build_type[] = "debug";
    115 #endif
    116   out << indent << FormatKV("library_build_type", build_type) << "\n";
    117   // Close context block and open the list of benchmarks.
    118   out << inner_indent << "},\n";
    119   out << inner_indent << "\"benchmarks\": [\n";
    120   return true;
    121 }
    122 
    123 void JSONReporter::ReportRuns(std::vector<Run> const& reports) {
    124   if (reports.empty()) {
    125     return;
    126   }
    127   std::string indent(4, ' ');
    128   std::ostream& out = GetOutputStream();
    129   if (!first_report_) {
    130     out << ",\n";
    131   }
    132   first_report_ = false;
    133 
    134   for (auto it = reports.begin(); it != reports.end(); ++it) {
    135     out << indent << "{\n";
    136     PrintRunData(*it);
    137     out << indent << '}';
    138     auto it_cp = it;
    139     if (++it_cp != reports.end()) {
    140       out << ",\n";
    141     }
    142   }
    143 }
    144 
    145 void JSONReporter::Finalize() {
    146   // Close the list of benchmarks and the top level object.
    147   GetOutputStream() << "\n  ]\n}\n";
    148 }
    149 
    150 void JSONReporter::PrintRunData(Run const& run) {
    151   std::string indent(6, ' ');
    152   std::ostream& out = GetOutputStream();
    153   out << indent << FormatKV("name", run.benchmark_name) << ",\n";
    154   if (run.error_occurred) {
    155     out << indent << FormatKV("error_occurred", run.error_occurred) << ",\n";
    156     out << indent << FormatKV("error_message", run.error_message) << ",\n";
    157   }
    158   if (!run.report_big_o && !run.report_rms) {
    159     out << indent << FormatKV("iterations", run.iterations) << ",\n";
    160     out << indent
    161         << FormatKV("real_time", run.GetAdjustedRealTime())
    162         << ",\n";
    163     out << indent
    164         << FormatKV("cpu_time", run.GetAdjustedCPUTime());
    165     out << ",\n"
    166         << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
    167   } else if (run.report_big_o) {
    168     out << indent
    169         << FormatKV("cpu_coefficient", run.GetAdjustedCPUTime())
    170         << ",\n";
    171     out << indent
    172         << FormatKV("real_coefficient", run.GetAdjustedRealTime())
    173         << ",\n";
    174     out << indent << FormatKV("big_o", GetBigOString(run.complexity)) << ",\n";
    175     out << indent << FormatKV("time_unit", GetTimeUnitString(run.time_unit));
    176   } else if (run.report_rms) {
    177     out << indent
    178         << FormatKV("rms", run.GetAdjustedCPUTime());
    179   }
    180   if (run.bytes_per_second > 0.0) {
    181     out << ",\n"
    182         << indent
    183         << FormatKV("bytes_per_second", run.bytes_per_second);
    184   }
    185   if (run.items_per_second > 0.0) {
    186     out << ",\n"
    187         << indent
    188         << FormatKV("items_per_second", run.items_per_second);
    189   }
    190   for(auto &c : run.counters) {
    191     out << ",\n"
    192         << indent
    193         << FormatKV(c.first, c.second);
    194   }
    195   if (!run.report_label.empty()) {
    196     out << ",\n" << indent << FormatKV("label", run.report_label);
    197   }
    198   out << '\n';
    199 }
    200 
    201 } // end namespace benchmark
    202