xref: /aosp_15_r20/external/google-benchmark/src/csv_reporter.cc (revision dbb99499c3810fa1611fa2242a2fc446be01a57c)
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 
55 BENCHMARK_EXPORT
ReportContext(const Context & context)56 bool CSVReporter::ReportContext(const Context& context) {
57   PrintBasicContext(&GetErrorStream(), context);
58   return true;
59 }
60 
61 BENCHMARK_EXPORT
ReportRuns(const std::vector<Run> & reports)62 void CSVReporter::ReportRuns(const std::vector<Run>& reports) {
63   std::ostream& Out = GetOutputStream();
64 
65   if (!printed_header_) {
66     // save the names of all the user counters
67     for (const auto& run : reports) {
68       for (const auto& cnt : run.counters) {
69         if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second")
70           continue;
71         user_counter_names_.insert(cnt.first);
72       }
73     }
74 
75     // print the header
76     for (auto B = elements.begin(); B != elements.end();) {
77       Out << *B++;
78       if (B != elements.end()) Out << ",";
79     }
80     for (auto B = user_counter_names_.begin();
81          B != user_counter_names_.end();) {
82       Out << ",\"" << *B++ << "\"";
83     }
84     Out << "\n";
85 
86     printed_header_ = true;
87   } else {
88     // check that all the current counters are saved in the name set
89     for (const auto& run : reports) {
90       for (const auto& cnt : run.counters) {
91         if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second")
92           continue;
93         BM_CHECK(user_counter_names_.find(cnt.first) !=
94                  user_counter_names_.end())
95             << "All counters must be present in each run. "
96             << "Counter named \"" << cnt.first
97             << "\" was not in a run after being added to the header";
98       }
99     }
100   }
101 
102   // print results for each run
103   for (const auto& run : reports) {
104     PrintRunData(run);
105   }
106 }
107 
108 BENCHMARK_EXPORT
PrintRunData(const Run & run)109 void CSVReporter::PrintRunData(const Run& run) {
110   std::ostream& Out = GetOutputStream();
111   Out << CsvEscape(run.benchmark_name()) << ",";
112   if (run.skipped) {
113     Out << std::string(elements.size() - 3, ',');
114     Out << std::boolalpha << (internal::SkippedWithError == run.skipped) << ",";
115     Out << CsvEscape(run.skip_message) << "\n";
116     return;
117   }
118 
119   // Do not print iteration on bigO and RMS report
120   if (!run.report_big_o && !run.report_rms) {
121     Out << run.iterations;
122   }
123   Out << ",";
124 
125   if (run.run_type != Run::RT_Aggregate ||
126       run.aggregate_unit == StatisticUnit::kTime) {
127     Out << run.GetAdjustedRealTime() << ",";
128     Out << run.GetAdjustedCPUTime() << ",";
129   } else {
130     assert(run.aggregate_unit == StatisticUnit::kPercentage);
131     Out << run.real_accumulated_time << ",";
132     Out << run.cpu_accumulated_time << ",";
133   }
134 
135   // Do not print timeLabel on bigO and RMS report
136   if (run.report_big_o) {
137     Out << GetBigOString(run.complexity);
138   } else if (!run.report_rms &&
139              run.aggregate_unit != StatisticUnit::kPercentage) {
140     Out << GetTimeUnitString(run.time_unit);
141   }
142   Out << ",";
143 
144   if (run.counters.find("bytes_per_second") != run.counters.end()) {
145     Out << run.counters.at("bytes_per_second");
146   }
147   Out << ",";
148   if (run.counters.find("items_per_second") != run.counters.end()) {
149     Out << run.counters.at("items_per_second");
150   }
151   Out << ",";
152   if (!run.report_label.empty()) {
153     Out << CsvEscape(run.report_label);
154   }
155   Out << ",,";  // for error_occurred and error_message
156 
157   // Print user counters
158   for (const auto& ucn : user_counter_names_) {
159     auto it = run.counters.find(ucn);
160     if (it == run.counters.end()) {
161       Out << ",";
162     } else {
163       Out << "," << it->second;
164     }
165   }
166   Out << '\n';
167 }
168 
169 }  // end namespace benchmark
170