• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <algorithm>
16 #include <cstdint>
17 #include <iostream>
18 #include <string>
19 #include <tuple>
20 #include <vector>
21 
22 #include "benchmark/benchmark.h"
23 #include "check.h"
24 #include "complexity.h"
25 #include "string_util.h"
26 #include "timers.h"
27 
28 // File format reference: http://edoceo.com/utilitas/csv-file-format.
29 
30 namespace benchmark {
31 
32 namespace {
33 std::vector<std::string> elements = {
34     "name",           "iterations",       "real_time",        "cpu_time",
35     "time_unit",      "bytes_per_second", "items_per_second", "label",
36     "error_occurred", "error_message"};
37 }  // namespace
38 
CsvEscape(const std::string & s)39 std::string CsvEscape(const std::string& s) {
40   std::string tmp;
41   tmp.reserve(s.size() + 2);
42   for (char c : s) {
43     switch (c) {
44       case '"':
45         tmp += "\"\"";
46         break;
47       default:
48         tmp += c;
49         break;
50     }
51   }
52   return '"' + tmp + '"';
53 }
54 
ReportContext(const Context & context)55 bool CSVReporter::ReportContext(const Context& context) {
56   PrintBasicContext(&GetErrorStream(), context);
57   return true;
58 }
59 
ReportRuns(const std::vector<Run> & reports)60 void CSVReporter::ReportRuns(const std::vector<Run>& reports) {
61   std::ostream& Out = GetOutputStream();
62 
63   if (!printed_header_) {
64     // save the names of all the user counters
65     for (const auto& run : reports) {
66       for (const auto& cnt : run.counters) {
67         if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second")
68           continue;
69         user_counter_names_.insert(cnt.first);
70       }
71     }
72 
73     // print the header
74     for (auto B = elements.begin(); B != elements.end();) {
75       Out << *B++;
76       if (B != elements.end()) Out << ",";
77     }
78     for (auto B = user_counter_names_.begin();
79          B != user_counter_names_.end();) {
80       Out << ",\"" << *B++ << "\"";
81     }
82     Out << "\n";
83 
84     printed_header_ = true;
85   } else {
86     // check that all the current counters are saved in the name set
87     for (const auto& run : reports) {
88       for (const auto& cnt : run.counters) {
89         if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second")
90           continue;
91         BM_CHECK(user_counter_names_.find(cnt.first) !=
92                  user_counter_names_.end())
93             << "All counters must be present in each run. "
94             << "Counter named \"" << cnt.first
95             << "\" was not in a run after being added to the header";
96       }
97     }
98   }
99 
100   // print results for each run
101   for (const auto& run : reports) {
102     PrintRunData(run);
103   }
104 }
105 
PrintRunData(const Run & run)106 void CSVReporter::PrintRunData(const Run& run) {
107   std::ostream& Out = GetOutputStream();
108   Out << CsvEscape(run.benchmark_name()) << ",";
109   if (run.error_occurred) {
110     Out << std::string(elements.size() - 3, ',');
111     Out << "true,";
112     Out << CsvEscape(run.error_message) << "\n";
113     return;
114   }
115 
116   // Do not print iteration on bigO and RMS report
117   if (!run.report_big_o && !run.report_rms) {
118     Out << run.iterations;
119   }
120   Out << ",";
121 
122   Out << run.GetAdjustedRealTime() << ",";
123   Out << run.GetAdjustedCPUTime() << ",";
124 
125   // Do not print timeLabel on bigO and RMS report
126   if (run.report_big_o) {
127     Out << GetBigOString(run.complexity);
128   } else if (!run.report_rms) {
129     Out << GetTimeUnitString(run.time_unit);
130   }
131   Out << ",";
132 
133   if (run.counters.find("bytes_per_second") != run.counters.end()) {
134     Out << run.counters.at("bytes_per_second");
135   }
136   Out << ",";
137   if (run.counters.find("items_per_second") != run.counters.end()) {
138     Out << run.counters.at("items_per_second");
139   }
140   Out << ",";
141   if (!run.report_label.empty()) {
142     Out << CsvEscape(run.report_label);
143   }
144   Out << ",,";  // for error_occurred and error_message
145 
146   // Print user counters
147   for (const auto& ucn : user_counter_names_) {
148     auto it = run.counters.find(ucn);
149     if (it == run.counters.end()) {
150       Out << ",";
151     } else {
152       Out << "," << it->second;
153     }
154   }
155   Out << '\n';
156 }
157 
158 }  // end namespace benchmark
159