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