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