| // 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. |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include <iostream> |
| #include <string> |
| #include <tuple> |
| #include <vector> |
| |
| #include "benchmark/benchmark.h" |
| #include "check.h" |
| #include "complexity.h" |
| #include "string_util.h" |
| #include "timers.h" |
| |
| // File format reference: http://edoceo.com/utilitas/csv-file-format. |
| |
| namespace benchmark { |
| |
| namespace { |
| std::vector<std::string> elements = { |
| "name", "iterations", "real_time", "cpu_time", |
| "time_unit", "bytes_per_second", "items_per_second", "label", |
| "error_occurred", "error_message"}; |
| } // namespace |
| |
| std::string CsvEscape(const std::string& s) { |
| std::string tmp; |
| tmp.reserve(s.size() + 2); |
| for (char c : s) { |
| switch (c) { |
| case '"': |
| tmp += "\"\""; |
| break; |
| default: |
| tmp += c; |
| break; |
| } |
| } |
| return '"' + tmp + '"'; |
| } |
| |
| BENCHMARK_EXPORT |
| bool CSVReporter::ReportContext(const Context& context) { |
| PrintBasicContext(&GetErrorStream(), context); |
| return true; |
| } |
| |
| BENCHMARK_EXPORT |
| void CSVReporter::ReportRuns(const std::vector<Run>& reports) { |
| std::ostream& Out = GetOutputStream(); |
| |
| if (!printed_header_) { |
| // save the names of all the user counters |
| for (const auto& run : reports) { |
| for (const auto& cnt : run.counters) { |
| if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second") |
| continue; |
| user_counter_names_.insert(cnt.first); |
| } |
| } |
| |
| // print the header |
| for (auto B = elements.begin(); B != elements.end();) { |
| Out << *B++; |
| if (B != elements.end()) Out << ","; |
| } |
| for (auto B = user_counter_names_.begin(); |
| B != user_counter_names_.end();) { |
| 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) { |
| if (cnt.first == "bytes_per_second" || cnt.first == "items_per_second") |
| continue; |
| BM_CHECK(user_counter_names_.find(cnt.first) != |
| user_counter_names_.end()) |
| << "All counters must be present in each run. " |
| << "Counter named \"" << cnt.first |
| << "\" was not in a run after being added to the header"; |
| } |
| } |
| } |
| |
| // print results for each run |
| for (const auto& run : reports) { |
| PrintRunData(run); |
| } |
| } |
| |
| BENCHMARK_EXPORT |
| void CSVReporter::PrintRunData(const Run& run) { |
| std::ostream& Out = GetOutputStream(); |
| Out << CsvEscape(run.benchmark_name()) << ","; |
| if (run.skipped) { |
| Out << std::string(elements.size() - 3, ','); |
| Out << std::boolalpha << (internal::SkippedWithError == run.skipped) << ","; |
| Out << CsvEscape(run.skip_message) << "\n"; |
| return; |
| } |
| |
| // Do not print iteration on bigO and RMS report |
| if (!run.report_big_o && !run.report_rms) { |
| Out << run.iterations; |
| } |
| Out << ","; |
| |
| if (run.run_type != Run::RT_Aggregate || |
| run.aggregate_unit == StatisticUnit::kTime) { |
| Out << run.GetAdjustedRealTime() << ","; |
| Out << run.GetAdjustedCPUTime() << ","; |
| } else { |
| assert(run.aggregate_unit == StatisticUnit::kPercentage); |
| Out << run.real_accumulated_time << ","; |
| Out << run.cpu_accumulated_time << ","; |
| } |
| |
| // Do not print timeLabel on bigO and RMS report |
| if (run.report_big_o) { |
| Out << GetBigOString(run.complexity); |
| } else if (!run.report_rms && |
| run.aggregate_unit != StatisticUnit::kPercentage) { |
| Out << GetTimeUnitString(run.time_unit); |
| } |
| Out << ","; |
| |
| if (run.counters.find("bytes_per_second") != run.counters.end()) { |
| Out << run.counters.at("bytes_per_second"); |
| } |
| Out << ","; |
| if (run.counters.find("items_per_second") != run.counters.end()) { |
| Out << run.counters.at("items_per_second"); |
| } |
| Out << ","; |
| if (!run.report_label.empty()) { |
| Out << CsvEscape(run.report_label); |
| } |
| Out << ",,"; // for error_occurred and error_message |
| |
| // Print user counters |
| for (const auto& ucn : user_counter_names_) { |
| auto it = run.counters.find(ucn); |
| if (it == run.counters.end()) { |
| Out << ","; |
| } else { |
| Out << "," << it->second; |
| } |
| } |
| Out << '\n'; |
| } |
| |
| } // end namespace benchmark |