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