2015-03-28 04:27:15 +08:00
|
|
|
// Copyright 2015 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2016-05-25 05:44:58 +08:00
|
|
|
#include <algorithm>
|
2016-06-03 04:01:31 +08:00
|
|
|
#include <cstdint>
|
2015-03-28 04:27:15 +08:00
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
2016-03-30 15:14:04 +08:00
|
|
|
#include <tuple>
|
2015-03-28 04:27:15 +08:00
|
|
|
#include <vector>
|
|
|
|
|
2021-11-11 00:04:32 +08:00
|
|
|
#include "benchmark/benchmark.h"
|
2018-06-01 18:14:19 +08:00
|
|
|
#include "check.h"
|
2021-11-11 00:04:32 +08:00
|
|
|
#include "complexity.h"
|
2015-03-28 04:27:15 +08:00
|
|
|
#include "string_util.h"
|
2016-09-03 11:34:34 +08:00
|
|
|
#include "timers.h"
|
2015-03-28 04:27:15 +08:00
|
|
|
|
2015-03-28 05:06:33 +08:00
|
|
|
// File format reference: http://edoceo.com/utilitas/csv-file-format.
|
|
|
|
|
2015-03-28 04:27:15 +08:00
|
|
|
namespace benchmark {
|
|
|
|
|
2016-05-25 09:45:18 +08:00
|
|
|
namespace {
|
|
|
|
std::vector<std::string> elements = {
|
2016-10-08 02:35:03 +08:00
|
|
|
"name", "iterations", "real_time", "cpu_time",
|
|
|
|
"time_unit", "bytes_per_second", "items_per_second", "label",
|
|
|
|
"error_occurred", "error_message"};
|
2017-07-15 06:21:20 +08:00
|
|
|
} // namespace
|
2016-05-25 09:45:18 +08:00
|
|
|
|
2021-11-11 00:04:32 +08:00
|
|
|
std::string CsvEscape(const std::string& s) {
|
2019-04-20 01:47:25 +08:00
|
|
|
std::string tmp;
|
|
|
|
tmp.reserve(s.size() + 2);
|
|
|
|
for (char c : s) {
|
|
|
|
switch (c) {
|
2021-11-11 00:04:32 +08:00
|
|
|
case '"':
|
|
|
|
tmp += "\"\"";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
tmp += c;
|
|
|
|
break;
|
2019-04-20 01:47:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return '"' + tmp + '"';
|
|
|
|
}
|
|
|
|
|
2022-08-03 16:44:35 +08:00
|
|
|
BENCHMARK_EXPORT
|
2015-03-28 04:27:15 +08:00
|
|
|
bool CSVReporter::ReportContext(const Context& context) {
|
2016-05-28 06:45:25 +08:00
|
|
|
PrintBasicContext(&GetErrorStream(), context);
|
2017-03-02 08:23:42 +08:00
|
|
|
return true;
|
|
|
|
}
|
2015-03-28 04:27:15 +08:00
|
|
|
|
2022-08-03 16:44:35 +08:00
|
|
|
BENCHMARK_EXPORT
|
2018-06-01 18:14:19 +08:00
|
|
|
void CSVReporter::ReportRuns(const std::vector<Run>& reports) {
|
2016-05-28 06:45:25 +08:00
|
|
|
std::ostream& Out = GetOutputStream();
|
2017-03-02 08:23:42 +08:00
|
|
|
|
|
|
|
if (!printed_header_) {
|
|
|
|
// save the names of all the user counters
|
|
|
|
for (const auto& run : reports) {
|
|
|
|
for (const auto& cnt : run.counters) {
|
2018-09-14 03:03:47 +08:00
|
|
|
if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second")
|
|
|
|
continue;
|
2017-03-02 08:23:42 +08:00
|
|
|
user_counter_names_.insert(cnt.first);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// print the header
|
|
|
|
for (auto B = elements.begin(); B != elements.end();) {
|
|
|
|
Out << *B++;
|
|
|
|
if (B != elements.end()) Out << ",";
|
|
|
|
}
|
2018-06-01 18:14:19 +08:00
|
|
|
for (auto B = user_counter_names_.begin();
|
|
|
|
B != user_counter_names_.end();) {
|
2017-03-02 08:23:42 +08:00
|
|
|
Out << ",\"" << *B++ << "\"";
|
|
|
|
}
|
|
|
|
Out << "\n";
|
|
|
|
|
|
|
|
printed_header_ = true;
|
|
|
|
} else {
|
|
|
|
// check that all the current counters are saved in the name set
|
|
|
|
for (const auto& run : reports) {
|
|
|
|
for (const auto& cnt : run.counters) {
|
2018-09-14 03:03:47 +08:00
|
|
|
if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second")
|
|
|
|
continue;
|
2021-06-25 01:21:59 +08:00
|
|
|
BM_CHECK(user_counter_names_.find(cnt.first) !=
|
|
|
|
user_counter_names_.end())
|
2018-06-01 18:14:19 +08:00
|
|
|
<< "All counters must be present in each run. "
|
|
|
|
<< "Counter named \"" << cnt.first
|
|
|
|
<< "\" was not in a run after being added to the header";
|
2017-03-02 08:23:42 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// print results for each run
|
|
|
|
for (const auto& run : reports) {
|
|
|
|
PrintRunData(run);
|
2016-05-25 09:45:18 +08:00
|
|
|
}
|
2016-05-19 03:25:00 +08:00
|
|
|
}
|
|
|
|
|
2022-08-03 16:44:35 +08:00
|
|
|
BENCHMARK_EXPORT
|
2018-06-01 18:14:19 +08:00
|
|
|
void CSVReporter::PrintRunData(const Run& run) {
|
2016-05-28 03:34:37 +08:00
|
|
|
std::ostream& Out = GetOutputStream();
|
2019-04-20 01:47:25 +08:00
|
|
|
Out << CsvEscape(run.benchmark_name()) << ",";
|
2023-03-09 02:24:48 +08:00
|
|
|
if (run.skipped) {
|
2016-05-28 03:34:37 +08:00
|
|
|
Out << std::string(elements.size() - 3, ',');
|
2023-03-09 02:24:48 +08:00
|
|
|
Out << std::boolalpha << (internal::SkippedWithError == run.skipped) << ",";
|
|
|
|
Out << CsvEscape(run.skip_message) << "\n";
|
2016-05-25 09:45:18 +08:00
|
|
|
return;
|
2016-05-25 05:44:58 +08:00
|
|
|
}
|
|
|
|
|
2016-05-24 04:09:55 +08:00
|
|
|
// Do not print iteration on bigO and RMS report
|
2016-06-03 04:01:31 +08:00
|
|
|
if (!run.report_big_o && !run.report_rms) {
|
2016-05-28 03:34:37 +08:00
|
|
|
Out << run.iterations;
|
2016-05-25 04:25:59 +08:00
|
|
|
}
|
2016-05-28 03:34:37 +08:00
|
|
|
Out << ",";
|
2016-05-25 04:25:59 +08:00
|
|
|
|
2016-05-28 06:45:25 +08:00
|
|
|
Out << run.GetAdjustedRealTime() << ",";
|
|
|
|
Out << run.GetAdjustedCPUTime() << ",";
|
2016-05-25 04:25:59 +08:00
|
|
|
|
2016-06-02 05:08:01 +08:00
|
|
|
// Do not print timeLabel on bigO and RMS report
|
2016-06-03 04:01:31 +08:00
|
|
|
if (run.report_big_o) {
|
2016-06-02 05:08:01 +08:00
|
|
|
Out << GetBigOString(run.complexity);
|
2016-06-03 04:01:31 +08:00
|
|
|
} else if (!run.report_rms) {
|
2016-05-28 06:45:25 +08:00
|
|
|
Out << GetTimeUnitString(run.time_unit);
|
2016-05-25 04:25:59 +08:00
|
|
|
}
|
2016-05-28 03:34:37 +08:00
|
|
|
Out << ",";
|
2015-03-28 04:27:15 +08:00
|
|
|
|
2018-09-14 03:03:47 +08:00
|
|
|
if (run.counters.find("bytes_per_second") != run.counters.end()) {
|
|
|
|
Out << run.counters.at("bytes_per_second");
|
2015-03-28 04:27:15 +08:00
|
|
|
}
|
2016-05-28 03:34:37 +08:00
|
|
|
Out << ",";
|
2018-09-14 03:03:47 +08:00
|
|
|
if (run.counters.find("items_per_second") != run.counters.end()) {
|
|
|
|
Out << run.counters.at("items_per_second");
|
2015-03-28 04:27:15 +08:00
|
|
|
}
|
2016-05-28 03:34:37 +08:00
|
|
|
Out << ",";
|
2015-03-28 04:27:15 +08:00
|
|
|
if (!run.report_label.empty()) {
|
2019-04-20 01:47:25 +08:00
|
|
|
Out << CsvEscape(run.report_label);
|
2015-03-28 04:27:15 +08:00
|
|
|
}
|
2016-06-03 04:01:31 +08:00
|
|
|
Out << ",,"; // for error_occurred and error_message
|
2017-03-02 08:23:42 +08:00
|
|
|
|
|
|
|
// Print user counters
|
2018-06-01 18:14:19 +08:00
|
|
|
for (const auto& ucn : user_counter_names_) {
|
2017-03-02 08:23:42 +08:00
|
|
|
auto it = run.counters.find(ucn);
|
2018-06-01 18:14:19 +08:00
|
|
|
if (it == run.counters.end()) {
|
2017-05-03 05:10:08 +08:00
|
|
|
Out << ",";
|
2017-05-03 06:30:36 +08:00
|
|
|
} else {
|
2017-05-03 05:10:08 +08:00
|
|
|
Out << "," << it->second;
|
|
|
|
}
|
2017-03-02 08:23:42 +08:00
|
|
|
}
|
2016-05-28 03:34:37 +08:00
|
|
|
Out << '\n';
|
2015-03-28 04:27:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace benchmark
|