xref: /aosp_15_r20/external/webrtc/api/test/metrics/stdout_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/stdout_metrics_exporter.h"
11 
12 #include <stdio.h>
13 
14 #include <cmath>
15 #include <string>
16 
17 #include "absl/types/optional.h"
18 #include "api/array_view.h"
19 #include "api/test/metrics/metric.h"
20 #include "rtc_base/strings/string_builder.h"
21 
22 namespace webrtc {
23 namespace test {
24 namespace {
25 
26 // Returns positive integral part of the number.
IntegralPart(double value)27 int64_t IntegralPart(double value) {
28   return std::lround(std::floor(std::abs(value)));
29 }
30 
AppendWithPrecision(double value,int digits_after_comma,rtc::StringBuilder & out)31 void AppendWithPrecision(double value,
32                          int digits_after_comma,
33                          rtc::StringBuilder& out) {
34   int64_t multiplier = std::lround(std::pow(10, digits_after_comma));
35   int64_t integral_part = IntegralPart(value);
36   double decimal_part = std::abs(value) - integral_part;
37 
38   // If decimal part has leading zeros then when it will be multiplied on
39   // `multiplier`, leading zeros will be lost. To preserve them we add "1"
40   // so then leading digit will be greater than 0 and won't be removed.
41   //
42   // During conversion to the string leading digit has to be stripped.
43   //
44   // Also due to rounding it may happen that leading digit may be incremented,
45   // like with `digits_after_comma` 3 number 1.9995 will be rounded to 2. In
46   // such case this increment has to be propagated to the `integral_part`.
47   int64_t decimal_holder = std::lround((1 + decimal_part) * multiplier);
48   if (decimal_holder >= 2 * multiplier) {
49     // Rounding incremented added leading digit, so we need to transfer 1 to
50     // integral part.
51     integral_part++;
52     decimal_holder -= multiplier;
53   }
54   // Remove trailing zeros.
55   while (decimal_holder % 10 == 0) {
56     decimal_holder /= 10;
57   }
58 
59   // Print serialized number to output.
60   if (value < 0) {
61     out << "-";
62   }
63   out << integral_part;
64   if (decimal_holder != 1) {
65     out << "." << std::to_string(decimal_holder).substr(1, digits_after_comma);
66   }
67 }
68 
69 }  // namespace
70 
StdoutMetricsExporter()71 StdoutMetricsExporter::StdoutMetricsExporter() : output_(stdout) {}
72 
Export(rtc::ArrayView<const Metric> metrics)73 bool StdoutMetricsExporter::Export(rtc::ArrayView<const Metric> metrics) {
74   for (const Metric& metric : metrics) {
75     PrintMetric(metric);
76   }
77   return true;
78 }
79 
PrintMetric(const Metric & metric)80 void StdoutMetricsExporter::PrintMetric(const Metric& metric) {
81   rtc::StringBuilder value_stream;
82   value_stream << metric.test_case << " / " << metric.name << "= {mean=";
83   if (metric.stats.mean.has_value()) {
84     AppendWithPrecision(*metric.stats.mean, 8, value_stream);
85   } else {
86     value_stream << "-";
87   }
88   value_stream << ", stddev=";
89   if (metric.stats.stddev.has_value()) {
90     AppendWithPrecision(*metric.stats.stddev, 8, value_stream);
91   } else {
92     value_stream << "-";
93   }
94   value_stream << "} " << ToString(metric.unit) << " ("
95                << ToString(metric.improvement_direction) << ")";
96 
97   fprintf(output_, "RESULT: %s\n", value_stream.str().c_str());
98 }
99 
100 }  // namespace test
101 }  // namespace webrtc
102