1 /*
2 * Copyright (c) 2020 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
11 #include "test/testsupport/perf_result_reporter.h"
12
13 #include <vector>
14
15 namespace {
16
17 // These characters mess with either the stdout parsing or the dashboard itself.
InvalidCharacters()18 const std::vector<std::string>& InvalidCharacters() {
19 static const std::vector<std::string> kInvalidCharacters({"/", ":", "="});
20
21 return kInvalidCharacters;
22 }
23
CheckForInvalidCharacters(const std::string & str)24 void CheckForInvalidCharacters(const std::string& str) {
25 for (const auto& invalid : InvalidCharacters()) {
26 RTC_CHECK(str.find(invalid) == std::string::npos)
27 << "Given invalid character for perf names '" << invalid << "'";
28 }
29 }
30
31 } // namespace
32
33 namespace webrtc {
34 namespace test {
35
36 namespace {
37
38 // For now, mark all tests as "not important". This distinction mostly goes away
39 // in histograms anyway.
40 const bool kNotImportant = false;
41
UnitToString(Unit unit)42 std::string UnitToString(Unit unit) {
43 // Down the line, we should convert directly from Unit to the histogram.proto
44 // enum values. We need to convert to strings until all uses of perf_test.h
45 // have been eliminated. We're not using the proto enum directly in the .h of
46 // this file because we don't want to limit the exposure of the proto.
47 //
48 // Keep this list up to date with kJsonToProtoUnit in histogram.cc in the
49 // Catapult repo.
50 switch (unit) {
51 case Unit::kMs:
52 return "ms";
53 case Unit::kMsBestFitFormat:
54 return "msBestFitFormat";
55 case Unit::kMsTs:
56 return "tsMs";
57 case Unit::kNPercent:
58 return "n%";
59 case Unit::kSizeInBytes:
60 return "sizeInBytes";
61 case Unit::kBytesPerSecond:
62 return "bytesPerSecond";
63 case Unit::kHertz:
64 return "Hz";
65 case Unit::kUnitless:
66 return "unitless";
67 case Unit::kCount:
68 return "count";
69 case Unit::kSigma:
70 return "sigma";
71 default:
72 RTC_NOTREACHED() << "Unknown unit " << unit;
73 return "unitless";
74 }
75 }
76
77 } // namespace
78
PerfResultReporter(const std::string & metric_basename,const std::string & story_name)79 PerfResultReporter::PerfResultReporter(const std::string& metric_basename,
80 const std::string& story_name)
81 : metric_basename_(metric_basename), story_name_(story_name) {
82 CheckForInvalidCharacters(metric_basename_);
83 CheckForInvalidCharacters(story_name_);
84 }
85
86 PerfResultReporter::~PerfResultReporter() = default;
87
RegisterMetric(const std::string & metric_suffix,Unit unit)88 void PerfResultReporter::RegisterMetric(const std::string& metric_suffix,
89 Unit unit) {
90 RegisterMetric(metric_suffix, unit, ImproveDirection::kNone);
91 }
RegisterMetric(const std::string & metric_suffix,Unit unit,ImproveDirection improve_direction)92 void PerfResultReporter::RegisterMetric(const std::string& metric_suffix,
93 Unit unit,
94 ImproveDirection improve_direction) {
95 CheckForInvalidCharacters(metric_suffix);
96 RTC_CHECK(metric_map_.count(metric_suffix) == 0);
97 metric_map_.insert({metric_suffix, {unit, improve_direction}});
98 }
99
AddResult(const std::string & metric_suffix,size_t value) const100 void PerfResultReporter::AddResult(const std::string& metric_suffix,
101 size_t value) const {
102 auto info = GetMetricInfoOrFail(metric_suffix);
103
104 PrintResult(metric_basename_, metric_suffix, story_name_, value,
105 UnitToString(info.unit), kNotImportant, info.improve_direction);
106 }
107
AddResult(const std::string & metric_suffix,double value) const108 void PerfResultReporter::AddResult(const std::string& metric_suffix,
109 double value) const {
110 auto info = GetMetricInfoOrFail(metric_suffix);
111
112 PrintResult(metric_basename_, metric_suffix, story_name_, value,
113 UnitToString(info.unit), kNotImportant, info.improve_direction);
114 }
115
AddResultList(const std::string & metric_suffix,rtc::ArrayView<const double> values) const116 void PerfResultReporter::AddResultList(
117 const std::string& metric_suffix,
118 rtc::ArrayView<const double> values) const {
119 auto info = GetMetricInfoOrFail(metric_suffix);
120
121 PrintResultList(metric_basename_, metric_suffix, story_name_, values,
122 UnitToString(info.unit), kNotImportant,
123 info.improve_direction);
124 }
125
AddResultMeanAndError(const std::string & metric_suffix,const double mean,const double error)126 void PerfResultReporter::AddResultMeanAndError(const std::string& metric_suffix,
127 const double mean,
128 const double error) {
129 auto info = GetMetricInfoOrFail(metric_suffix);
130
131 PrintResultMeanAndError(metric_basename_, metric_suffix, story_name_, mean,
132 error, UnitToString(info.unit), kNotImportant,
133 info.improve_direction);
134 }
135
GetMetricInfo(const std::string & metric_suffix) const136 absl::optional<MetricInfo> PerfResultReporter::GetMetricInfo(
137 const std::string& metric_suffix) const {
138 auto iter = metric_map_.find(metric_suffix);
139 if (iter == metric_map_.end()) {
140 return absl::optional<MetricInfo>();
141 }
142
143 return absl::optional<MetricInfo>(iter->second);
144 }
145
GetMetricInfoOrFail(const std::string & metric_suffix) const146 MetricInfo PerfResultReporter::GetMetricInfoOrFail(
147 const std::string& metric_suffix) const {
148 absl::optional<MetricInfo> info = GetMetricInfo(metric_suffix);
149 RTC_CHECK(info.has_value())
150 << "Attempted to use unregistered metric " << metric_suffix;
151 return *info;
152 }
153
154 } // namespace test
155 } // namespace webrtc
156