1*dbb99499SAndroid Build Coastguard Worker // Copyright 2015 Google Inc. All rights reserved.
2*dbb99499SAndroid Build Coastguard Worker //
3*dbb99499SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*dbb99499SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*dbb99499SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*dbb99499SAndroid Build Coastguard Worker //
7*dbb99499SAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*dbb99499SAndroid Build Coastguard Worker //
9*dbb99499SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*dbb99499SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*dbb99499SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*dbb99499SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*dbb99499SAndroid Build Coastguard Worker // limitations under the License.
14*dbb99499SAndroid Build Coastguard Worker
15*dbb99499SAndroid Build Coastguard Worker #include <algorithm>
16*dbb99499SAndroid Build Coastguard Worker #include <cstdint>
17*dbb99499SAndroid Build Coastguard Worker #include <iostream>
18*dbb99499SAndroid Build Coastguard Worker #include <string>
19*dbb99499SAndroid Build Coastguard Worker #include <tuple>
20*dbb99499SAndroid Build Coastguard Worker #include <vector>
21*dbb99499SAndroid Build Coastguard Worker
22*dbb99499SAndroid Build Coastguard Worker #include "benchmark/benchmark.h"
23*dbb99499SAndroid Build Coastguard Worker #include "check.h"
24*dbb99499SAndroid Build Coastguard Worker #include "complexity.h"
25*dbb99499SAndroid Build Coastguard Worker #include "string_util.h"
26*dbb99499SAndroid Build Coastguard Worker #include "timers.h"
27*dbb99499SAndroid Build Coastguard Worker
28*dbb99499SAndroid Build Coastguard Worker // File format reference: http://edoceo.com/utilitas/csv-file-format.
29*dbb99499SAndroid Build Coastguard Worker
30*dbb99499SAndroid Build Coastguard Worker namespace benchmark {
31*dbb99499SAndroid Build Coastguard Worker
32*dbb99499SAndroid Build Coastguard Worker namespace {
33*dbb99499SAndroid Build Coastguard Worker std::vector<std::string> elements = {
34*dbb99499SAndroid Build Coastguard Worker "name", "iterations", "real_time", "cpu_time",
35*dbb99499SAndroid Build Coastguard Worker "time_unit", "bytes_per_second", "items_per_second", "label",
36*dbb99499SAndroid Build Coastguard Worker "error_occurred", "error_message"};
37*dbb99499SAndroid Build Coastguard Worker } // namespace
38*dbb99499SAndroid Build Coastguard Worker
CsvEscape(const std::string & s)39*dbb99499SAndroid Build Coastguard Worker std::string CsvEscape(const std::string& s) {
40*dbb99499SAndroid Build Coastguard Worker std::string tmp;
41*dbb99499SAndroid Build Coastguard Worker tmp.reserve(s.size() + 2);
42*dbb99499SAndroid Build Coastguard Worker for (char c : s) {
43*dbb99499SAndroid Build Coastguard Worker switch (c) {
44*dbb99499SAndroid Build Coastguard Worker case '"':
45*dbb99499SAndroid Build Coastguard Worker tmp += "\"\"";
46*dbb99499SAndroid Build Coastguard Worker break;
47*dbb99499SAndroid Build Coastguard Worker default:
48*dbb99499SAndroid Build Coastguard Worker tmp += c;
49*dbb99499SAndroid Build Coastguard Worker break;
50*dbb99499SAndroid Build Coastguard Worker }
51*dbb99499SAndroid Build Coastguard Worker }
52*dbb99499SAndroid Build Coastguard Worker return '"' + tmp + '"';
53*dbb99499SAndroid Build Coastguard Worker }
54*dbb99499SAndroid Build Coastguard Worker
55*dbb99499SAndroid Build Coastguard Worker BENCHMARK_EXPORT
ReportContext(const Context & context)56*dbb99499SAndroid Build Coastguard Worker bool CSVReporter::ReportContext(const Context& context) {
57*dbb99499SAndroid Build Coastguard Worker PrintBasicContext(&GetErrorStream(), context);
58*dbb99499SAndroid Build Coastguard Worker return true;
59*dbb99499SAndroid Build Coastguard Worker }
60*dbb99499SAndroid Build Coastguard Worker
61*dbb99499SAndroid Build Coastguard Worker BENCHMARK_EXPORT
ReportRuns(const std::vector<Run> & reports)62*dbb99499SAndroid Build Coastguard Worker void CSVReporter::ReportRuns(const std::vector<Run>& reports) {
63*dbb99499SAndroid Build Coastguard Worker std::ostream& Out = GetOutputStream();
64*dbb99499SAndroid Build Coastguard Worker
65*dbb99499SAndroid Build Coastguard Worker if (!printed_header_) {
66*dbb99499SAndroid Build Coastguard Worker // save the names of all the user counters
67*dbb99499SAndroid Build Coastguard Worker for (const auto& run : reports) {
68*dbb99499SAndroid Build Coastguard Worker for (const auto& cnt : run.counters) {
69*dbb99499SAndroid Build Coastguard Worker if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second")
70*dbb99499SAndroid Build Coastguard Worker continue;
71*dbb99499SAndroid Build Coastguard Worker user_counter_names_.insert(cnt.first);
72*dbb99499SAndroid Build Coastguard Worker }
73*dbb99499SAndroid Build Coastguard Worker }
74*dbb99499SAndroid Build Coastguard Worker
75*dbb99499SAndroid Build Coastguard Worker // print the header
76*dbb99499SAndroid Build Coastguard Worker for (auto B = elements.begin(); B != elements.end();) {
77*dbb99499SAndroid Build Coastguard Worker Out << *B++;
78*dbb99499SAndroid Build Coastguard Worker if (B != elements.end()) Out << ",";
79*dbb99499SAndroid Build Coastguard Worker }
80*dbb99499SAndroid Build Coastguard Worker for (auto B = user_counter_names_.begin();
81*dbb99499SAndroid Build Coastguard Worker B != user_counter_names_.end();) {
82*dbb99499SAndroid Build Coastguard Worker Out << ",\"" << *B++ << "\"";
83*dbb99499SAndroid Build Coastguard Worker }
84*dbb99499SAndroid Build Coastguard Worker Out << "\n";
85*dbb99499SAndroid Build Coastguard Worker
86*dbb99499SAndroid Build Coastguard Worker printed_header_ = true;
87*dbb99499SAndroid Build Coastguard Worker } else {
88*dbb99499SAndroid Build Coastguard Worker // check that all the current counters are saved in the name set
89*dbb99499SAndroid Build Coastguard Worker for (const auto& run : reports) {
90*dbb99499SAndroid Build Coastguard Worker for (const auto& cnt : run.counters) {
91*dbb99499SAndroid Build Coastguard Worker if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second")
92*dbb99499SAndroid Build Coastguard Worker continue;
93*dbb99499SAndroid Build Coastguard Worker BM_CHECK(user_counter_names_.find(cnt.first) !=
94*dbb99499SAndroid Build Coastguard Worker user_counter_names_.end())
95*dbb99499SAndroid Build Coastguard Worker << "All counters must be present in each run. "
96*dbb99499SAndroid Build Coastguard Worker << "Counter named \"" << cnt.first
97*dbb99499SAndroid Build Coastguard Worker << "\" was not in a run after being added to the header";
98*dbb99499SAndroid Build Coastguard Worker }
99*dbb99499SAndroid Build Coastguard Worker }
100*dbb99499SAndroid Build Coastguard Worker }
101*dbb99499SAndroid Build Coastguard Worker
102*dbb99499SAndroid Build Coastguard Worker // print results for each run
103*dbb99499SAndroid Build Coastguard Worker for (const auto& run : reports) {
104*dbb99499SAndroid Build Coastguard Worker PrintRunData(run);
105*dbb99499SAndroid Build Coastguard Worker }
106*dbb99499SAndroid Build Coastguard Worker }
107*dbb99499SAndroid Build Coastguard Worker
108*dbb99499SAndroid Build Coastguard Worker BENCHMARK_EXPORT
PrintRunData(const Run & run)109*dbb99499SAndroid Build Coastguard Worker void CSVReporter::PrintRunData(const Run& run) {
110*dbb99499SAndroid Build Coastguard Worker std::ostream& Out = GetOutputStream();
111*dbb99499SAndroid Build Coastguard Worker Out << CsvEscape(run.benchmark_name()) << ",";
112*dbb99499SAndroid Build Coastguard Worker if (run.skipped) {
113*dbb99499SAndroid Build Coastguard Worker Out << std::string(elements.size() - 3, ',');
114*dbb99499SAndroid Build Coastguard Worker Out << std::boolalpha << (internal::SkippedWithError == run.skipped) << ",";
115*dbb99499SAndroid Build Coastguard Worker Out << CsvEscape(run.skip_message) << "\n";
116*dbb99499SAndroid Build Coastguard Worker return;
117*dbb99499SAndroid Build Coastguard Worker }
118*dbb99499SAndroid Build Coastguard Worker
119*dbb99499SAndroid Build Coastguard Worker // Do not print iteration on bigO and RMS report
120*dbb99499SAndroid Build Coastguard Worker if (!run.report_big_o && !run.report_rms) {
121*dbb99499SAndroid Build Coastguard Worker Out << run.iterations;
122*dbb99499SAndroid Build Coastguard Worker }
123*dbb99499SAndroid Build Coastguard Worker Out << ",";
124*dbb99499SAndroid Build Coastguard Worker
125*dbb99499SAndroid Build Coastguard Worker if (run.run_type != Run::RT_Aggregate ||
126*dbb99499SAndroid Build Coastguard Worker run.aggregate_unit == StatisticUnit::kTime) {
127*dbb99499SAndroid Build Coastguard Worker Out << run.GetAdjustedRealTime() << ",";
128*dbb99499SAndroid Build Coastguard Worker Out << run.GetAdjustedCPUTime() << ",";
129*dbb99499SAndroid Build Coastguard Worker } else {
130*dbb99499SAndroid Build Coastguard Worker assert(run.aggregate_unit == StatisticUnit::kPercentage);
131*dbb99499SAndroid Build Coastguard Worker Out << run.real_accumulated_time << ",";
132*dbb99499SAndroid Build Coastguard Worker Out << run.cpu_accumulated_time << ",";
133*dbb99499SAndroid Build Coastguard Worker }
134*dbb99499SAndroid Build Coastguard Worker
135*dbb99499SAndroid Build Coastguard Worker // Do not print timeLabel on bigO and RMS report
136*dbb99499SAndroid Build Coastguard Worker if (run.report_big_o) {
137*dbb99499SAndroid Build Coastguard Worker Out << GetBigOString(run.complexity);
138*dbb99499SAndroid Build Coastguard Worker } else if (!run.report_rms &&
139*dbb99499SAndroid Build Coastguard Worker run.aggregate_unit != StatisticUnit::kPercentage) {
140*dbb99499SAndroid Build Coastguard Worker Out << GetTimeUnitString(run.time_unit);
141*dbb99499SAndroid Build Coastguard Worker }
142*dbb99499SAndroid Build Coastguard Worker Out << ",";
143*dbb99499SAndroid Build Coastguard Worker
144*dbb99499SAndroid Build Coastguard Worker if (run.counters.find("bytes_per_second") != run.counters.end()) {
145*dbb99499SAndroid Build Coastguard Worker Out << run.counters.at("bytes_per_second");
146*dbb99499SAndroid Build Coastguard Worker }
147*dbb99499SAndroid Build Coastguard Worker Out << ",";
148*dbb99499SAndroid Build Coastguard Worker if (run.counters.find("items_per_second") != run.counters.end()) {
149*dbb99499SAndroid Build Coastguard Worker Out << run.counters.at("items_per_second");
150*dbb99499SAndroid Build Coastguard Worker }
151*dbb99499SAndroid Build Coastguard Worker Out << ",";
152*dbb99499SAndroid Build Coastguard Worker if (!run.report_label.empty()) {
153*dbb99499SAndroid Build Coastguard Worker Out << CsvEscape(run.report_label);
154*dbb99499SAndroid Build Coastguard Worker }
155*dbb99499SAndroid Build Coastguard Worker Out << ",,"; // for error_occurred and error_message
156*dbb99499SAndroid Build Coastguard Worker
157*dbb99499SAndroid Build Coastguard Worker // Print user counters
158*dbb99499SAndroid Build Coastguard Worker for (const auto& ucn : user_counter_names_) {
159*dbb99499SAndroid Build Coastguard Worker auto it = run.counters.find(ucn);
160*dbb99499SAndroid Build Coastguard Worker if (it == run.counters.end()) {
161*dbb99499SAndroid Build Coastguard Worker Out << ",";
162*dbb99499SAndroid Build Coastguard Worker } else {
163*dbb99499SAndroid Build Coastguard Worker Out << "," << it->second;
164*dbb99499SAndroid Build Coastguard Worker }
165*dbb99499SAndroid Build Coastguard Worker }
166*dbb99499SAndroid Build Coastguard Worker Out << '\n';
167*dbb99499SAndroid Build Coastguard Worker }
168*dbb99499SAndroid Build Coastguard Worker
169*dbb99499SAndroid Build Coastguard Worker } // end namespace benchmark
170