• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_test_histogram_writer.h"
12 
13 #include <stdlib.h>
14 
15 #include <map>
16 #include <memory>
17 
18 #include "rtc_base/logging.h"
19 #include "rtc_base/synchronization/mutex.h"
20 #include "third_party/catapult/tracing/tracing/value/diagnostics/reserved_infos.h"
21 #include "third_party/catapult/tracing/tracing/value/histogram.h"
22 
23 namespace webrtc {
24 namespace test {
25 
26 namespace {
27 
28 namespace proto = catapult::tracing::tracing::proto;
29 
AsJsonString(const std::string string)30 std::string AsJsonString(const std::string string) {
31   return "\"" + string + "\"";
32 }
33 
34 class PerfTestHistogramWriter : public PerfTestResultWriter {
35  public:
PerfTestHistogramWriter()36   PerfTestHistogramWriter() : mutex_() {}
ClearResults()37   void ClearResults() override {
38     MutexLock lock(&mutex_);
39     histograms_.clear();
40   }
41 
LogResult(const std::string & graph_name,const std::string & trace_name,const double value,const std::string & units,const bool important,ImproveDirection improve_direction)42   void LogResult(const std::string& graph_name,
43                  const std::string& trace_name,
44                  const double value,
45                  const std::string& units,
46                  const bool important,
47                  ImproveDirection improve_direction) override {
48     (void)important;
49     AddSample(graph_name, trace_name, value, units, improve_direction);
50   }
LogResultMeanAndError(const std::string & graph_name,const std::string & trace_name,const double mean,const double error,const std::string & units,const bool important,ImproveDirection improve_direction)51   void LogResultMeanAndError(const std::string& graph_name,
52                              const std::string& trace_name,
53                              const double mean,
54                              const double error,
55                              const std::string& units,
56                              const bool important,
57                              ImproveDirection improve_direction) override {
58     RTC_LOG(LS_WARNING) << "Discarding stddev, not supported by histograms";
59     (void)error;
60     (void)important;
61 
62     AddSample(graph_name, trace_name, mean, units, improve_direction);
63   }
LogResultList(const std::string & graph_name,const std::string & trace_name,const rtc::ArrayView<const double> values,const std::string & units,const bool important,ImproveDirection improve_direction)64   void LogResultList(const std::string& graph_name,
65                      const std::string& trace_name,
66                      const rtc::ArrayView<const double> values,
67                      const std::string& units,
68                      const bool important,
69                      ImproveDirection improve_direction) override {
70     (void)important;
71     for (double value : values) {
72       AddSample(graph_name, trace_name, value, units, improve_direction);
73     }
74   }
Serialize() const75   std::string Serialize() const override {
76     proto::HistogramSet histogram_set;
77 
78     MutexLock lock(&mutex_);
79     for (const auto& histogram : histograms_) {
80       std::unique_ptr<proto::Histogram> proto = histogram.second->toProto();
81       histogram_set.mutable_histograms()->AddAllocated(proto.release());
82     }
83 
84     std::string output;
85     bool ok = histogram_set.SerializeToString(&output);
86     RTC_DCHECK(ok) << "Failed to serialize histogram set to string";
87     return output;
88   }
89 
90  private:
AddSample(const std::string & original_graph_name,const std::string & trace_name,const double value,const std::string & units,ImproveDirection improve_direction)91   void AddSample(const std::string& original_graph_name,
92                  const std::string& trace_name,
93                  const double value,
94                  const std::string& units,
95                  ImproveDirection improve_direction) {
96     // WebRTC annotates the units into the metric name when they are not
97     // supported by the Histogram API.
98     std::string graph_name = original_graph_name;
99     if (units == "dB") {
100       graph_name += "_dB";
101     } else if (units == "fps") {
102       graph_name += "_fps";
103     } else if (units == "%") {
104       graph_name += "_%";
105     }
106 
107     // Lookup on graph name + trace name (or measurement + story in catapult
108     // parlance). There should be several histograms with the same measurement
109     // if they're for different stories.
110     std::string measurement_and_story = graph_name + trace_name;
111     MutexLock lock(&mutex_);
112     if (histograms_.count(measurement_and_story) == 0) {
113       proto::UnitAndDirection unit = ParseUnit(units, improve_direction);
114       std::unique_ptr<catapult::HistogramBuilder> builder =
115           std::make_unique<catapult::HistogramBuilder>(graph_name, unit);
116 
117       // Set all summary options as false - we don't want to generate
118       // metric_std, metric_count, and so on for all metrics.
119       builder->SetSummaryOptions(proto::SummaryOptions());
120       histograms_[measurement_and_story] = std::move(builder);
121 
122       proto::Diagnostic stories;
123       proto::GenericSet* generic_set = stories.mutable_generic_set();
124       generic_set->add_values(AsJsonString(trace_name));
125       histograms_[measurement_and_story]->AddDiagnostic(
126           catapult::kStoriesDiagnostic, stories);
127     }
128 
129     if (units == "bps") {
130       // Bps has been interpreted as bits per second in WebRTC tests.
131       histograms_[measurement_and_story]->AddSample(value / 8);
132     } else {
133       histograms_[measurement_and_story]->AddSample(value);
134     }
135   }
136 
ParseUnit(const std::string & units,ImproveDirection improve_direction)137   proto::UnitAndDirection ParseUnit(const std::string& units,
138                                     ImproveDirection improve_direction) {
139     RTC_DCHECK(units.find('_') == std::string::npos)
140         << "The unit_bigger|smallerIsBetter syntax isn't supported in WebRTC, "
141            "use the enum instead.";
142 
143     proto::UnitAndDirection result;
144     result.set_improvement_direction(ParseDirection(improve_direction));
145     if (units == "bps") {
146       result.set_unit(proto::BYTES_PER_SECOND);
147     } else if (units == "dB") {
148       result.set_unit(proto::UNITLESS);
149     } else if (units == "fps") {
150       result.set_unit(proto::HERTZ);
151     } else if (units == "frames") {
152       result.set_unit(proto::COUNT);
153     } else if (units == "ms") {
154       result.set_unit(proto::MS_BEST_FIT_FORMAT);
155     } else if (units == "%") {
156       result.set_unit(proto::UNITLESS);
157     } else {
158       proto::Unit unit = catapult::UnitFromJsonUnit(units);
159 
160       // UnitFromJsonUnit returns UNITLESS if it doesn't recognize the unit.
161       if (unit == proto::UNITLESS && units != "unitless") {
162         RTC_LOG(LS_WARNING) << "Unit " << units << " is unsupported.";
163       }
164 
165       result.set_unit(unit);
166     }
167     return result;
168   }
169 
ParseDirection(ImproveDirection improve_direction)170   proto::ImprovementDirection ParseDirection(
171       ImproveDirection improve_direction) {
172     switch (improve_direction) {
173       case ImproveDirection::kNone:
174         return proto::NOT_SPECIFIED;
175       case ImproveDirection::kSmallerIsBetter:
176         return proto::SMALLER_IS_BETTER;
177       case ImproveDirection::kBiggerIsBetter:
178         return proto::BIGGER_IS_BETTER;
179       default:
180         RTC_NOTREACHED() << "Invalid enum value " << improve_direction;
181     }
182   }
183 
184  private:
185   mutable Mutex mutex_;
186   std::map<std::string, std::unique_ptr<catapult::HistogramBuilder>> histograms_
187       RTC_GUARDED_BY(&mutex_);
188 };
189 
190 }  // namespace
191 
CreateHistogramWriter()192 PerfTestResultWriter* CreateHistogramWriter() {
193   return new PerfTestHistogramWriter();
194 }
195 
196 }  // namespace test
197 }  // namespace webrtc
198