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 "benchmark/reporter.h" 16 #include "complexity.h" 17 18 #include <algorithm> 19 #include <cstdint> 20 #include <iostream> 21 #include <string> 22 #include <tuple> 23 #include <vector> 24 25 #include "string_util.h" 26 #include "timers.h" 27 #include "check.h" 28 29 // File format reference: http://edoceo.com/utilitas/csv-file-format. 30 31 namespace benchmark { 32 33 namespace { 34 std::vector<std::string> elements = { 35 "name", "iterations", "real_time", "cpu_time", 36 "time_unit", "bytes_per_second", "items_per_second", "label", 37 "error_occurred", "error_message"}; 38 } 39 40 bool CSVReporter::ReportContext(const Context& context) { 41 PrintBasicContext(&GetErrorStream(), context); 42 return true; 43 } 44 45 void CSVReporter::ReportRuns(const std::vector<Run> & reports) { 46 std::ostream& Out = GetOutputStream(); 47 48 if (!printed_header_) { 49 // save the names of all the user counters 50 for (const auto& run : reports) { 51 for (const auto& cnt : run.counters) { 52 user_counter_names_.insert(cnt.first); 53 } 54 } 55 56 // print the header 57 for (auto B = elements.begin(); B != elements.end();) { 58 Out << *B++; 59 if (B != elements.end()) Out << ","; 60 } 61 for (auto B = user_counter_names_.begin(); B != user_counter_names_.end();) { 62 Out << ",\"" << *B++ << "\""; 63 } 64 Out << "\n"; 65 66 printed_header_ = true; 67 } else { 68 // check that all the current counters are saved in the name set 69 for (const auto& run : reports) { 70 for (const auto& cnt : run.counters) { 71 CHECK(user_counter_names_.find(cnt.first) != user_counter_names_.end()) 72 << "All counters must be present in each run. " 73 << "Counter named \"" << cnt.first 74 << "\" was not in a run after being added to the header"; 75 } 76 } 77 } 78 79 // print results for each run 80 for (const auto& run : reports) { 81 PrintRunData(run); 82 } 83 84 } 85 86 void CSVReporter::PrintRunData(const Run & run) { 87 std::ostream& Out = GetOutputStream(); 88 89 // Field with embedded double-quote characters must be doubled and the field 90 // delimited with double-quotes. 91 std::string name = run.benchmark_name; 92 ReplaceAll(&name, "\"", "\"\""); 93 Out << '"' << name << "\","; 94 if (run.error_occurred) { 95 Out << std::string(elements.size() - 3, ','); 96 Out << "true,"; 97 std::string msg = run.error_message; 98 ReplaceAll(&msg, "\"", "\"\""); 99 Out << '"' << msg << "\"\n"; 100 return; 101 } 102 103 // Do not print iteration on bigO and RMS report 104 if (!run.report_big_o && !run.report_rms) { 105 Out << run.iterations; 106 } 107 Out << ","; 108 109 Out << run.GetAdjustedRealTime() << ","; 110 Out << run.GetAdjustedCPUTime() << ","; 111 112 // Do not print timeLabel on bigO and RMS report 113 if (run.report_big_o) { 114 Out << GetBigOString(run.complexity); 115 } else if (!run.report_rms) { 116 Out << GetTimeUnitString(run.time_unit); 117 } 118 Out << ","; 119 120 if (run.bytes_per_second > 0.0) { 121 Out << run.bytes_per_second; 122 } 123 Out << ","; 124 if (run.items_per_second > 0.0) { 125 Out << run.items_per_second; 126 } 127 Out << ","; 128 if (!run.report_label.empty()) { 129 // Field with embedded double-quote characters must be doubled and the field 130 // delimited with double-quotes. 131 std::string label = run.report_label; 132 ReplaceAll(&label, "\"", "\"\""); 133 Out << "\"" << label << "\""; 134 } 135 Out << ",,"; // for error_occurred and error_message 136 137 // Print user counters 138 for (const auto &ucn : user_counter_names_) { 139 auto it = run.counters.find(ucn); 140 CHECK(it != run.counters.end()); 141 Out << "," << it->second; 142 } 143 Out << '\n'; 144 } 145 146 } // end namespace benchmark 147