xref: /aosp_15_r20/external/webrtc/api/test/metrics/chrome_perf_dashboard_metrics_exporter.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 #include "api/test/metrics/chrome_perf_dashboard_metrics_exporter.h"
11 
12 #include <stdio.h>
13 
14 #include <memory>
15 #include <string>
16 #include <vector>
17 
18 #include "absl/memory/memory.h"
19 #include "absl/strings/string_view.h"
20 #include "api/array_view.h"
21 #include "api/test/metrics/metric.h"
22 #include "test/testsupport/file_utils.h"
23 #include "test/testsupport/perf_test_histogram_writer.h"
24 #include "test/testsupport/perf_test_result_writer.h"
25 
26 namespace webrtc {
27 namespace test {
28 namespace {
29 
ToChromePerfDashboardUnit(Unit unit)30 std::string ToChromePerfDashboardUnit(Unit unit) {
31   switch (unit) {
32     case Unit::kMilliseconds:
33       return "msBestFitFormat";
34     case Unit::kPercent:
35       return "n%";
36     case Unit::kBytes:
37       return "sizeInBytes";
38     case Unit::kKilobitsPerSecond:
39       // Chrome Perf Dashboard doesn't have kpbs units, so we change the unit
40       // and value accordingly.
41       return "bytesPerSecond";
42     case Unit::kHertz:
43       return "Hz";
44     case Unit::kUnitless:
45       return "unitless";
46     case Unit::kCount:
47       return "count";
48   }
49 }
50 
ToChromePerfDashboardValue(double value,Unit unit)51 double ToChromePerfDashboardValue(double value, Unit unit) {
52   switch (unit) {
53     case Unit::kKilobitsPerSecond:
54       // Chrome Perf Dashboard doesn't have kpbs units, so we change the unit
55       // and value accordingly.
56       return value * 1000 / 8;
57     default:
58       return value;
59   }
60 }
61 
ToChromePerfDashboardImproveDirection(ImprovementDirection direction)62 ImproveDirection ToChromePerfDashboardImproveDirection(
63     ImprovementDirection direction) {
64   switch (direction) {
65     case ImprovementDirection::kBiggerIsBetter:
66       return ImproveDirection::kBiggerIsBetter;
67     case ImprovementDirection::kNeitherIsBetter:
68       return ImproveDirection::kNone;
69     case ImprovementDirection::kSmallerIsBetter:
70       return ImproveDirection::kSmallerIsBetter;
71   }
72 }
73 
WriteMetricsToFile(const std::string & path,const std::string & data)74 bool WriteMetricsToFile(const std::string& path, const std::string& data) {
75   CreateDir(DirName(path));
76   FILE* output = fopen(path.c_str(), "wb");
77   if (output == NULL) {
78     printf("Failed to write to %s.\n", path.c_str());
79     return false;
80   }
81   size_t written = fwrite(data.c_str(), sizeof(char), data.size(), output);
82   fclose(output);
83 
84   if (written != data.size()) {
85     size_t expected = data.size();
86     printf("Wrote %zu, tried to write %zu\n", written, expected);
87     return false;
88   }
89   return true;
90 }
91 
IsEmpty(const Metric::Stats & stats)92 bool IsEmpty(const Metric::Stats& stats) {
93   return !stats.mean.has_value() && !stats.stddev.has_value() &&
94          !stats.min.has_value() && !stats.max.has_value();
95 }
96 
97 }  // namespace
98 
ChromePerfDashboardMetricsExporter(absl::string_view export_file_path)99 ChromePerfDashboardMetricsExporter::ChromePerfDashboardMetricsExporter(
100     absl::string_view export_file_path)
101     : export_file_path_(export_file_path) {}
102 
Export(rtc::ArrayView<const Metric> metrics)103 bool ChromePerfDashboardMetricsExporter::Export(
104     rtc::ArrayView<const Metric> metrics) {
105   std::unique_ptr<PerfTestResultWriter> writer =
106       absl::WrapUnique<PerfTestResultWriter>(CreateHistogramWriter());
107   for (const Metric& metric : metrics) {
108     if (metric.time_series.samples.empty() && IsEmpty(metric.stats)) {
109       // If there were no data collected for the metric it is expected that 0
110       // will be exported, so add 0 to the samples.
111       writer->LogResult(
112           metric.name, metric.test_case,
113           ToChromePerfDashboardValue(0, metric.unit),
114           ToChromePerfDashboardUnit(metric.unit),
115           /*important=*/false,
116           ToChromePerfDashboardImproveDirection(metric.improvement_direction));
117       continue;
118     }
119 
120     if (metric.time_series.samples.empty()) {
121       writer->LogResultMeanAndError(
122           metric.name, metric.test_case,
123           ToChromePerfDashboardValue(*metric.stats.mean, metric.unit),
124           ToChromePerfDashboardValue(*metric.stats.stddev, metric.unit),
125           ToChromePerfDashboardUnit(metric.unit),
126           /*important=*/false,
127           ToChromePerfDashboardImproveDirection(metric.improvement_direction));
128       continue;
129     }
130 
131     std::vector<double> samples(metric.time_series.samples.size());
132     for (size_t i = 0; i < metric.time_series.samples.size(); ++i) {
133       samples[i] = ToChromePerfDashboardValue(
134           metric.time_series.samples[i].value, metric.unit);
135     }
136     writer->LogResultList(
137         metric.name, metric.test_case, samples,
138         ToChromePerfDashboardUnit(metric.unit),
139         /*important=*/false,
140         ToChromePerfDashboardImproveDirection(metric.improvement_direction));
141   }
142   return WriteMetricsToFile(export_file_path_, writer->Serialize());
143 }
144 
145 }  // namespace test
146 }  // namespace webrtc
147