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