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