xref: /aosp_15_r20/test/dittosuite/src/result.cpp (revision 6fa2df46f119dce7527f5beb2814eca0e6f886ac)
1*6fa2df46SAndroid Build Coastguard Worker // Copyright (C) 2021 The Android Open Source Project
2*6fa2df46SAndroid Build Coastguard Worker //
3*6fa2df46SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*6fa2df46SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*6fa2df46SAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*6fa2df46SAndroid Build Coastguard Worker //
7*6fa2df46SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
8*6fa2df46SAndroid Build Coastguard Worker //
9*6fa2df46SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*6fa2df46SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*6fa2df46SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6fa2df46SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*6fa2df46SAndroid Build Coastguard Worker // limitations under the License.
14*6fa2df46SAndroid Build Coastguard Worker 
15*6fa2df46SAndroid Build Coastguard Worker #include <ditto/result.h>
16*6fa2df46SAndroid Build Coastguard Worker #include <ditto/statistics.h>
17*6fa2df46SAndroid Build Coastguard Worker #include <ditto/timespec_utils.h>
18*6fa2df46SAndroid Build Coastguard Worker 
19*6fa2df46SAndroid Build Coastguard Worker #include <google/protobuf/util/json_util.h>
20*6fa2df46SAndroid Build Coastguard Worker 
21*6fa2df46SAndroid Build Coastguard Worker #include <algorithm>
22*6fa2df46SAndroid Build Coastguard Worker #include <fstream>
23*6fa2df46SAndroid Build Coastguard Worker #include <iomanip>
24*6fa2df46SAndroid Build Coastguard Worker #include <iostream>
25*6fa2df46SAndroid Build Coastguard Worker #include <set>
26*6fa2df46SAndroid Build Coastguard Worker #include <string>
27*6fa2df46SAndroid Build Coastguard Worker 
28*6fa2df46SAndroid Build Coastguard Worker const int kSampleDisplayWidth = 16;  // this width is used displaying a sample value
29*6fa2df46SAndroid Build Coastguard Worker const int kTableWidth = 164;  // table width; can be adjusted in case of longer instruction paths
30*6fa2df46SAndroid Build Coastguard Worker const char* kTableDivider = " | ";   // table character divider
31*6fa2df46SAndroid Build Coastguard Worker const int kMaxHistogramHeight = 20;  // used for normalizing the histogram (represents the
32*6fa2df46SAndroid Build Coastguard Worker                                      //  maximum height of the histogram)
33*6fa2df46SAndroid Build Coastguard Worker const int kMaxHistogramWidth = 50;   // used for normalizing the histogram (represents the
34*6fa2df46SAndroid Build Coastguard Worker                                      // maximum width of the histogram)
35*6fa2df46SAndroid Build Coastguard Worker const char kCsvDelimiter = ',';      // delimiter used for .csv files
36*6fa2df46SAndroid Build Coastguard Worker static int bin_size;                 // bin size corresponding to the normalization
37*6fa2df46SAndroid Build Coastguard Worker                                      // of the Oy axis of the histograms
38*6fa2df46SAndroid Build Coastguard Worker 
39*6fa2df46SAndroid Build Coastguard Worker namespace dittosuite {
40*6fa2df46SAndroid Build Coastguard Worker 
Result(const std::string & name,const int repeat)41*6fa2df46SAndroid Build Coastguard Worker Result::Result(const std::string& name, const int repeat) : name_(name), repeat_(repeat) {}
42*6fa2df46SAndroid Build Coastguard Worker 
AddMeasurement(const std::string & name,const std::vector<double> & samples)43*6fa2df46SAndroid Build Coastguard Worker void Result::AddMeasurement(const std::string& name, const std::vector<double>& samples) {
44*6fa2df46SAndroid Build Coastguard Worker   samples_[name] = samples;
45*6fa2df46SAndroid Build Coastguard Worker   AnalyseMeasurement(name);
46*6fa2df46SAndroid Build Coastguard Worker }
47*6fa2df46SAndroid Build Coastguard Worker 
AddSubResult(std::unique_ptr<Result> result)48*6fa2df46SAndroid Build Coastguard Worker void Result::AddSubResult(std::unique_ptr<Result> result) {
49*6fa2df46SAndroid Build Coastguard Worker   sub_results_.push_back(std::move(result));
50*6fa2df46SAndroid Build Coastguard Worker }
51*6fa2df46SAndroid Build Coastguard Worker 
GetSamples(const std::string & measurement_name) const52*6fa2df46SAndroid Build Coastguard Worker std::vector<double> Result::GetSamples(const std::string& measurement_name) const {
53*6fa2df46SAndroid Build Coastguard Worker   return samples_.find(measurement_name)->second;
54*6fa2df46SAndroid Build Coastguard Worker }
55*6fa2df46SAndroid Build Coastguard Worker 
GetRepeat() const56*6fa2df46SAndroid Build Coastguard Worker int Result::GetRepeat() const {
57*6fa2df46SAndroid Build Coastguard Worker   return repeat_;
58*6fa2df46SAndroid Build Coastguard Worker }
59*6fa2df46SAndroid Build Coastguard Worker 
60*6fa2df46SAndroid Build Coastguard Worker // analyse the measurement with the given name, and store
61*6fa2df46SAndroid Build Coastguard Worker // the results in the statistics_ map
AnalyseMeasurement(const std::string & name)62*6fa2df46SAndroid Build Coastguard Worker void Result::AnalyseMeasurement(const std::string& name) {
63*6fa2df46SAndroid Build Coastguard Worker   statistics_[name].min = StatisticsGetMin(samples_[name]);
64*6fa2df46SAndroid Build Coastguard Worker   statistics_[name].max = StatisticsGetMax(samples_[name]);
65*6fa2df46SAndroid Build Coastguard Worker   statistics_[name].mean = StatisticsGetMean(samples_[name]);
66*6fa2df46SAndroid Build Coastguard Worker   statistics_[name].median = StatisticsGetMedian(samples_[name]);
67*6fa2df46SAndroid Build Coastguard Worker   statistics_[name].sd = StatisticsGetSd(samples_[name]);
68*6fa2df46SAndroid Build Coastguard Worker }
69*6fa2df46SAndroid Build Coastguard Worker 
ComputeNextInstructionPath(const std::string & instruction_path)70*6fa2df46SAndroid Build Coastguard Worker std::string Result::ComputeNextInstructionPath(const std::string& instruction_path) {
71*6fa2df46SAndroid Build Coastguard Worker   return instruction_path + (instruction_path != "" ? "/" : "") + name_;
72*6fa2df46SAndroid Build Coastguard Worker }
73*6fa2df46SAndroid Build Coastguard Worker 
Print(const ResultsOutput results_output,const std::string & instruction_path)74*6fa2df46SAndroid Build Coastguard Worker void Result::Print(const ResultsOutput results_output, const std::string& instruction_path) {
75*6fa2df46SAndroid Build Coastguard Worker   switch (results_output) {
76*6fa2df46SAndroid Build Coastguard Worker     case ResultsOutput::kReport:
77*6fa2df46SAndroid Build Coastguard Worker       PrintHistograms(instruction_path);
78*6fa2df46SAndroid Build Coastguard Worker       PrintStatisticsTables();
79*6fa2df46SAndroid Build Coastguard Worker       break;
80*6fa2df46SAndroid Build Coastguard Worker     case ResultsOutput::kCsv:
81*6fa2df46SAndroid Build Coastguard Worker       MakeStatisticsCsv();
82*6fa2df46SAndroid Build Coastguard Worker       break;
83*6fa2df46SAndroid Build Coastguard Worker     case ResultsOutput::kPb:
84*6fa2df46SAndroid Build Coastguard Worker       PrintPb(ToPb());
85*6fa2df46SAndroid Build Coastguard Worker       break;
86*6fa2df46SAndroid Build Coastguard Worker     case ResultsOutput::kNull:
87*6fa2df46SAndroid Build Coastguard Worker       break;
88*6fa2df46SAndroid Build Coastguard Worker   }
89*6fa2df46SAndroid Build Coastguard Worker }
90*6fa2df46SAndroid Build Coastguard Worker 
PrintTableBorder()91*6fa2df46SAndroid Build Coastguard Worker void PrintTableBorder() {
92*6fa2df46SAndroid Build Coastguard Worker   std::cout << std::setfill('-') << std::setw(kTableWidth) << "" << std::setfill(' ');
93*6fa2df46SAndroid Build Coastguard Worker   std::cout << '\n';
94*6fa2df46SAndroid Build Coastguard Worker }
95*6fa2df46SAndroid Build Coastguard Worker 
PrintStatisticsTableHeader()96*6fa2df46SAndroid Build Coastguard Worker void PrintStatisticsTableHeader() {
97*6fa2df46SAndroid Build Coastguard Worker   std::cout << "\x1b[1m";  // beginning of bold
98*6fa2df46SAndroid Build Coastguard Worker   std::cout << '\n';
99*6fa2df46SAndroid Build Coastguard Worker   PrintTableBorder();
100*6fa2df46SAndroid Build Coastguard Worker   std::cout << "| ";  // beginning of table row
101*6fa2df46SAndroid Build Coastguard Worker   std::cout << std::setw(70) << std::left << "Instruction name";
102*6fa2df46SAndroid Build Coastguard Worker   std::cout << kTableDivider;
103*6fa2df46SAndroid Build Coastguard Worker   std::cout << std::setw(15) << std::right << " Min";
104*6fa2df46SAndroid Build Coastguard Worker   std::cout << kTableDivider;
105*6fa2df46SAndroid Build Coastguard Worker   std::cout << std::setw(15) << " Max";
106*6fa2df46SAndroid Build Coastguard Worker   std::cout << kTableDivider;
107*6fa2df46SAndroid Build Coastguard Worker   std::cout << std::setw(15) << " Mean";
108*6fa2df46SAndroid Build Coastguard Worker   std::cout << kTableDivider;
109*6fa2df46SAndroid Build Coastguard Worker   std::cout << std::setw(15) << " Median";
110*6fa2df46SAndroid Build Coastguard Worker   std::cout << kTableDivider;
111*6fa2df46SAndroid Build Coastguard Worker   std::cout << std::setw(15) << " SD";
112*6fa2df46SAndroid Build Coastguard Worker   std::cout << kTableDivider;
113*6fa2df46SAndroid Build Coastguard Worker   std::cout << '\n';
114*6fa2df46SAndroid Build Coastguard Worker   PrintTableBorder();
115*6fa2df46SAndroid Build Coastguard Worker   std::cout << "\x1b[0m";  // ending of bold
116*6fa2df46SAndroid Build Coastguard Worker }
117*6fa2df46SAndroid Build Coastguard Worker 
PrintMeasurementInTable(const int64_t & measurement,const std::string & measurement_name)118*6fa2df46SAndroid Build Coastguard Worker void PrintMeasurementInTable(const int64_t& measurement, const std::string& measurement_name) {
119*6fa2df46SAndroid Build Coastguard Worker   if (measurement_name == "duration") {
120*6fa2df46SAndroid Build Coastguard Worker     std::cout << std::setw(13) << measurement << "ns";
121*6fa2df46SAndroid Build Coastguard Worker   } else if (measurement_name == "bandwidth") {
122*6fa2df46SAndroid Build Coastguard Worker     std::cout << std::setw(11) << measurement << "KB/s";
123*6fa2df46SAndroid Build Coastguard Worker   }
124*6fa2df46SAndroid Build Coastguard Worker }
125*6fa2df46SAndroid Build Coastguard Worker 
126*6fa2df46SAndroid Build Coastguard Worker // Recursive function to print one row at a time
127*6fa2df46SAndroid Build Coastguard Worker // of statistics table content (the instruction path, min, max and mean).
PrintStatisticsTableContent(const std::string & instruction_path,const std::string & measurement_name)128*6fa2df46SAndroid Build Coastguard Worker void Result::PrintStatisticsTableContent(const std::string& instruction_path,
129*6fa2df46SAndroid Build Coastguard Worker                                          const std::string& measurement_name) {
130*6fa2df46SAndroid Build Coastguard Worker   std::string next_instruction_path = ComputeNextInstructionPath(instruction_path);
131*6fa2df46SAndroid Build Coastguard Worker   int subinstruction_level =
132*6fa2df46SAndroid Build Coastguard Worker       std::count(next_instruction_path.begin(), next_instruction_path.end(), '/');
133*6fa2df46SAndroid Build Coastguard Worker   // If the instruction path name contains too many subinstrions,
134*6fa2df46SAndroid Build Coastguard Worker   // print only the last 2 preceded by "../".
135*6fa2df46SAndroid Build Coastguard Worker   if (subinstruction_level > 2) {
136*6fa2df46SAndroid Build Coastguard Worker     std::size_t first_truncate_pos = next_instruction_path.find('/');
137*6fa2df46SAndroid Build Coastguard Worker     next_instruction_path = ".." + next_instruction_path.substr(first_truncate_pos);
138*6fa2df46SAndroid Build Coastguard Worker   }
139*6fa2df46SAndroid Build Coastguard Worker 
140*6fa2df46SAndroid Build Coastguard Worker   // Print table row
141*6fa2df46SAndroid Build Coastguard Worker   if (samples_.find(measurement_name) != samples_.end()) {
142*6fa2df46SAndroid Build Coastguard Worker     std::cout << "| ";  // started new row
143*6fa2df46SAndroid Build Coastguard Worker     std::cout << std::setw(70) << std::left << next_instruction_path << std::right;
144*6fa2df46SAndroid Build Coastguard Worker     std::cout << kTableDivider;
145*6fa2df46SAndroid Build Coastguard Worker     PrintMeasurementInTable(statistics_[measurement_name].min, measurement_name);
146*6fa2df46SAndroid Build Coastguard Worker     std::cout << kTableDivider;
147*6fa2df46SAndroid Build Coastguard Worker     PrintMeasurementInTable(statistics_[measurement_name].max, measurement_name);
148*6fa2df46SAndroid Build Coastguard Worker     std::cout << kTableDivider;
149*6fa2df46SAndroid Build Coastguard Worker     PrintMeasurementInTable(statistics_[measurement_name].mean, measurement_name);
150*6fa2df46SAndroid Build Coastguard Worker     std::cout << kTableDivider;
151*6fa2df46SAndroid Build Coastguard Worker     PrintMeasurementInTable(statistics_[measurement_name].median, measurement_name);
152*6fa2df46SAndroid Build Coastguard Worker     std::cout << kTableDivider;
153*6fa2df46SAndroid Build Coastguard Worker     std::cout << std::setw(15)
154*6fa2df46SAndroid Build Coastguard Worker               << statistics_[measurement_name].sd;  // SD is always printed without measurement unit
155*6fa2df46SAndroid Build Coastguard Worker     std::cout << kTableDivider;                     // ended current row
156*6fa2df46SAndroid Build Coastguard Worker     std::cout << '\n';
157*6fa2df46SAndroid Build Coastguard Worker     PrintTableBorder();
158*6fa2df46SAndroid Build Coastguard Worker   }
159*6fa2df46SAndroid Build Coastguard Worker 
160*6fa2df46SAndroid Build Coastguard Worker   for (const auto& sub_result : sub_results_) {
161*6fa2df46SAndroid Build Coastguard Worker     sub_result->PrintStatisticsTableContent(next_instruction_path, measurement_name);
162*6fa2df46SAndroid Build Coastguard Worker   }
163*6fa2df46SAndroid Build Coastguard Worker }
164*6fa2df46SAndroid Build Coastguard Worker 
GetMeasurementsNames()165*6fa2df46SAndroid Build Coastguard Worker std::set<std::string> Result::GetMeasurementsNames() {
166*6fa2df46SAndroid Build Coastguard Worker   std::set<std::string> names;
167*6fa2df46SAndroid Build Coastguard Worker 
168*6fa2df46SAndroid Build Coastguard Worker   for (const auto& it : samples_) {
169*6fa2df46SAndroid Build Coastguard Worker     names.insert(it.first);
170*6fa2df46SAndroid Build Coastguard Worker   }
171*6fa2df46SAndroid Build Coastguard Worker   for (const auto& sub_result : sub_results_) {
172*6fa2df46SAndroid Build Coastguard Worker     for (const auto& sub_name : sub_result->GetMeasurementsNames()) {
173*6fa2df46SAndroid Build Coastguard Worker       names.insert(sub_name);
174*6fa2df46SAndroid Build Coastguard Worker     }
175*6fa2df46SAndroid Build Coastguard Worker   }
176*6fa2df46SAndroid Build Coastguard Worker 
177*6fa2df46SAndroid Build Coastguard Worker   return names;
178*6fa2df46SAndroid Build Coastguard Worker }
179*6fa2df46SAndroid Build Coastguard Worker 
PrintStatisticsTables()180*6fa2df46SAndroid Build Coastguard Worker void Result::PrintStatisticsTables() {
181*6fa2df46SAndroid Build Coastguard Worker   std::set<std::string> measurement_names = GetMeasurementsNames();
182*6fa2df46SAndroid Build Coastguard Worker   for (const auto& s : measurement_names) {
183*6fa2df46SAndroid Build Coastguard Worker     std::cout << s << " statistics:";
184*6fa2df46SAndroid Build Coastguard Worker     PrintStatisticsTableHeader();
185*6fa2df46SAndroid Build Coastguard Worker     PrintStatisticsTableContent("", s);
186*6fa2df46SAndroid Build Coastguard Worker     std::cout << '\n';
187*6fa2df46SAndroid Build Coastguard Worker   }
188*6fa2df46SAndroid Build Coastguard Worker }
189*6fa2df46SAndroid Build Coastguard Worker 
PrintHistogramHeader(const std::string & measurement_name)190*6fa2df46SAndroid Build Coastguard Worker void Result::PrintHistogramHeader(const std::string& measurement_name) {
191*6fa2df46SAndroid Build Coastguard Worker   if (measurement_name == "duration") {
192*6fa2df46SAndroid Build Coastguard Worker     std::cout.width(kSampleDisplayWidth - 3);
193*6fa2df46SAndroid Build Coastguard Worker     std::cout << "Time(" << time_unit_.name << ") |";
194*6fa2df46SAndroid Build Coastguard Worker     std::cout << " Normalized number of time samples\n";
195*6fa2df46SAndroid Build Coastguard Worker   } else if (measurement_name == "bandwidth") {
196*6fa2df46SAndroid Build Coastguard Worker     std::cout.width(kSampleDisplayWidth - 6);
197*6fa2df46SAndroid Build Coastguard Worker     std::cout << "Bandwidth(" << bandwidth_unit_.name << ") |";
198*6fa2df46SAndroid Build Coastguard Worker     std::cout << " Normalized number of bandwidth samples\n";
199*6fa2df46SAndroid Build Coastguard Worker   }
200*6fa2df46SAndroid Build Coastguard Worker   std::cout << std::setfill('-') << std::setw(kMaxHistogramWidth) << "" << std::setfill(' ');
201*6fa2df46SAndroid Build Coastguard Worker   std::cout << '\n';
202*6fa2df46SAndroid Build Coastguard Worker }
203*6fa2df46SAndroid Build Coastguard Worker 
204*6fa2df46SAndroid Build Coastguard Worker // makes (normalized) histogram from vector
MakeHistogramFromVector(const std::vector<int> & freq_vector,const int min_value)205*6fa2df46SAndroid Build Coastguard Worker void Result::MakeHistogramFromVector(const std::vector<int>& freq_vector, const int min_value) {
206*6fa2df46SAndroid Build Coastguard Worker   int sum = 0;
207*6fa2df46SAndroid Build Coastguard Worker   int max_frequency = *std::max_element(freq_vector.begin(), freq_vector.end());
208*6fa2df46SAndroid Build Coastguard Worker   for (std::size_t i = 0; i < freq_vector.size(); i++) {
209*6fa2df46SAndroid Build Coastguard Worker     std::cout.width(kSampleDisplayWidth);
210*6fa2df46SAndroid Build Coastguard Worker     std::cout << min_value + bin_size * i << kTableDivider;
211*6fa2df46SAndroid Build Coastguard Worker 
212*6fa2df46SAndroid Build Coastguard Worker     int hist_width = ceil(static_cast<double>(freq_vector[i]) * kMaxHistogramWidth / max_frequency);
213*6fa2df46SAndroid Build Coastguard Worker     std::cout << std::setfill('#') << std::setw(hist_width) << "" << std::setfill(' ');
214*6fa2df46SAndroid Build Coastguard Worker 
215*6fa2df46SAndroid Build Coastguard Worker     std::cout << " { " << freq_vector[i] << " }\n";
216*6fa2df46SAndroid Build Coastguard Worker 
217*6fa2df46SAndroid Build Coastguard Worker     sum += freq_vector[i];
218*6fa2df46SAndroid Build Coastguard Worker   }
219*6fa2df46SAndroid Build Coastguard Worker 
220*6fa2df46SAndroid Build Coastguard Worker   std::cout << '\n';
221*6fa2df46SAndroid Build Coastguard Worker   std::cout << "Total samples: { " << sum << " }\n";
222*6fa2df46SAndroid Build Coastguard Worker }
223*6fa2df46SAndroid Build Coastguard Worker 
224*6fa2df46SAndroid Build Coastguard Worker // makes and returns the normalized frequency vector
ComputeNormalizedFrequencyVector(const std::string & measurement_name)225*6fa2df46SAndroid Build Coastguard Worker std::vector<int> Result::ComputeNormalizedFrequencyVector(const std::string& measurement_name) {
226*6fa2df46SAndroid Build Coastguard Worker   int64_t min_value = statistics_[measurement_name].min;
227*6fa2df46SAndroid Build Coastguard Worker   if (measurement_name == "duration") {
228*6fa2df46SAndroid Build Coastguard Worker     min_value /= time_unit_.dividing_factor;
229*6fa2df46SAndroid Build Coastguard Worker   } else if (measurement_name == "bandwidth") {
230*6fa2df46SAndroid Build Coastguard Worker     min_value /= bandwidth_unit_.dividing_factor;
231*6fa2df46SAndroid Build Coastguard Worker   }
232*6fa2df46SAndroid Build Coastguard Worker 
233*6fa2df46SAndroid Build Coastguard Worker   std::vector<int> freq_vector(kMaxHistogramHeight, 0);
234*6fa2df46SAndroid Build Coastguard Worker   for (const auto& sample : samples_[measurement_name]) {
235*6fa2df46SAndroid Build Coastguard Worker     int64_t sample_copy = sample;
236*6fa2df46SAndroid Build Coastguard Worker     if (measurement_name == "duration") {
237*6fa2df46SAndroid Build Coastguard Worker       sample_copy /= time_unit_.dividing_factor;
238*6fa2df46SAndroid Build Coastguard Worker     } else if (measurement_name == "bandwidth") {
239*6fa2df46SAndroid Build Coastguard Worker       sample_copy /= bandwidth_unit_.dividing_factor;
240*6fa2df46SAndroid Build Coastguard Worker     }
241*6fa2df46SAndroid Build Coastguard Worker     int64_t bin = (sample_copy - min_value) / bin_size;
242*6fa2df46SAndroid Build Coastguard Worker 
243*6fa2df46SAndroid Build Coastguard Worker     freq_vector[bin]++;
244*6fa2df46SAndroid Build Coastguard Worker   }
245*6fa2df46SAndroid Build Coastguard Worker   return freq_vector;
246*6fa2df46SAndroid Build Coastguard Worker }
247*6fa2df46SAndroid Build Coastguard Worker 
GetTimeUnit(const int64_t min_value)248*6fa2df46SAndroid Build Coastguard Worker Result::TimeUnit Result::GetTimeUnit(const int64_t min_value) {
249*6fa2df46SAndroid Build Coastguard Worker   TimeUnit result;
250*6fa2df46SAndroid Build Coastguard Worker   if (min_value <= 1e7) {
251*6fa2df46SAndroid Build Coastguard Worker     // time unit in nanoseconds
252*6fa2df46SAndroid Build Coastguard Worker     result.dividing_factor = 1;
253*6fa2df46SAndroid Build Coastguard Worker     result.name = "ns";
254*6fa2df46SAndroid Build Coastguard Worker   } else if (min_value <= 1e10) {
255*6fa2df46SAndroid Build Coastguard Worker     // time unit in microseconds
256*6fa2df46SAndroid Build Coastguard Worker     result.dividing_factor = 1e3;
257*6fa2df46SAndroid Build Coastguard Worker     result.name = "us";
258*6fa2df46SAndroid Build Coastguard Worker   } else if (min_value <= 1e13) {
259*6fa2df46SAndroid Build Coastguard Worker     // time unit in milliseconds
260*6fa2df46SAndroid Build Coastguard Worker     result.dividing_factor = 1e6;
261*6fa2df46SAndroid Build Coastguard Worker     result.name = "ms";
262*6fa2df46SAndroid Build Coastguard Worker   } else {
263*6fa2df46SAndroid Build Coastguard Worker     // time unit in seconds
264*6fa2df46SAndroid Build Coastguard Worker     result.dividing_factor = 1e9;
265*6fa2df46SAndroid Build Coastguard Worker     result.name = "s";
266*6fa2df46SAndroid Build Coastguard Worker   }
267*6fa2df46SAndroid Build Coastguard Worker   return result;
268*6fa2df46SAndroid Build Coastguard Worker }
269*6fa2df46SAndroid Build Coastguard Worker 
GetBandwidthUnit(const int64_t min_value)270*6fa2df46SAndroid Build Coastguard Worker Result::BandwidthUnit Result::GetBandwidthUnit(const int64_t min_value) {
271*6fa2df46SAndroid Build Coastguard Worker   BandwidthUnit result;
272*6fa2df46SAndroid Build Coastguard Worker   if (min_value <= (1 << 15)) {
273*6fa2df46SAndroid Build Coastguard Worker     // bandwidth unit in KB/s
274*6fa2df46SAndroid Build Coastguard Worker     result.dividing_factor = 1;
275*6fa2df46SAndroid Build Coastguard Worker     result.name = "KiB/s";
276*6fa2df46SAndroid Build Coastguard Worker   } else if (min_value <= (1 << 25)) {
277*6fa2df46SAndroid Build Coastguard Worker     // bandwidth unit in MB/s
278*6fa2df46SAndroid Build Coastguard Worker     result.dividing_factor = 1 << 10;
279*6fa2df46SAndroid Build Coastguard Worker     result.name = "MiB/s";
280*6fa2df46SAndroid Build Coastguard Worker   } else {
281*6fa2df46SAndroid Build Coastguard Worker     // bandwidth unit in GB/s
282*6fa2df46SAndroid Build Coastguard Worker     result.dividing_factor = 1 << 20;
283*6fa2df46SAndroid Build Coastguard Worker     result.name = "GiB/s";
284*6fa2df46SAndroid Build Coastguard Worker   }
285*6fa2df46SAndroid Build Coastguard Worker   return result;
286*6fa2df46SAndroid Build Coastguard Worker }
287*6fa2df46SAndroid Build Coastguard Worker 
PrintHistograms(const std::string & instruction_path)288*6fa2df46SAndroid Build Coastguard Worker void Result::PrintHistograms(const std::string& instruction_path) {
289*6fa2df46SAndroid Build Coastguard Worker   std::string next_instruction_path = ComputeNextInstructionPath(instruction_path);
290*6fa2df46SAndroid Build Coastguard Worker   std::cout << "\x1b[1m";  // beginning of bold
291*6fa2df46SAndroid Build Coastguard Worker   std::cout << "Instruction path: " << next_instruction_path;
292*6fa2df46SAndroid Build Coastguard Worker   std::cout << "\x1b[0m";  // ending of bold
293*6fa2df46SAndroid Build Coastguard Worker   std::cout << "\n\n";
294*6fa2df46SAndroid Build Coastguard Worker 
295*6fa2df46SAndroid Build Coastguard Worker   for (const auto& sample : samples_) {
296*6fa2df46SAndroid Build Coastguard Worker     int64_t min_value = statistics_[sample.first].min;
297*6fa2df46SAndroid Build Coastguard Worker     int64_t max_value = statistics_[sample.first].max;
298*6fa2df46SAndroid Build Coastguard Worker     if (sample.first == "duration") {
299*6fa2df46SAndroid Build Coastguard Worker       time_unit_ = GetTimeUnit(statistics_[sample.first].min);
300*6fa2df46SAndroid Build Coastguard Worker       min_value /= time_unit_.dividing_factor;
301*6fa2df46SAndroid Build Coastguard Worker       max_value /= time_unit_.dividing_factor;
302*6fa2df46SAndroid Build Coastguard Worker     } else if (sample.first == "bandwidth") {
303*6fa2df46SAndroid Build Coastguard Worker       bandwidth_unit_ = GetBandwidthUnit(min_value);
304*6fa2df46SAndroid Build Coastguard Worker       min_value /= bandwidth_unit_.dividing_factor;
305*6fa2df46SAndroid Build Coastguard Worker       max_value /= bandwidth_unit_.dividing_factor;
306*6fa2df46SAndroid Build Coastguard Worker     }
307*6fa2df46SAndroid Build Coastguard Worker     bin_size = (max_value - min_value) / kMaxHistogramHeight + 1;
308*6fa2df46SAndroid Build Coastguard Worker 
309*6fa2df46SAndroid Build Coastguard Worker     std::vector<int> freq_vector = ComputeNormalizedFrequencyVector(sample.first);
310*6fa2df46SAndroid Build Coastguard Worker     PrintHistogramHeader(sample.first);
311*6fa2df46SAndroid Build Coastguard Worker     MakeHistogramFromVector(freq_vector, min_value);
312*6fa2df46SAndroid Build Coastguard Worker     std::cout << "\n\n";
313*6fa2df46SAndroid Build Coastguard Worker 
314*6fa2df46SAndroid Build Coastguard Worker     for (const auto& sub_result : sub_results_) {
315*6fa2df46SAndroid Build Coastguard Worker       sub_result->PrintHistograms(next_instruction_path);
316*6fa2df46SAndroid Build Coastguard Worker     }
317*6fa2df46SAndroid Build Coastguard Worker   }
318*6fa2df46SAndroid Build Coastguard Worker }
319*6fa2df46SAndroid Build Coastguard Worker 
320*6fa2df46SAndroid Build Coastguard Worker // Print statistic measurement with given name in .csv
PrintMeasurementStatisticInCsv(std::ostream & csv_stream,const std::string & name)321*6fa2df46SAndroid Build Coastguard Worker void Result::PrintMeasurementStatisticInCsv(std::ostream& csv_stream, const std::string& name) {
322*6fa2df46SAndroid Build Coastguard Worker   csv_stream << kCsvDelimiter;
323*6fa2df46SAndroid Build Coastguard Worker   csv_stream << statistics_[name].min << kCsvDelimiter;
324*6fa2df46SAndroid Build Coastguard Worker   csv_stream << statistics_[name].max << kCsvDelimiter;
325*6fa2df46SAndroid Build Coastguard Worker   csv_stream << statistics_[name].mean << kCsvDelimiter;
326*6fa2df46SAndroid Build Coastguard Worker   csv_stream << statistics_[name].median << kCsvDelimiter;
327*6fa2df46SAndroid Build Coastguard Worker   csv_stream << statistics_[name].sd;
328*6fa2df46SAndroid Build Coastguard Worker }
329*6fa2df46SAndroid Build Coastguard Worker 
PrintEmptyMeasurementInCsv(std::ostream & csv_stream)330*6fa2df46SAndroid Build Coastguard Worker void PrintEmptyMeasurementInCsv(std::ostream& csv_stream) {
331*6fa2df46SAndroid Build Coastguard Worker   csv_stream << std::setfill(kCsvDelimiter) << std::setw(5) << "" << std::setfill(' ');
332*6fa2df46SAndroid Build Coastguard Worker }
333*6fa2df46SAndroid Build Coastguard Worker 
334*6fa2df46SAndroid Build Coastguard Worker // Recursive function to print one row at a time using the .csv stream given as a parameter
335*6fa2df46SAndroid Build Coastguard Worker // of statistics table content (the instruction path, min, max, mean and SD).
PrintStatisticInCsv(std::ostream & csv_stream,const std::string & instruction_path,const std::set<std::string> & measurements_names)336*6fa2df46SAndroid Build Coastguard Worker void Result::PrintStatisticInCsv(std::ostream& csv_stream, const std::string& instruction_path,
337*6fa2df46SAndroid Build Coastguard Worker                                  const std::set<std::string>& measurements_names) {
338*6fa2df46SAndroid Build Coastguard Worker   std::string next_instruction_path = ComputeNextInstructionPath(instruction_path);
339*6fa2df46SAndroid Build Coastguard Worker 
340*6fa2df46SAndroid Build Coastguard Worker   // print one row in csv
341*6fa2df46SAndroid Build Coastguard Worker   csv_stream << next_instruction_path;
342*6fa2df46SAndroid Build Coastguard Worker   for (const auto& measurement : measurements_names) {
343*6fa2df46SAndroid Build Coastguard Worker     if (statistics_.find(measurement) != statistics_.end()) {
344*6fa2df46SAndroid Build Coastguard Worker       PrintMeasurementStatisticInCsv(csv_stream, measurement);
345*6fa2df46SAndroid Build Coastguard Worker     } else {
346*6fa2df46SAndroid Build Coastguard Worker       PrintEmptyMeasurementInCsv(csv_stream);
347*6fa2df46SAndroid Build Coastguard Worker     }
348*6fa2df46SAndroid Build Coastguard Worker   }
349*6fa2df46SAndroid Build Coastguard Worker   csv_stream << '\n';
350*6fa2df46SAndroid Build Coastguard Worker 
351*6fa2df46SAndroid Build Coastguard Worker   for (const auto& sub_result : sub_results_) {
352*6fa2df46SAndroid Build Coastguard Worker     sub_result->PrintStatisticInCsv(csv_stream, next_instruction_path, measurements_names);
353*6fa2df46SAndroid Build Coastguard Worker   }
354*6fa2df46SAndroid Build Coastguard Worker }
355*6fa2df46SAndroid Build Coastguard Worker 
PrintCsvHeader(std::ostream & csv_stream,const std::set<std::string> & measurement_names)356*6fa2df46SAndroid Build Coastguard Worker void PrintCsvHeader(std::ostream& csv_stream, const std::set<std::string>& measurement_names) {
357*6fa2df46SAndroid Build Coastguard Worker   csv_stream << "Instruction path";
358*6fa2df46SAndroid Build Coastguard Worker   for (const auto& measurement : measurement_names) {
359*6fa2df46SAndroid Build Coastguard Worker     csv_stream << kCsvDelimiter;
360*6fa2df46SAndroid Build Coastguard Worker     csv_stream << measurement << " min" << kCsvDelimiter;
361*6fa2df46SAndroid Build Coastguard Worker     csv_stream << measurement << " max" << kCsvDelimiter;
362*6fa2df46SAndroid Build Coastguard Worker     csv_stream << measurement << " mean" << kCsvDelimiter;
363*6fa2df46SAndroid Build Coastguard Worker     csv_stream << measurement << " median" << kCsvDelimiter;
364*6fa2df46SAndroid Build Coastguard Worker     csv_stream << measurement << " SD";
365*6fa2df46SAndroid Build Coastguard Worker   }
366*6fa2df46SAndroid Build Coastguard Worker   csv_stream << '\n';
367*6fa2df46SAndroid Build Coastguard Worker }
368*6fa2df46SAndroid Build Coastguard Worker 
MakeStatisticsCsv()369*6fa2df46SAndroid Build Coastguard Worker void Result::MakeStatisticsCsv() {
370*6fa2df46SAndroid Build Coastguard Worker   std::ostream csv_stream(std::cout.rdbuf());
371*6fa2df46SAndroid Build Coastguard Worker 
372*6fa2df46SAndroid Build Coastguard Worker   std::set<std::string> measurements_names = GetMeasurementsNames();
373*6fa2df46SAndroid Build Coastguard Worker   PrintCsvHeader(csv_stream, measurements_names);
374*6fa2df46SAndroid Build Coastguard Worker 
375*6fa2df46SAndroid Build Coastguard Worker   PrintStatisticInCsv(csv_stream, "", measurements_names);
376*6fa2df46SAndroid Build Coastguard Worker }
377*6fa2df46SAndroid Build Coastguard Worker 
StoreStatisticsInPb(dittosuiteproto::Metrics * metrics,const std::string & name)378*6fa2df46SAndroid Build Coastguard Worker void Result::StoreStatisticsInPb(dittosuiteproto::Metrics* metrics,
379*6fa2df46SAndroid Build Coastguard Worker                                            const std::string& name) {
380*6fa2df46SAndroid Build Coastguard Worker   metrics->set_name(name);
381*6fa2df46SAndroid Build Coastguard Worker   metrics->set_min(statistics_[name].min);
382*6fa2df46SAndroid Build Coastguard Worker   metrics->set_max(statistics_[name].max);
383*6fa2df46SAndroid Build Coastguard Worker   metrics->set_mean(statistics_[name].mean);
384*6fa2df46SAndroid Build Coastguard Worker   metrics->set_median(statistics_[name].median);
385*6fa2df46SAndroid Build Coastguard Worker   metrics->set_sd(statistics_[name].sd);
386*6fa2df46SAndroid Build Coastguard Worker }
387*6fa2df46SAndroid Build Coastguard Worker 
__ToPb(dittosuiteproto::Result * result_pb)388*6fa2df46SAndroid Build Coastguard Worker void Result::__ToPb(dittosuiteproto::Result* result_pb) {
389*6fa2df46SAndroid Build Coastguard Worker   result_pb->set_name(name_);
390*6fa2df46SAndroid Build Coastguard Worker 
391*6fa2df46SAndroid Build Coastguard Worker 
392*6fa2df46SAndroid Build Coastguard Worker   for (const auto &stats : statistics_) {
393*6fa2df46SAndroid Build Coastguard Worker       StoreStatisticsInPb(result_pb->add_metrics(), stats.first);
394*6fa2df46SAndroid Build Coastguard Worker   }
395*6fa2df46SAndroid Build Coastguard Worker 
396*6fa2df46SAndroid Build Coastguard Worker   for (const auto& sub_result : sub_results_) {
397*6fa2df46SAndroid Build Coastguard Worker     sub_result->__ToPb(result_pb->add_sub_result());
398*6fa2df46SAndroid Build Coastguard Worker   }
399*6fa2df46SAndroid Build Coastguard Worker }
400*6fa2df46SAndroid Build Coastguard Worker 
ToPb()401*6fa2df46SAndroid Build Coastguard Worker dittosuiteproto::Result Result::ToPb() {
402*6fa2df46SAndroid Build Coastguard Worker   dittosuiteproto::Result result_pb;
403*6fa2df46SAndroid Build Coastguard Worker   std::set<std::string> measurements_names = GetMeasurementsNames();
404*6fa2df46SAndroid Build Coastguard Worker 
405*6fa2df46SAndroid Build Coastguard Worker   __ToPb(&result_pb);
406*6fa2df46SAndroid Build Coastguard Worker 
407*6fa2df46SAndroid Build Coastguard Worker   return result_pb;
408*6fa2df46SAndroid Build Coastguard Worker }
409*6fa2df46SAndroid Build Coastguard Worker 
SetStatistics(const std::string & name,const Result::Statistics & statistics)410*6fa2df46SAndroid Build Coastguard Worker void Result::SetStatistics(const std::string& name, const Result::Statistics& statistics) {
411*6fa2df46SAndroid Build Coastguard Worker   statistics_[name] = statistics;
412*6fa2df46SAndroid Build Coastguard Worker }
413*6fa2df46SAndroid Build Coastguard Worker 
PrintPb(const dittosuiteproto::Result & pb)414*6fa2df46SAndroid Build Coastguard Worker void PrintPb(const dittosuiteproto::Result &pb) {
415*6fa2df46SAndroid Build Coastguard Worker   std::string json;
416*6fa2df46SAndroid Build Coastguard Worker   google::protobuf::util::JsonPrintOptions options;
417*6fa2df46SAndroid Build Coastguard Worker 
418*6fa2df46SAndroid Build Coastguard Worker   options.add_whitespace = true;
419*6fa2df46SAndroid Build Coastguard Worker   auto status = google::protobuf::util::MessageToJsonString(pb, &json, options);
420*6fa2df46SAndroid Build Coastguard Worker   if (status.ok()) {
421*6fa2df46SAndroid Build Coastguard Worker     std::ostream pb_stream(std::cout.rdbuf());
422*6fa2df46SAndroid Build Coastguard Worker     pb_stream << json << std::endl;
423*6fa2df46SAndroid Build Coastguard Worker   }
424*6fa2df46SAndroid Build Coastguard Worker }
425*6fa2df46SAndroid Build Coastguard Worker 
FromPb(const dittosuiteproto::Result & pb)426*6fa2df46SAndroid Build Coastguard Worker std::unique_ptr<Result> Result::FromPb(const dittosuiteproto::Result& pb) {
427*6fa2df46SAndroid Build Coastguard Worker   auto result = std::make_unique<Result>(pb.name(), 1);
428*6fa2df46SAndroid Build Coastguard Worker 
429*6fa2df46SAndroid Build Coastguard Worker   for (const auto& m : pb.metrics()) {
430*6fa2df46SAndroid Build Coastguard Worker     Result::Statistics stats = {
431*6fa2df46SAndroid Build Coastguard Worker         .min = m.min(), .max = m.max(), .mean = m.mean(), .median = m.median(), .sd = m.sd()};
432*6fa2df46SAndroid Build Coastguard Worker     result->SetStatistics(m.name(), stats);
433*6fa2df46SAndroid Build Coastguard Worker   }
434*6fa2df46SAndroid Build Coastguard Worker 
435*6fa2df46SAndroid Build Coastguard Worker   for (const auto& r : pb.sub_result()) {
436*6fa2df46SAndroid Build Coastguard Worker     result->AddSubResult(Result::FromPb(r));
437*6fa2df46SAndroid Build Coastguard Worker   }
438*6fa2df46SAndroid Build Coastguard Worker 
439*6fa2df46SAndroid Build Coastguard Worker   return result;
440*6fa2df46SAndroid Build Coastguard Worker }
441*6fa2df46SAndroid Build Coastguard Worker 
442*6fa2df46SAndroid Build Coastguard Worker }  // namespace dittosuite
443