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
30namespace benchmark {
31
32namespace {
33std::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
39std::string CsvEscape(const std::string& s) {
40 std::string tmp;
41 tmp.reserve(res: 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
55BENCHMARK_EXPORT
56bool CSVReporter::ReportContext(const Context& context) {
57 PrintBasicContext(out: &GetErrorStream(), context);
58 return true;
59}
60
61BENCHMARK_EXPORT
62void 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(x: 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(report: run);
105 }
106}
107
108BENCHMARK_EXPORT
109void CSVReporter::PrintRunData(const Run& run) {
110 std::ostream& Out = GetOutputStream();
111 Out << CsvEscape(s: 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(s: 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(complexity: run.complexity);
138 } else if (!run.report_rms &&
139 run.aggregate_unit != StatisticUnit::kPercentage) {
140 Out << GetTimeUnitString(unit: run.time_unit);
141 }
142 Out << ",";
143
144 if (run.counters.find(x: "bytes_per_second") != run.counters.end()) {
145 Out << run.counters.at(k: "bytes_per_second");
146 }
147 Out << ",";
148 if (run.counters.find(x: "items_per_second") != run.counters.end()) {
149 Out << run.counters.at(k: "items_per_second");
150 }
151 Out << ",";
152 if (!run.report_label.empty()) {
153 Out << CsvEscape(s: 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(x: 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

source code of third-party/benchmark/src/csv_reporter.cc