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 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 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 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 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 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 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. 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 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 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