• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/media/webrtc_browsertest_perf.h"
6 
7 #include "base/strings/stringprintf.h"
8 #include "base/values.h"
9 #include "chrome/test/base/in_process_browser_test.h"
10 #include "testing/perf/perf_test.h"
11 
Statistic(const std::string & statistic,const std::string & bucket)12 static std::string Statistic(const std::string& statistic,
13                              const std::string& bucket) {
14   // A ssrc stats key will be on the form stats.<bucket>-<key>.values.
15   // This will give a json "path" which will dig into the time series for the
16   // specified statistic. Buckets can be for instance ssrc_1212344, bweforvideo,
17   // and will each contain a bunch of statistics relevant to their nature.
18   // Each peer connection has a number of such buckets.
19   return base::StringPrintf("stats.%s-%s.values", bucket.c_str(),
20                             statistic.c_str());
21 }
22 
MaybePrintResultsForAudioReceive(const std::string & ssrc,const base::DictionaryValue & pc_dict)23 static bool MaybePrintResultsForAudioReceive(
24     const std::string& ssrc, const base::DictionaryValue& pc_dict) {
25   std::string value;
26   if (!pc_dict.GetString(Statistic("audioOutputLevel", ssrc), &value)) {
27     // Not an audio receive stream.
28     return false;
29   }
30 
31   EXPECT_TRUE(pc_dict.GetString(Statistic("bytesReceived", ssrc), &value));
32   perf_test::PrintResult(
33       "audio_bytes", "", "bytes_recv", value, "bytes", false);
34   EXPECT_TRUE(pc_dict.GetString(Statistic("packetsLost", ssrc), &value));
35   perf_test::PrintResult(
36       "audio_misc", "", "packets_lost", value, "", false);
37 
38   return true;
39 }
40 
MaybePrintResultsForAudioSend(const std::string & ssrc,const base::DictionaryValue & pc_dict)41 static bool MaybePrintResultsForAudioSend(
42     const std::string& ssrc, const base::DictionaryValue& pc_dict) {
43   std::string value;
44   if (!pc_dict.GetString(Statistic("audioInputLevel", ssrc), &value)) {
45     // Not an audio send stream.
46     return false;
47   }
48 
49   EXPECT_TRUE(pc_dict.GetString(Statistic("bytesSent", ssrc), &value));
50   perf_test::PrintResult(
51       "audio_bytes", "", "bytes_sent", value, "bytes", false);
52   EXPECT_TRUE(pc_dict.GetString(Statistic("googJitterReceived", ssrc), &value));
53   perf_test::PrintResult(
54       "audio_tx", "", "goog_jitter_recv", value, "ms", false);
55   EXPECT_TRUE(pc_dict.GetString(Statistic("googRtt", ssrc), &value));
56   perf_test::PrintResult(
57       "audio_tx", "", "goog_rtt", value, "ms", false);
58   return true;
59 }
60 
MaybePrintResultsForVideoSend(const std::string & ssrc,const base::DictionaryValue & pc_dict)61 static bool MaybePrintResultsForVideoSend(
62     const std::string& ssrc, const base::DictionaryValue& pc_dict) {
63   std::string value;
64   if (!pc_dict.GetString(Statistic("googFrameRateSent", ssrc), &value)) {
65     // Not a video send stream.
66     return false;
67   }
68 
69   // Graph these by unit: the dashboard expects all stats in one graph to have
70   // the same unit (e.g. ms, fps, etc). Most graphs, like video_fps, will also
71   // be populated by the counterparts on the video receiving side.
72   perf_test::PrintResult(
73       "video_fps", "", "goog_frame_rate_sent", value, "fps", false);
74   EXPECT_TRUE(pc_dict.GetString(Statistic("googFrameRateInput", ssrc), &value));
75   perf_test::PrintResult(
76       "video_fps", "", "goog_frame_rate_input", value, "fps", false);
77 
78   EXPECT_TRUE(pc_dict.GetString(Statistic("bytesSent", ssrc), &value));
79   perf_test::PrintResult(
80       "video_total_bytes", "", "bytes_sent", value, "bytes", false);
81 
82   EXPECT_TRUE(pc_dict.GetString(Statistic("googFirsReceived", ssrc), &value));
83   perf_test::PrintResult(
84       "video_misc", "", "goog_firs_recv", value, "", false);
85   EXPECT_TRUE(pc_dict.GetString(Statistic("googNacksReceived", ssrc), &value));
86   perf_test::PrintResult(
87       "video_misc", "", "goog_nacks_recv", value, "", false);
88 
89   EXPECT_TRUE(pc_dict.GetString(Statistic("googFrameWidthSent", ssrc), &value));
90   perf_test::PrintResult(
91       "video_resolution", "", "goog_frame_width_sent", value, "pixels", false);
92   EXPECT_TRUE(
93       pc_dict.GetString(Statistic("googFrameHeightSent", ssrc), &value));
94   perf_test::PrintResult(
95       "video_resolution", "", "goog_frame_height_sent", value, "pixels", false);
96 
97   EXPECT_TRUE(pc_dict.GetString(
98       Statistic("googCaptureJitterMs", ssrc), &value));
99   perf_test::PrintResult(
100       "video_tx", "", "goog_capture_jitter_ms", value, "ms", false);
101   EXPECT_TRUE(pc_dict.GetString(
102       Statistic("googCaptureQueueDelayMsPerS", ssrc), &value));
103   perf_test::PrintResult(
104       "video_tx", "", "goog_capture_queue_delay_ms_per_s",
105        value, "ms/s", false);
106   EXPECT_TRUE(pc_dict.GetString(Statistic("googAvgEncodeMs", ssrc), &value));
107   perf_test::PrintResult(
108       "video_tx", "", "goog_avg_encode_ms", value, "ms", false);
109   EXPECT_TRUE(pc_dict.GetString(Statistic("googRtt", ssrc), &value));
110   perf_test::PrintResult("video_tx", "", "goog_rtt", value, "ms", false);
111 
112   EXPECT_TRUE(pc_dict.GetString(
113       Statistic("googEncodeUsagePercent", ssrc), &value));
114   perf_test::PrintResult(
115       "video_cpu_usage", "", "goog_encode_usage_percent", value, "%", false);
116   return true;
117 }
118 
MaybePrintResultsForVideoReceive(const std::string & ssrc,const base::DictionaryValue & pc_dict)119 static bool MaybePrintResultsForVideoReceive(
120     const std::string& ssrc, const base::DictionaryValue& pc_dict) {
121   std::string value;
122   if (!pc_dict.GetString(Statistic("googFrameRateReceived", ssrc), &value)) {
123     // Not a video receive stream.
124     return false;
125   }
126 
127   perf_test::PrintResult(
128       "video_fps", "", "goog_frame_rate_recv", value, "fps", false);
129   EXPECT_TRUE(
130       pc_dict.GetString(Statistic("googFrameRateOutput", ssrc), &value));
131   perf_test::PrintResult(
132       "video_fps", "", "goog_frame_rate_output", value, "fps", false);
133 
134   EXPECT_TRUE(pc_dict.GetString(Statistic("packetsLost", ssrc), &value));
135   perf_test::PrintResult("video_misc", "", "packets_lost", value, "", false);
136 
137   EXPECT_TRUE(pc_dict.GetString(Statistic("bytesReceived", ssrc), &value));
138   perf_test::PrintResult(
139       "video_total_bytes", "", "bytes_recv", value, "bytes", false);
140 
141   EXPECT_TRUE(
142       pc_dict.GetString(Statistic("googFrameWidthReceived", ssrc), &value));
143   perf_test::PrintResult(
144       "video_resolution", "", "goog_frame_width_recv", value, "pixels", false);
145   EXPECT_TRUE(
146       pc_dict.GetString(Statistic("googFrameHeightReceived", ssrc), &value));
147   perf_test::PrintResult(
148       "video_resolution", "", "goog_frame_height_recv", value, "pixels", false);
149 
150   EXPECT_TRUE(pc_dict.GetString(Statistic("googCurrentDelayMs", ssrc), &value));
151   perf_test::PrintResult(
152       "video_rx", "", "goog_current_delay_ms", value, "ms", false);
153   EXPECT_TRUE(pc_dict.GetString(Statistic("googTargetDelayMs", ssrc), &value));
154   perf_test::PrintResult(
155       "video_rx", "", "goog_target_delay_ms", value, "ms", false);
156   EXPECT_TRUE(pc_dict.GetString(Statistic("googDecodeMs", ssrc), &value));
157   perf_test::PrintResult("video_rx", "", "goog_decode_ms", value, "ms", false);
158   EXPECT_TRUE(pc_dict.GetString(Statistic("googMaxDecodeMs", ssrc), &value));
159   perf_test::PrintResult(
160       "video_rx", "", "goog_max_decode_ms", value, "ms", false);
161   EXPECT_TRUE(pc_dict.GetString(Statistic("googJitterBufferMs", ssrc), &value));
162   perf_test::PrintResult(
163       "video_rx", "", "goog_jitter_buffer_ms", value, "ms", false);
164   EXPECT_TRUE(pc_dict.GetString(Statistic("googRenderDelayMs", ssrc), &value));
165   perf_test::PrintResult(
166       "video_rx", "", "goog_render_delay_ms", value, "ms", false);
167 
168   return true;
169 }
170 
ExtractSsrcIdentifier(const std::string & key)171 static std::string ExtractSsrcIdentifier(const std::string& key) {
172   // Example key: ssrc_1234-someStatName. Grab the part before the dash.
173   size_t key_start_pos = 0;
174   size_t key_end_pos = key.find("-");
175   CHECK(key_end_pos != std::string::npos) << "Could not parse key " << key;
176   return key.substr(key_start_pos, key_end_pos - key_start_pos);
177 }
178 
179 // Returns the set of unique ssrc identifiers in the call (e.g. ssrc_1234,
180 // ssrc_12356, etc). |stats_dict| is the .stats dict from one peer connection.
FindAllSsrcIdentifiers(const base::DictionaryValue & stats_dict)181 static std::set<std::string> FindAllSsrcIdentifiers(
182     const base::DictionaryValue& stats_dict) {
183   std::set<std::string> result;
184   base::DictionaryValue::Iterator stats_iterator(stats_dict);
185 
186   while (!stats_iterator.IsAtEnd()) {
187     if (stats_iterator.key().find("ssrc_") != std::string::npos)
188       result.insert(ExtractSsrcIdentifier(stats_iterator.key()));
189     stats_iterator.Advance();
190   }
191   return result;
192 }
193 
194 namespace test {
195 
PrintBweForVideoMetrics(const base::DictionaryValue & pc_dict)196 void PrintBweForVideoMetrics(const base::DictionaryValue& pc_dict) {
197   const std::string kBweStatsKey = "bweforvideo";
198   std::string value;
199   ASSERT_TRUE(pc_dict.GetString(
200       Statistic("googAvailableSendBandwidth", kBweStatsKey), &value));
201   perf_test::PrintResult(
202       "bwe_stats", "", "available_send_bw", value, "bit/s", false);
203   ASSERT_TRUE(pc_dict.GetString(
204       Statistic("googAvailableReceiveBandwidth", kBweStatsKey), &value));
205   perf_test::PrintResult(
206       "bwe_stats", "", "available_recv_bw", value, "bit/s", false);
207   ASSERT_TRUE(pc_dict.GetString(
208       Statistic("googTargetEncBitrate", kBweStatsKey), &value));
209   perf_test::PrintResult(
210       "bwe_stats", "", "target_enc_bitrate", value, "bit/s", false);
211   ASSERT_TRUE(pc_dict.GetString(
212       Statistic("googActualEncBitrate", kBweStatsKey), &value));
213   perf_test::PrintResult(
214       "bwe_stats", "", "actual_enc_bitrate", value, "bit/s", false);
215   ASSERT_TRUE(pc_dict.GetString(
216       Statistic("googTransmitBitrate", kBweStatsKey), &value));
217   perf_test::PrintResult(
218       "bwe_stats", "", "transmit_bitrate", value, "bit/s",false);
219 }
220 
PrintMetricsForAllStreams(const base::DictionaryValue & pc_dict)221 void PrintMetricsForAllStreams(const base::DictionaryValue& pc_dict) {
222   const base::DictionaryValue* stats_dict;
223   ASSERT_TRUE(pc_dict.GetDictionary("stats", &stats_dict));
224   std::set<std::string> ssrc_identifiers = FindAllSsrcIdentifiers(*stats_dict);
225 
226   std::set<std::string>::const_iterator ssrc_iterator =
227       ssrc_identifiers.begin();
228   for (; ssrc_iterator != ssrc_identifiers.end(); ++ssrc_iterator) {
229     // Figure out which stream type this ssrc represents and print all the
230     // interesting metrics for it.
231     const std::string& ssrc = *ssrc_iterator;
232     bool did_recognize_stream_type =
233         MaybePrintResultsForAudioReceive(ssrc, pc_dict) ||
234         MaybePrintResultsForAudioSend(ssrc, pc_dict) ||
235         MaybePrintResultsForVideoReceive(ssrc, pc_dict) ||
236         MaybePrintResultsForVideoSend(ssrc, pc_dict);
237     ASSERT_TRUE(did_recognize_stream_type) << "Failed to figure out which "
238                                               "kind of stream SSRC " << ssrc
239                                            << " is. ";
240   }
241 }
242 
243 }  // namespace test
244