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.
5 #include "chrome/browser/media/webrtc_browsertest_perf.h"
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"
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(),
23 static bool MaybePrintResultsForAudioReceive(
24 const std::string
& ssrc
, const base::DictionaryValue
& pc_dict
,
25 const std::string
& modifier
) {
27 if (!pc_dict
.GetString(Statistic("audioOutputLevel", ssrc
), &value
)) {
28 // Not an audio receive stream.
32 EXPECT_TRUE(pc_dict
.GetString(Statistic("bytesReceived", ssrc
), &value
));
33 perf_test::PrintResult(
34 "audio_bytes", modifier
, "bytes_recv", value
, "bytes", false);
35 EXPECT_TRUE(pc_dict
.GetString(Statistic("packetsLost", ssrc
), &value
));
36 perf_test::PrintResult(
37 "audio_misc", modifier
, "packets_lost", value
, "frames", false);
39 EXPECT_TRUE(pc_dict
.GetString(Statistic("googExpandRate", ssrc
), &value
));
40 perf_test::PrintResult(
41 "audio_rates", modifier
, "goog_expand_rate", value
, "%", false);
43 pc_dict
.GetString(Statistic("googSpeechExpandRate", ssrc
), &value
));
44 perf_test::PrintResult(
45 "audio_rates", modifier
, "goog_speech_expand_rate", value
, "%", false);
47 pc_dict
.GetString(Statistic("googSecondaryDecodedRate", ssrc
), &value
));
48 perf_test::PrintResult(
49 "audio_rates", modifier
, "goog_secondary_decoded_rate", value
, "%",
55 static bool MaybePrintResultsForAudioSend(
56 const std::string
& ssrc
, const base::DictionaryValue
& pc_dict
,
57 const std::string
& modifier
) {
59 if (!pc_dict
.GetString(Statistic("audioInputLevel", ssrc
), &value
)) {
60 // Not an audio send stream.
64 EXPECT_TRUE(pc_dict
.GetString(Statistic("bytesSent", ssrc
), &value
));
65 perf_test::PrintResult(
66 "audio_bytes", modifier
, "bytes_sent", value
, "bytes", false);
67 EXPECT_TRUE(pc_dict
.GetString(Statistic("googJitterReceived", ssrc
), &value
));
68 perf_test::PrintResult(
69 "audio_tx", modifier
, "goog_jitter_recv", value
, "ms", false);
70 EXPECT_TRUE(pc_dict
.GetString(Statistic("googRtt", ssrc
), &value
));
71 perf_test::PrintResult(
72 "audio_tx", modifier
, "goog_rtt", value
, "ms", false);
76 static bool MaybePrintResultsForVideoSend(
77 const std::string
& ssrc
, const base::DictionaryValue
& pc_dict
,
78 const std::string
& modifier
) {
80 if (!pc_dict
.GetString(Statistic("googFrameRateSent", ssrc
), &value
)) {
81 // Not a video send stream.
85 // Graph these by unit: the dashboard expects all stats in one graph to have
86 // the same unit (e.g. ms, fps, etc). Most graphs, like video_fps, will also
87 // be populated by the counterparts on the video receiving side.
88 perf_test::PrintResult(
89 "video_fps", modifier
, "goog_frame_rate_sent", value
, "fps", false);
90 EXPECT_TRUE(pc_dict
.GetString(Statistic("googFrameRateInput", ssrc
), &value
));
91 perf_test::PrintResult(
92 "video_fps", modifier
, "goog_frame_rate_input", value
, "fps", false);
94 EXPECT_TRUE(pc_dict
.GetString(Statistic("bytesSent", ssrc
), &value
));
95 perf_test::PrintResult(
96 "video_total_bytes", modifier
, "bytes_sent", value
, "bytes", false);
98 EXPECT_TRUE(pc_dict
.GetString(Statistic("googFirsReceived", ssrc
), &value
));
99 perf_test::PrintResult(
100 "video_misc", modifier
, "goog_firs_recv", value
, "", false);
101 EXPECT_TRUE(pc_dict
.GetString(Statistic("googNacksReceived", ssrc
), &value
));
102 perf_test::PrintResult(
103 "video_misc", modifier
, "goog_nacks_recv", value
, "", false);
105 EXPECT_TRUE(pc_dict
.GetString(Statistic("googFrameWidthSent", ssrc
), &value
));
106 perf_test::PrintResult("video_resolution", modifier
, "goog_frame_width_sent",
107 value
, "pixels", false);
109 pc_dict
.GetString(Statistic("googFrameHeightSent", ssrc
), &value
));
110 perf_test::PrintResult("video_resolution", modifier
, "goog_frame_height_sent",
111 value
, "pixels", false);
113 EXPECT_TRUE(pc_dict
.GetString(
114 Statistic("googCaptureJitterMs", ssrc
), &value
));
115 perf_test::PrintResult(
116 "video_tx", modifier
, "goog_capture_jitter_ms", value
, "ms", false);
117 EXPECT_TRUE(pc_dict
.GetString(
118 Statistic("googCaptureQueueDelayMsPerS", ssrc
), &value
));
119 perf_test::PrintResult(
120 "video_tx", modifier
, "goog_capture_queue_delay_ms_per_s",
121 value
, "ms/s", false);
122 EXPECT_TRUE(pc_dict
.GetString(Statistic("googAvgEncodeMs", ssrc
), &value
));
123 perf_test::PrintResult(
124 "video_tx", modifier
, "goog_avg_encode_ms", value
, "ms", false);
125 EXPECT_TRUE(pc_dict
.GetString(Statistic("googRtt", ssrc
), &value
));
126 perf_test::PrintResult("video_tx", modifier
, "goog_rtt", value
, "ms", false);
128 EXPECT_TRUE(pc_dict
.GetString(
129 Statistic("googEncodeUsagePercent", ssrc
), &value
));
130 perf_test::PrintResult("video_cpu_usage", modifier
,
131 "goog_encode_usage_percent", value
, "%", false);
135 static bool MaybePrintResultsForVideoReceive(
136 const std::string
& ssrc
, const base::DictionaryValue
& pc_dict
,
137 const std::string
& modifier
) {
139 if (!pc_dict
.GetString(Statistic("googFrameRateReceived", ssrc
), &value
)) {
140 // Not a video receive stream.
144 perf_test::PrintResult(
145 "video_fps", modifier
, "goog_frame_rate_recv", value
, "fps", false);
147 pc_dict
.GetString(Statistic("googFrameRateOutput", ssrc
), &value
));
148 perf_test::PrintResult(
149 "video_fps", modifier
, "goog_frame_rate_output", value
, "fps", false);
151 EXPECT_TRUE(pc_dict
.GetString(Statistic("packetsLost", ssrc
), &value
));
152 perf_test::PrintResult("video_misc", modifier
, "packets_lost", value
,
155 EXPECT_TRUE(pc_dict
.GetString(Statistic("bytesReceived", ssrc
), &value
));
156 perf_test::PrintResult(
157 "video_total_bytes", modifier
, "bytes_recv", value
, "bytes", false);
160 pc_dict
.GetString(Statistic("googFrameWidthReceived", ssrc
), &value
));
161 perf_test::PrintResult("video_resolution", modifier
, "goog_frame_width_recv",
162 value
, "pixels", false);
164 pc_dict
.GetString(Statistic("googFrameHeightReceived", ssrc
), &value
));
165 perf_test::PrintResult("video_resolution", modifier
, "goog_frame_height_recv",
166 value
, "pixels", false);
168 EXPECT_TRUE(pc_dict
.GetString(Statistic("googCurrentDelayMs", ssrc
), &value
));
169 perf_test::PrintResult(
170 "video_rx", modifier
, "goog_current_delay_ms", value
, "ms", false);
171 EXPECT_TRUE(pc_dict
.GetString(Statistic("googTargetDelayMs", ssrc
), &value
));
172 perf_test::PrintResult(
173 "video_rx", modifier
, "goog_target_delay_ms", value
, "ms", false);
174 EXPECT_TRUE(pc_dict
.GetString(Statistic("googDecodeMs", ssrc
), &value
));
175 perf_test::PrintResult("video_rx", modifier
, "goog_decode_ms", value
, "ms",
177 EXPECT_TRUE(pc_dict
.GetString(Statistic("googMaxDecodeMs", ssrc
), &value
));
178 perf_test::PrintResult(
179 "video_rx", modifier
, "goog_max_decode_ms", value
, "ms", false);
180 EXPECT_TRUE(pc_dict
.GetString(Statistic("googJitterBufferMs", ssrc
), &value
));
181 perf_test::PrintResult(
182 "video_rx", modifier
, "goog_jitter_buffer_ms", value
, "ms", false);
183 EXPECT_TRUE(pc_dict
.GetString(Statistic("googRenderDelayMs", ssrc
), &value
));
184 perf_test::PrintResult(
185 "video_rx", modifier
, "goog_render_delay_ms", value
, "ms", false);
190 static std::string
ExtractSsrcIdentifier(const std::string
& key
) {
191 // Example key: ssrc_1234-someStatName. Grab the part before the dash.
192 size_t key_start_pos
= 0;
193 size_t key_end_pos
= key
.find("-");
194 CHECK(key_end_pos
!= std::string::npos
) << "Could not parse key " << key
;
195 return key
.substr(key_start_pos
, key_end_pos
- key_start_pos
);
198 // Returns the set of unique ssrc identifiers in the call (e.g. ssrc_1234,
199 // ssrc_12356, etc). |stats_dict| is the .stats dict from one peer connection.
200 static std::set
<std::string
> FindAllSsrcIdentifiers(
201 const base::DictionaryValue
& stats_dict
) {
202 std::set
<std::string
> result
;
203 base::DictionaryValue::Iterator
stats_iterator(stats_dict
);
205 while (!stats_iterator
.IsAtEnd()) {
206 if (stats_iterator
.key().find("ssrc_") != std::string::npos
)
207 result
.insert(ExtractSsrcIdentifier(stats_iterator
.key()));
208 stats_iterator
.Advance();
215 void PrintBweForVideoMetrics(const base::DictionaryValue
& pc_dict
,
216 const std::string
& modifier
) {
217 const std::string kBweStatsKey
= "bweforvideo";
219 ASSERT_TRUE(pc_dict
.GetString(
220 Statistic("googAvailableSendBandwidth", kBweStatsKey
), &value
));
221 perf_test::PrintResult(
222 "bwe_stats", modifier
, "available_send_bw", value
, "bit/s", false);
223 ASSERT_TRUE(pc_dict
.GetString(
224 Statistic("googAvailableReceiveBandwidth", kBweStatsKey
), &value
));
225 perf_test::PrintResult(
226 "bwe_stats", modifier
, "available_recv_bw", value
, "bit/s", false);
227 ASSERT_TRUE(pc_dict
.GetString(
228 Statistic("googTargetEncBitrate", kBweStatsKey
), &value
));
229 perf_test::PrintResult(
230 "bwe_stats", modifier
, "target_enc_bitrate", value
, "bit/s", false);
231 ASSERT_TRUE(pc_dict
.GetString(
232 Statistic("googActualEncBitrate", kBweStatsKey
), &value
));
233 perf_test::PrintResult(
234 "bwe_stats", modifier
, "actual_enc_bitrate", value
, "bit/s", false);
235 ASSERT_TRUE(pc_dict
.GetString(
236 Statistic("googTransmitBitrate", kBweStatsKey
), &value
));
237 perf_test::PrintResult(
238 "bwe_stats", modifier
, "transmit_bitrate", value
, "bit/s",false);
241 void PrintMetricsForAllStreams(const base::DictionaryValue
& pc_dict
,
242 const std::string
& modifier
) {
243 const base::DictionaryValue
* stats_dict
;
244 ASSERT_TRUE(pc_dict
.GetDictionary("stats", &stats_dict
));
245 std::set
<std::string
> ssrc_identifiers
= FindAllSsrcIdentifiers(*stats_dict
);
247 std::set
<std::string
>::const_iterator ssrc_iterator
=
248 ssrc_identifiers
.begin();
249 for (; ssrc_iterator
!= ssrc_identifiers
.end(); ++ssrc_iterator
) {
250 // Figure out which stream type this ssrc represents and print all the
251 // interesting metrics for it.
252 const std::string
& ssrc
= *ssrc_iterator
;
253 bool did_recognize_stream_type
=
254 MaybePrintResultsForAudioReceive(ssrc
, pc_dict
, modifier
) ||
255 MaybePrintResultsForAudioSend(ssrc
, pc_dict
, modifier
) ||
256 MaybePrintResultsForVideoReceive(ssrc
, pc_dict
, modifier
) ||
257 MaybePrintResultsForVideoSend(ssrc
, pc_dict
, modifier
);
258 ASSERT_TRUE(did_recognize_stream_type
) << "Failed to figure out which "
259 "kind of stream SSRC " << ssrc