xref: /aosp_15_r20/external/webrtc/api/test/metrics/metrics_set_proto_file_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/metrics_set_proto_file_exporter.h"
11 
12 #include <stdio.h>
13 
14 #include <string>
15 
16 #include "api/test/metrics/metric.h"
17 #include "rtc_base/logging.h"
18 #include "test/testsupport/file_utils.h"
19 
20 #if WEBRTC_ENABLE_PROTOBUF
21 #include "api/test/metrics/proto/metric.pb.h"
22 #endif
23 
24 namespace webrtc {
25 namespace test {
26 namespace {
27 
28 #if WEBRTC_ENABLE_PROTOBUF
ToProtoUnit(Unit unit)29 webrtc::test_metrics::Unit ToProtoUnit(Unit unit) {
30   switch (unit) {
31     case Unit::kMilliseconds:
32       return webrtc::test_metrics::Unit::MILLISECONDS;
33     case Unit::kPercent:
34       return webrtc::test_metrics::Unit::PERCENT;
35     case Unit::kBytes:
36       return webrtc::test_metrics::Unit::BYTES;
37     case Unit::kKilobitsPerSecond:
38       return webrtc::test_metrics::Unit::KILOBITS_PER_SECOND;
39     case Unit::kHertz:
40       return webrtc::test_metrics::Unit::HERTZ;
41     case Unit::kUnitless:
42       return webrtc::test_metrics::Unit::UNITLESS;
43     case Unit::kCount:
44       return webrtc::test_metrics::Unit::COUNT;
45   }
46 }
47 
ToProtoImprovementDirection(ImprovementDirection direction)48 webrtc::test_metrics::ImprovementDirection ToProtoImprovementDirection(
49     ImprovementDirection direction) {
50   switch (direction) {
51     case ImprovementDirection::kBiggerIsBetter:
52       return webrtc::test_metrics::ImprovementDirection::BIGGER_IS_BETTER;
53     case ImprovementDirection::kNeitherIsBetter:
54       return webrtc::test_metrics::ImprovementDirection::NEITHER_IS_BETTER;
55     case ImprovementDirection::kSmallerIsBetter:
56       return webrtc::test_metrics::ImprovementDirection::SMALLER_IS_BETTER;
57   }
58 }
59 
SetTimeSeries(const Metric::TimeSeries & time_series,webrtc::test_metrics::Metric::TimeSeries * proto_time_series)60 void SetTimeSeries(
61     const Metric::TimeSeries& time_series,
62     webrtc::test_metrics::Metric::TimeSeries* proto_time_series) {
63   for (const Metric::TimeSeries::Sample& sample : time_series.samples) {
64     webrtc::test_metrics::Metric::TimeSeries::Sample* proto_sample =
65         proto_time_series->add_samples();
66     proto_sample->set_value(sample.value);
67     proto_sample->set_timestamp_us(sample.timestamp.us());
68     for (const auto& [key, value] : sample.sample_metadata) {
69       proto_sample->mutable_sample_metadata()->insert({key, value});
70     }
71   }
72 }
73 
SetStats(const Metric::Stats & stats,webrtc::test_metrics::Metric::Stats * proto_stats)74 void SetStats(const Metric::Stats& stats,
75               webrtc::test_metrics::Metric::Stats* proto_stats) {
76   if (stats.mean.has_value()) {
77     proto_stats->set_mean(*stats.mean);
78   }
79   if (stats.stddev.has_value()) {
80     proto_stats->set_stddev(*stats.stddev);
81   }
82   if (stats.min.has_value()) {
83     proto_stats->set_min(*stats.min);
84   }
85   if (stats.max.has_value()) {
86     proto_stats->set_max(*stats.max);
87   }
88 }
89 
WriteMetricsToFile(const std::string & path,const webrtc::test_metrics::MetricsSet & metrics_set)90 bool WriteMetricsToFile(const std::string& path,
91                         const webrtc::test_metrics::MetricsSet& metrics_set) {
92   std::string data;
93   bool ok = metrics_set.SerializeToString(&data);
94   if (!ok) {
95     RTC_LOG(LS_ERROR) << "Failed to serialize histogram set to string";
96     return false;
97   }
98 
99   CreateDir(DirName(path));
100   FILE* output = fopen(path.c_str(), "wb");
101   if (output == NULL) {
102     RTC_LOG(LS_ERROR) << "Failed to write to " << path;
103     return false;
104   }
105   size_t written = fwrite(data.c_str(), sizeof(char), data.size(), output);
106   fclose(output);
107 
108   if (written != data.size()) {
109     size_t expected = data.size();
110     RTC_LOG(LS_ERROR) << "Wrote " << written << ", tried to write " << expected;
111     return false;
112   }
113   return true;
114 }
115 #endif  // WEBRTC_ENABLE_PROTOBUF
116 
117 }  // namespace
118 
Options(absl::string_view export_file_path)119 MetricsSetProtoFileExporter::Options::Options(
120     absl::string_view export_file_path)
121     : export_file_path(export_file_path) {}
Options(absl::string_view export_file_path,bool export_whole_time_series)122 MetricsSetProtoFileExporter::Options::Options(
123     absl::string_view export_file_path,
124     bool export_whole_time_series)
125     : export_file_path(export_file_path),
126       export_whole_time_series(export_whole_time_series) {}
127 
Export(rtc::ArrayView<const Metric> metrics)128 bool MetricsSetProtoFileExporter::Export(rtc::ArrayView<const Metric> metrics) {
129 #if WEBRTC_ENABLE_PROTOBUF
130   webrtc::test_metrics::MetricsSet metrics_set;
131   for (const Metric& metric : metrics) {
132     webrtc::test_metrics::Metric* metric_proto = metrics_set.add_metrics();
133     metric_proto->set_name(metric.name);
134     metric_proto->set_unit(ToProtoUnit(metric.unit));
135     metric_proto->set_improvement_direction(
136         ToProtoImprovementDirection(metric.improvement_direction));
137     metric_proto->set_test_case(metric.test_case);
138     for (const auto& [key, value] : metric.metric_metadata) {
139       metric_proto->mutable_metric_metadata()->insert({key, value});
140     }
141 
142     if (options_.export_whole_time_series) {
143       SetTimeSeries(metric.time_series, metric_proto->mutable_time_series());
144     }
145     SetStats(metric.stats, metric_proto->mutable_stats());
146   }
147 
148   return WriteMetricsToFile(options_.export_file_path, metrics_set);
149 #else
150   RTC_LOG(LS_ERROR)
151       << "Compile with protobuf support to properly use this class";
152   return false;
153 #endif
154 }
155 
156 }  // namespace test
157 }  // namespace webrtc
158