xref: /aosp_15_r20/external/webrtc/api/test/metrics/metrics_accumulator.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_accumulator.h"
11 
12 #include <map>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "absl/strings/string_view.h"
18 #include "api/numerics/samples_stats_counter.h"
19 #include "api/test/metrics/metric.h"
20 #include "api/units/timestamp.h"
21 #include "rtc_base/synchronization/mutex.h"
22 
23 namespace webrtc {
24 namespace test {
25 namespace {
26 
ToStats(const SamplesStatsCounter & values)27 Metric::Stats ToStats(const SamplesStatsCounter& values) {
28   if (values.IsEmpty()) {
29     return Metric::Stats();
30   }
31   return Metric::Stats{.mean = values.GetAverage(),
32                        .stddev = values.GetStandardDeviation(),
33                        .min = values.GetMin(),
34                        .max = values.GetMax()};
35 }
36 
SetTimeseries(const Metric & prototype,const SamplesStatsCounter & counter)37 Metric SetTimeseries(const Metric& prototype,
38                      const SamplesStatsCounter& counter) {
39   Metric output(prototype);
40   Metric::TimeSeries time_series;
41   for (const SamplesStatsCounter::StatsSample& sample :
42        counter.GetTimedSamples()) {
43     time_series.samples.push_back(
44         Metric::TimeSeries::Sample{.timestamp = sample.time,
45                                    .value = sample.value,
46                                    .sample_metadata = sample.metadata});
47   }
48   output.time_series = std::move(time_series);
49   output.stats = ToStats(counter);
50   return output;
51 }
52 
53 }  // namespace
54 
operator <(const MetricsAccumulator::MetricKey & a,const MetricsAccumulator::MetricKey & b)55 bool operator<(const MetricsAccumulator::MetricKey& a,
56                const MetricsAccumulator::MetricKey& b) {
57   if (a.test_case_name < b.test_case_name) {
58     return true;
59   } else if (a.test_case_name > b.test_case_name) {
60     return false;
61   } else {
62     return a.metric_name < b.metric_name;
63   }
64 }
65 
AddSample(absl::string_view metric_name,absl::string_view test_case_name,double value,Timestamp timestamp,std::map<std::string,std::string> point_metadata)66 bool MetricsAccumulator::AddSample(
67     absl::string_view metric_name,
68     absl::string_view test_case_name,
69     double value,
70     Timestamp timestamp,
71     std::map<std::string, std::string> point_metadata) {
72   MutexLock lock(&mutex_);
73   bool created;
74   MetricValue* metric_value =
75       GetOrCreateMetric(metric_name, test_case_name, &created);
76   metric_value->counter.AddSample(
77       SamplesStatsCounter::StatsSample{.value = value,
78                                        .time = timestamp,
79                                        .metadata = std::move(point_metadata)});
80   return created;
81 }
82 
AddMetricMetadata(absl::string_view metric_name,absl::string_view test_case_name,Unit unit,ImprovementDirection improvement_direction,std::map<std::string,std::string> metric_metadata)83 bool MetricsAccumulator::AddMetricMetadata(
84     absl::string_view metric_name,
85     absl::string_view test_case_name,
86     Unit unit,
87     ImprovementDirection improvement_direction,
88     std::map<std::string, std::string> metric_metadata) {
89   MutexLock lock(&mutex_);
90   bool created;
91   MetricValue* metric_value =
92       GetOrCreateMetric(metric_name, test_case_name, &created);
93   metric_value->metric.unit = unit;
94   metric_value->metric.improvement_direction = improvement_direction;
95   metric_value->metric.metric_metadata = std::move(metric_metadata);
96   return created;
97 }
98 
GetCollectedMetrics() const99 std::vector<Metric> MetricsAccumulator::GetCollectedMetrics() const {
100   MutexLock lock(&mutex_);
101   std::vector<Metric> out;
102   out.reserve(metrics_.size());
103   for (const auto& [unused_key, metric_value] : metrics_) {
104     out.push_back(SetTimeseries(metric_value.metric, metric_value.counter));
105   }
106   return out;
107 }
108 
GetOrCreateMetric(absl::string_view metric_name,absl::string_view test_case_name,bool * created)109 MetricsAccumulator::MetricValue* MetricsAccumulator::GetOrCreateMetric(
110     absl::string_view metric_name,
111     absl::string_view test_case_name,
112     bool* created) {
113   MetricKey key(metric_name, test_case_name);
114   auto it = metrics_.find(key);
115   if (it != metrics_.end()) {
116     *created = false;
117     return &it->second;
118   }
119   *created = true;
120 
121   Metric metric{
122       .name = key.metric_name,
123       .unit = Unit::kUnitless,
124       .improvement_direction = ImprovementDirection::kNeitherIsBetter,
125       .test_case = key.test_case_name,
126   };
127   return &metrics_.emplace(key, MetricValue{.metric = std::move(metric)})
128               .first->second;
129 }
130 
131 }  // namespace test
132 }  // namespace webrtc
133