|  | /* | 
|  | *  Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  | #include "api/test/metrics/metrics_set_proto_file_exporter.h" | 
|  |  | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include <map> | 
|  | #include <string> | 
|  | #include <utility> | 
|  |  | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "api/array_view.h" | 
|  | #include "api/test/metrics/metric.h" | 
|  | #include "rtc_base/logging.h" | 
|  | #include "test/testsupport/file_utils.h" | 
|  |  | 
|  | #if WEBRTC_ENABLE_PROTOBUF | 
|  | #include "api/test/metrics/proto/metric.pb.h" | 
|  | #endif | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace test { | 
|  | namespace { | 
|  |  | 
|  | #if WEBRTC_ENABLE_PROTOBUF | 
|  | webrtc::test_metrics::Unit ToProtoUnit(Unit unit) { | 
|  | switch (unit) { | 
|  | case Unit::kMilliseconds: | 
|  | return webrtc::test_metrics::Unit::MILLISECONDS; | 
|  | case Unit::kPercent: | 
|  | return webrtc::test_metrics::Unit::PERCENT; | 
|  | case Unit::kBytes: | 
|  | return webrtc::test_metrics::Unit::BYTES; | 
|  | case Unit::kKilobitsPerSecond: | 
|  | return webrtc::test_metrics::Unit::KILOBITS_PER_SECOND; | 
|  | case Unit::kHertz: | 
|  | return webrtc::test_metrics::Unit::HERTZ; | 
|  | case Unit::kUnitless: | 
|  | return webrtc::test_metrics::Unit::UNITLESS; | 
|  | case Unit::kCount: | 
|  | return webrtc::test_metrics::Unit::COUNT; | 
|  | } | 
|  | } | 
|  |  | 
|  | webrtc::test_metrics::ImprovementDirection ToProtoImprovementDirection( | 
|  | ImprovementDirection direction) { | 
|  | switch (direction) { | 
|  | case ImprovementDirection::kBiggerIsBetter: | 
|  | return webrtc::test_metrics::ImprovementDirection::BIGGER_IS_BETTER; | 
|  | case ImprovementDirection::kNeitherIsBetter: | 
|  | return webrtc::test_metrics::ImprovementDirection::NEITHER_IS_BETTER; | 
|  | case ImprovementDirection::kSmallerIsBetter: | 
|  | return webrtc::test_metrics::ImprovementDirection::SMALLER_IS_BETTER; | 
|  | } | 
|  | } | 
|  |  | 
|  | void SetTimeSeries( | 
|  | const Metric::TimeSeries& time_series, | 
|  | webrtc::test_metrics::Metric::TimeSeries* proto_time_series) { | 
|  | for (const Metric::TimeSeries::Sample& sample : time_series.samples) { | 
|  | webrtc::test_metrics::Metric::TimeSeries::Sample* proto_sample = | 
|  | proto_time_series->add_samples(); | 
|  | proto_sample->set_value(sample.value); | 
|  | proto_sample->set_timestamp_us(sample.timestamp.us()); | 
|  | for (const auto& [key, value] : sample.sample_metadata) { | 
|  | proto_sample->mutable_sample_metadata()->insert({key, value}); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void SetStats(const Metric::Stats& stats, | 
|  | webrtc::test_metrics::Metric::Stats* proto_stats) { | 
|  | if (stats.mean.has_value()) { | 
|  | proto_stats->set_mean(*stats.mean); | 
|  | } | 
|  | if (stats.stddev.has_value()) { | 
|  | proto_stats->set_stddev(*stats.stddev); | 
|  | } | 
|  | if (stats.min.has_value()) { | 
|  | proto_stats->set_min(*stats.min); | 
|  | } | 
|  | if (stats.max.has_value()) { | 
|  | proto_stats->set_max(*stats.max); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool WriteMetricsToFile(const std::string& path, | 
|  | const webrtc::test_metrics::MetricsSet& metrics_set) { | 
|  | std::string data; | 
|  | bool ok = metrics_set.SerializeToString(&data); | 
|  | if (!ok) { | 
|  | RTC_LOG(LS_ERROR) << "Failed to serialize histogram set to string"; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | CreateDir(DirName(path)); | 
|  | FILE* output = fopen(path.c_str(), "wb"); | 
|  | if (output == NULL) { | 
|  | RTC_LOG(LS_ERROR) << "Failed to write to " << path; | 
|  | return false; | 
|  | } | 
|  | size_t written = fwrite(data.c_str(), sizeof(char), data.size(), output); | 
|  | fclose(output); | 
|  |  | 
|  | if (written != data.size()) { | 
|  | size_t expected = data.size(); | 
|  | RTC_LOG(LS_ERROR) << "Wrote " << written << ", tried to write " << expected; | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  | #endif  // WEBRTC_ENABLE_PROTOBUF | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | MetricsSetProtoFileExporter::Options::Options( | 
|  | absl::string_view export_file_path) | 
|  | : export_file_path(export_file_path) {} | 
|  | MetricsSetProtoFileExporter::Options::Options( | 
|  | absl::string_view export_file_path, | 
|  | bool export_whole_time_series) | 
|  | : export_file_path(export_file_path), | 
|  | export_whole_time_series(export_whole_time_series) {} | 
|  | MetricsSetProtoFileExporter::Options::Options( | 
|  | absl::string_view export_file_path, | 
|  | std::map<std::string, std::string> metadata) | 
|  | : export_file_path(export_file_path), metadata(std::move(metadata)) {} | 
|  |  | 
|  | bool MetricsSetProtoFileExporter::Export(rtc::ArrayView<const Metric> metrics) { | 
|  | #if WEBRTC_ENABLE_PROTOBUF | 
|  | webrtc::test_metrics::MetricsSet metrics_set; | 
|  | for (const auto& [key, value] : options_.metadata) { | 
|  | metrics_set.mutable_metadata()->insert({key, value}); | 
|  | } | 
|  | for (const Metric& metric : metrics) { | 
|  | webrtc::test_metrics::Metric* metric_proto = metrics_set.add_metrics(); | 
|  | metric_proto->set_name(metric.name); | 
|  | metric_proto->set_unit(ToProtoUnit(metric.unit)); | 
|  | metric_proto->set_improvement_direction( | 
|  | ToProtoImprovementDirection(metric.improvement_direction)); | 
|  | metric_proto->set_test_case(metric.test_case); | 
|  | for (const auto& [key, value] : metric.metric_metadata) { | 
|  | metric_proto->mutable_metric_metadata()->insert({key, value}); | 
|  | } | 
|  |  | 
|  | if (options_.export_whole_time_series) { | 
|  | SetTimeSeries(metric.time_series, metric_proto->mutable_time_series()); | 
|  | } | 
|  | SetStats(metric.stats, metric_proto->mutable_stats()); | 
|  | } | 
|  |  | 
|  | return WriteMetricsToFile(options_.export_file_path, metrics_set); | 
|  | #else | 
|  | RTC_LOG(LS_ERROR) | 
|  | << "Compile with protobuf support to properly use this class"; | 
|  | return false; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | }  // namespace test | 
|  | }  // namespace webrtc |