Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(268)

Side by Side Diff: webrtc/tools/event_log_visualizer/analyzer.cc

Issue 1995523002: Visualization tool for WebrtcEventLogs (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Use include_tests==1 to avoid compiling if gflags isn't available. Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2016 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 "webrtc/tools/event_log_visualizer/analyzer.h"
12
13 #include <algorithm>
14 #include <limits>
15 #include <map>
16 #include <sstream>
17 #include <string>
18 #include <utility>
19
20 #include "webrtc/audio_receive_stream.h"
21 #include "webrtc/audio_send_stream.h"
22 #include "webrtc/base/checks.h"
23 #include "webrtc/call.h"
24 #include "webrtc/common_types.h"
25 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
26 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
27 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
28 #include "webrtc/video_receive_stream.h"
29 #include "webrtc/video_send_stream.h"
30
31 namespace {
32
33 std::string SsrcToString(uint32_t ssrc) {
34 std::stringstream ss;
35 ss << "SSRC " << ssrc;
36 return ss.str();
37 }
38
39 // Checks whether an SSRC is contained in the list of desired SSRCs.
40 // Note that an empty SSRC list matches every SSRC.
41 bool MatchingSsrc(uint32_t ssrc, const std::vector<uint32_t>& desired_ssrc) {
42 if (desired_ssrc.size() == 0)
43 return true;
44 return std::find(desired_ssrc.begin(), desired_ssrc.end(), ssrc) !=
45 desired_ssrc.end();
46 }
47
48 double AbsSendTimeToMicroseconds(int64_t abs_send_time) {
49 // The timestamp is a fixed point representation with 6 bits for seconds
50 // and 18 bits for fractions of a second. Thus, we divide by 2^18 to get the
51 // time in seconds and then multiply by 1000000 to convert to microseconds.
52 static constexpr double kTimestampToMicroSec =
53 1000000.0 / static_cast<double>(1 << 18);
54 return abs_send_time * kTimestampToMicroSec;
55 }
56
57 // Computes the difference |later| - |earlier| where |later| and |earlier|
58 // are counters that wrap at |modulus|. The difference is chosen to have the
59 // least absolute value. For example if |modulus| is 8, then the difference will
60 // be chosen in the range [-3, 4]. If |modulus| is 9, then the difference will
61 // be in [-4, 4].
62 int64_t WrappingDifference(uint32_t later, uint32_t earlier, int64_t modulus) {
63 RTC_DCHECK_LE(1, modulus);
64 RTC_DCHECK_LT(later, modulus);
65 RTC_DCHECK_LT(earlier, modulus);
66 int64_t difference =
67 static_cast<int64_t>(later) - static_cast<int64_t>(earlier);
68 int64_t max_difference = modulus / 2;
69 int64_t min_difference = max_difference - modulus + 1;
70 if (difference > max_difference) {
71 difference -= modulus;
72 }
73 if (difference < min_difference) {
74 difference += modulus;
75 }
76 return difference;
77 }
78
79 class StreamId {
80 public:
81 StreamId(uint32_t ssrc,
82 webrtc::PacketDirection direction,
83 webrtc::MediaType media_type)
84 : ssrc_(ssrc), direction_(direction), media_type_(media_type) {}
85
86 bool operator<(const StreamId& other) const {
87 if (ssrc_ < other.ssrc_) {
88 return true;
89 }
90 if (ssrc_ == other.ssrc_) {
91 if (media_type_ < other.media_type_) {
92 return true;
93 }
94 if (media_type_ == other.media_type_) {
95 if (direction_ < other.direction_) {
96 return true;
97 }
98 }
99 }
100 return false;
101 }
102
103 bool operator==(const StreamId& other) const {
104 return ssrc_ == other.ssrc_ && direction_ == other.direction_ &&
105 media_type_ == other.media_type_;
106 }
107
108 uint32_t GetSsrc() const { return ssrc_; }
109
110 private:
111 uint32_t ssrc_;
112 webrtc::PacketDirection direction_;
113 webrtc::MediaType media_type_;
114 };
115
116 const double kXMargin = 1.02;
117 const double kYMargin = 1.1;
118 const double kDefaultXMin = -1;
119 const double kDefaultYMin = -1;
120
121 } // namespace
122
123 namespace webrtc {
124 namespace plotting {
125
126 EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log)
127 : parsed_log_(log), window_duration_(250000), step_(10000) {
128 uint64_t first_timestamp = std::numeric_limits<uint64_t>::max();
129 uint64_t last_timestamp = std::numeric_limits<uint64_t>::min();
130 for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
131 ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
132 if (event_type == ParsedRtcEventLog::EventType::VIDEO_RECEIVER_CONFIG_EVENT)
133 continue;
134 if (event_type == ParsedRtcEventLog::EventType::VIDEO_SENDER_CONFIG_EVENT)
135 continue;
136 if (event_type == ParsedRtcEventLog::EventType::AUDIO_RECEIVER_CONFIG_EVENT)
137 continue;
138 if (event_type == ParsedRtcEventLog::EventType::AUDIO_SENDER_CONFIG_EVENT)
139 continue;
140 uint64_t timestamp = parsed_log_.GetTimestamp(i);
141 first_timestamp = std::min(first_timestamp, timestamp);
142 last_timestamp = std::max(last_timestamp, timestamp);
143 }
144 if (last_timestamp < first_timestamp) {
145 // No useful events in the log.
146 first_timestamp = last_timestamp = 0;
147 }
148 begin_time_ = first_timestamp;
149 end_time_ = last_timestamp;
150 }
151
152 void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction,
153 Plot* plot) {
154 std::map<uint32_t, TimeSeries> time_series;
155
156 PacketDirection direction;
157 MediaType media_type;
158 uint8_t header[IP_PACKET_SIZE];
159 size_t header_length, total_length;
160 float max_y = 0;
161
162 for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
163 ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
164 if (event_type == ParsedRtcEventLog::RTP_EVENT) {
165 parsed_log_.GetRtpHeader(i, &direction, &media_type, header,
166 &header_length, &total_length);
167 if (direction == desired_direction) {
168 // Parse header to get SSRC.
169 RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
170 RTPHeader parsed_header;
171 rtp_parser.Parse(&parsed_header);
172 // Filter on SSRC.
173 if (MatchingSsrc(parsed_header.ssrc, desired_ssrc_)) {
174 uint64_t timestamp = parsed_log_.GetTimestamp(i);
175 float x = static_cast<float>(timestamp - begin_time_) / 1000000;
176 float y = total_length;
177 max_y = std::max(max_y, y);
178 time_series[parsed_header.ssrc].points.push_back(
179 TimeSeriesPoint(x, y));
180 }
181 }
182 }
183 }
184
185 // Set labels and put in graph.
186 for (auto& kv : time_series) {
187 kv.second.label = SsrcToString(kv.first);
188 kv.second.style = BAR_GRAPH;
189 plot->series.push_back(std::move(kv.second));
190 }
191
192 plot->xaxis_min = kDefaultXMin;
193 plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
194 plot->xaxis_label = "Time (s)";
195 plot->yaxis_min = kDefaultYMin;
196 plot->yaxis_max = max_y * kYMargin;
197 plot->yaxis_label = "Packet size (bytes)";
198 if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
199 plot->title = "Incoming RTP packets";
200 } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
201 plot->title = "Outgoing RTP packets";
202 }
203 }
204
205 // For each SSRC, plot the time between the consecutive playouts.
206 void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) {
207 std::map<uint32_t, TimeSeries> time_series;
208 std::map<uint32_t, uint64_t> last_playout;
209
210 uint32_t ssrc;
211 float max_y = 0;
212
213 for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
214 ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
215 if (event_type == ParsedRtcEventLog::AUDIO_PLAYOUT_EVENT) {
216 parsed_log_.GetAudioPlayout(i, &ssrc);
217 uint64_t timestamp = parsed_log_.GetTimestamp(i);
218 if (MatchingSsrc(ssrc, desired_ssrc_)) {
219 float x = static_cast<float>(timestamp - begin_time_) / 1000000;
220 float y = static_cast<float>(timestamp - last_playout[ssrc]) / 1000;
221 if (time_series[ssrc].points.size() == 0) {
222 // There were no previusly logged playout for this SSRC.
223 // Generate a point, but place it on the x-axis.
224 y = 0;
225 }
226 max_y = std::max(max_y, y);
227 time_series[ssrc].points.push_back(TimeSeriesPoint(x, y));
228 last_playout[ssrc] = timestamp;
229 }
230 }
231 }
232
233 // Set labels and put in graph.
234 for (auto& kv : time_series) {
235 kv.second.label = SsrcToString(kv.first);
236 kv.second.style = BAR_GRAPH;
237 plot->series.push_back(std::move(kv.second));
238 }
239
240 plot->xaxis_min = kDefaultXMin;
241 plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
242 plot->xaxis_label = "Time (s)";
243 plot->yaxis_min = kDefaultYMin;
244 plot->yaxis_max = max_y * kYMargin;
245 plot->yaxis_label = "Time since last playout (ms)";
246 plot->title = "Audio playout";
247 }
248
249 // For each SSRC, plot the time between the consecutive playouts.
250 void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) {
251 std::map<uint32_t, TimeSeries> time_series;
252 std::map<uint32_t, uint16_t> last_seqno;
253
254 PacketDirection direction;
255 MediaType media_type;
256 uint8_t header[IP_PACKET_SIZE];
257 size_t header_length, total_length;
258
259 int max_y = 1;
260 int min_y = 0;
261
262 for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
263 ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
264 if (event_type == ParsedRtcEventLog::RTP_EVENT) {
265 parsed_log_.GetRtpHeader(i, &direction, &media_type, header,
266 &header_length, &total_length);
267 uint64_t timestamp = parsed_log_.GetTimestamp(i);
268 if (direction == PacketDirection::kIncomingPacket) {
269 // Parse header to get SSRC.
270 RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
271 RTPHeader parsed_header;
272 rtp_parser.Parse(&parsed_header);
273 // Filter on SSRC.
274 if (MatchingSsrc(parsed_header.ssrc, desired_ssrc_)) {
275 float x = static_cast<float>(timestamp - begin_time_) / 1000000;
276 int y = WrappingDifference(parsed_header.sequenceNumber,
277 last_seqno[parsed_header.ssrc], 1ul << 16);
278 if (time_series[parsed_header.ssrc].points.size() == 0) {
279 // There were no previusly logged playout for this SSRC.
280 // Generate a point, but place it on the x-axis.
281 y = 0;
282 }
283 max_y = std::max(max_y, y);
284 min_y = std::min(min_y, y);
285 time_series[parsed_header.ssrc].points.push_back(
286 TimeSeriesPoint(x, y));
287 last_seqno[parsed_header.ssrc] = parsed_header.sequenceNumber;
288 }
289 }
290 }
291 }
292
293 // Set labels and put in graph.
294 for (auto& kv : time_series) {
295 kv.second.label = SsrcToString(kv.first);
296 kv.second.style = BAR_GRAPH;
297 plot->series.push_back(std::move(kv.second));
298 }
299
300 plot->xaxis_min = kDefaultXMin;
301 plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
302 plot->xaxis_label = "Time (s)";
303 plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
304 plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
305 plot->yaxis_label = "Difference since last packet";
306 plot->title = "Sequence number";
307 }
308
309 void EventLogAnalyzer::CreateDelayChangeGraph(Plot* plot) {
310 // Maps a stream identifier consisting of ssrc, direction and MediaType
311 // to the header extensions used by that stream,
312 std::map<StreamId, RtpHeaderExtensionMap> extension_maps;
313
314 struct SendReceiveTime {
315 SendReceiveTime() = default;
316 SendReceiveTime(uint32_t send_time, uint64_t recv_time)
317 : absolute_send_time(send_time), receive_timestamp(recv_time) {}
318 uint32_t absolute_send_time; // 24-bit value in units of 2^-18 seconds.
319 uint64_t receive_timestamp; // In microseconds.
320 };
321 std::map<StreamId, SendReceiveTime> last_packet;
322 std::map<StreamId, TimeSeries> time_series;
323
324 PacketDirection direction;
325 MediaType media_type;
326 uint8_t header[IP_PACKET_SIZE];
327 size_t header_length, total_length;
328
329 double max_y = 10;
330 double min_y = 0;
331
332 for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
333 ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
334 if (event_type == ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT) {
335 VideoReceiveStream::Config config(nullptr);
336 parsed_log_.GetVideoReceiveConfig(i, &config);
337 StreamId stream(config.rtp.remote_ssrc, kIncomingPacket,
338 MediaType::VIDEO);
339 extension_maps[stream].Erase();
340 for (size_t j = 0; j < config.rtp.extensions.size(); ++j) {
341 const std::string& extension = config.rtp.extensions[j].uri;
342 int id = config.rtp.extensions[j].id;
343 extension_maps[stream].Register(StringToRtpExtensionType(extension),
344 id);
345 }
346 } else if (event_type == ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT) {
347 VideoSendStream::Config config(nullptr);
348 parsed_log_.GetVideoSendConfig(i, &config);
349 for (auto ssrc : config.rtp.ssrcs) {
350 StreamId stream(ssrc, kIncomingPacket, MediaType::VIDEO);
351 extension_maps[stream].Erase();
352 for (size_t j = 0; j < config.rtp.extensions.size(); ++j) {
353 const std::string& extension = config.rtp.extensions[j].uri;
354 int id = config.rtp.extensions[j].id;
355 extension_maps[stream].Register(StringToRtpExtensionType(extension),
356 id);
357 }
358 }
359 } else if (event_type == ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT) {
360 AudioReceiveStream::Config config;
361 // TODO(terelius): Parse the audio configs once we have them
362 } else if (event_type == ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT) {
363 AudioSendStream::Config config(nullptr);
364 // TODO(terelius): Parse the audio configs once we have them
365 } else if (event_type == ParsedRtcEventLog::RTP_EVENT) {
366 parsed_log_.GetRtpHeader(i, &direction, &media_type, header,
367 &header_length, &total_length);
368 if (direction == kIncomingPacket) {
369 // Parse header to get SSRC.
370 RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
371 RTPHeader parsed_header;
372 rtp_parser.Parse(&parsed_header);
373 // Filter on SSRC.
374 if (MatchingSsrc(parsed_header.ssrc, desired_ssrc_)) {
375 StreamId stream(parsed_header.ssrc, direction, media_type);
376 // Look up the extension_map and parse it again to get the extensions.
377 if (extension_maps.count(stream) == 1) {
378 RtpHeaderExtensionMap* extension_map = &extension_maps[stream];
379 rtp_parser.Parse(&parsed_header, extension_map);
380 if (parsed_header.extension.hasAbsoluteSendTime) {
381 uint64_t timestamp = parsed_log_.GetTimestamp(i);
382 int64_t send_time_diff = WrappingDifference(
383 parsed_header.extension.absoluteSendTime,
384 last_packet[stream].absolute_send_time, 1ul << 24);
385 int64_t recv_time_diff =
386 timestamp - last_packet[stream].receive_timestamp;
387
388 float x = static_cast<float>(timestamp - begin_time_) / 1000000;
389 double y = static_cast<double>(
390 recv_time_diff -
391 AbsSendTimeToMicroseconds(send_time_diff)) /
392 1000;
393 if (time_series[stream].points.size() == 0) {
394 // There were no previusly logged playout for this SSRC.
395 // Generate a point, but place it on the x-axis.
396 y = 0;
397 }
398 max_y = std::max(max_y, y);
399 min_y = std::min(min_y, y);
400 time_series[stream].points.push_back(TimeSeriesPoint(x, y));
401 last_packet[stream] = SendReceiveTime(
402 parsed_header.extension.absoluteSendTime, timestamp);
403 }
404 }
405 }
406 }
407 }
408 }
409
410 // Set labels and put in graph.
411 for (auto& kv : time_series) {
412 kv.second.label = SsrcToString(kv.first.GetSsrc());
413 kv.second.style = BAR_GRAPH;
414 plot->series.push_back(std::move(kv.second));
415 }
416
417 plot->xaxis_min = kDefaultXMin;
418 plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
419 plot->xaxis_label = "Time (s)";
420 plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
421 plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
422 plot->yaxis_label = "Latency change (ms)";
423 plot->title = "Network latency change between consecutive packets";
424 }
425
426 void EventLogAnalyzer::CreateAccumulatedDelayChangeGraph(Plot* plot) {
427 // TODO(terelius): Refactor
428
429 // Maps a stream identifier consisting of ssrc, direction and MediaType
430 // to the header extensions used by that stream.
431 std::map<StreamId, RtpHeaderExtensionMap> extension_maps;
432
433 struct SendReceiveTime {
434 SendReceiveTime() = default;
435 SendReceiveTime(uint32_t send_time, uint64_t recv_time, double accumulated)
436 : absolute_send_time(send_time),
437 receive_timestamp(recv_time),
438 accumulated_delay(accumulated) {}
439 uint32_t absolute_send_time; // 24-bit value in units of 2^-18 seconds.
440 uint64_t receive_timestamp; // In microseconds.
441 double accumulated_delay; // In milliseconds.
442 };
443 std::map<StreamId, SendReceiveTime> last_packet;
444 std::map<StreamId, TimeSeries> time_series;
445
446 PacketDirection direction;
447 MediaType media_type;
448 uint8_t header[IP_PACKET_SIZE];
449 size_t header_length, total_length;
450
451 double max_y = 10;
452 double min_y = 0;
453
454 for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
455 ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
456 if (event_type == ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT) {
457 VideoReceiveStream::Config config(nullptr);
458 parsed_log_.GetVideoReceiveConfig(i, &config);
459 StreamId stream(config.rtp.remote_ssrc, kIncomingPacket,
460 MediaType::VIDEO);
461 extension_maps[stream].Erase();
462 for (size_t j = 0; j < config.rtp.extensions.size(); ++j) {
463 const std::string& extension = config.rtp.extensions[j].uri;
464 int id = config.rtp.extensions[j].id;
465 extension_maps[stream].Register(StringToRtpExtensionType(extension),
466 id);
467 }
468 } else if (event_type == ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT) {
469 VideoSendStream::Config config(nullptr);
470 parsed_log_.GetVideoSendConfig(i, &config);
471 for (auto ssrc : config.rtp.ssrcs) {
472 StreamId stream(ssrc, kIncomingPacket, MediaType::VIDEO);
473 extension_maps[stream].Erase();
474 for (size_t j = 0; j < config.rtp.extensions.size(); ++j) {
475 const std::string& extension = config.rtp.extensions[j].uri;
476 int id = config.rtp.extensions[j].id;
477 extension_maps[stream].Register(StringToRtpExtensionType(extension),
478 id);
479 }
480 }
481 } else if (event_type == ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT) {
482 AudioReceiveStream::Config config;
483 // TODO(terelius): Parse the audio configs once we have them
484 } else if (event_type == ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT) {
485 AudioSendStream::Config config(nullptr);
486 // TODO(terelius): Parse the audio configs once we have them
487 } else if (event_type == ParsedRtcEventLog::RTP_EVENT) {
488 parsed_log_.GetRtpHeader(i, &direction, &media_type, header,
489 &header_length, &total_length);
490 if (direction == kIncomingPacket) {
491 // Parse header to get SSRC.
492 RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
493 RTPHeader parsed_header;
494 rtp_parser.Parse(&parsed_header);
495 // Filter on SSRC.
496 if (MatchingSsrc(parsed_header.ssrc, desired_ssrc_)) {
497 StreamId stream(parsed_header.ssrc, direction, media_type);
498 // Look up the extension_map and parse it again to get the extensions.
499 if (extension_maps.count(stream) == 1) {
500 RtpHeaderExtensionMap* extension_map = &extension_maps[stream];
501 rtp_parser.Parse(&parsed_header, extension_map);
502 if (parsed_header.extension.hasAbsoluteSendTime) {
503 uint64_t timestamp = parsed_log_.GetTimestamp(i);
504 int64_t send_time_diff = WrappingDifference(
505 parsed_header.extension.absoluteSendTime,
506 last_packet[stream].absolute_send_time, 1ul << 24);
507 int64_t recv_time_diff =
508 timestamp - last_packet[stream].receive_timestamp;
509
510 float x = static_cast<float>(timestamp - begin_time_) / 1000000;
511 double y = last_packet[stream].accumulated_delay +
512 static_cast<double>(
513 recv_time_diff -
514 AbsSendTimeToMicroseconds(send_time_diff)) /
515 1000;
516 if (time_series[stream].points.size() == 0) {
517 // There were no previusly logged playout for this SSRC.
518 // Generate a point, but place it on the x-axis.
519 y = 0;
520 }
521 max_y = std::max(max_y, y);
522 min_y = std::min(min_y, y);
523 time_series[stream].points.push_back(TimeSeriesPoint(x, y));
524 last_packet[stream] = SendReceiveTime(
525 parsed_header.extension.absoluteSendTime, timestamp, y);
526 }
527 }
528 }
529 }
530 }
531 }
532
533 // Set labels and put in graph.
534 for (auto& kv : time_series) {
535 kv.second.label = SsrcToString(kv.first.GetSsrc());
536 kv.second.style = LINE_GRAPH;
537 plot->series.push_back(std::move(kv.second));
538 }
539
540 plot->xaxis_min = kDefaultXMin;
541 plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
542 plot->xaxis_label = "Time (s)";
543 plot->yaxis_min = min_y - (kYMargin - 1) / 2 * (max_y - min_y);
544 plot->yaxis_max = max_y + (kYMargin - 1) / 2 * (max_y - min_y);
545 plot->yaxis_label = "Latency change (ms)";
546 plot->title = "Accumulated network latency change";
547 }
548
549 // Plot the total bandwidth used by all RTP streams.
550 void EventLogAnalyzer::CreateTotalBitrateGraph(
551 PacketDirection desired_direction,
552 Plot* plot) {
553 struct TimestampSize {
554 TimestampSize(uint64_t t, size_t s) : timestamp(t), size(s) {}
555 uint64_t timestamp;
556 size_t size;
557 };
558 std::vector<TimestampSize> packets;
559
560 PacketDirection direction;
561 size_t total_length;
562
563 // Extract timestamps and sizes for the relevant packets.
564 for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
565 ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
566 if (event_type == ParsedRtcEventLog::RTP_EVENT) {
567 parsed_log_.GetRtpHeader(i, &direction, nullptr, nullptr, nullptr,
568 &total_length);
569 if (direction == desired_direction) {
570 uint64_t timestamp = parsed_log_.GetTimestamp(i);
571 packets.push_back(TimestampSize(timestamp, total_length));
572 }
573 }
574 }
575
576 size_t window_index_begin = 0;
577 size_t window_index_end = 0;
578 size_t bytes_in_window = 0;
579 float max_y = 0;
580
581 // Calculate a moving average of the bitrate and store in a TimeSeries.
582 plot->series.push_back(TimeSeries());
583 for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) {
584 while (window_index_end < packets.size() &&
585 packets[window_index_end].timestamp < time) {
586 bytes_in_window += packets[window_index_end].size;
587 window_index_end++;
588 }
589 while (window_index_begin < packets.size() &&
590 packets[window_index_begin].timestamp < time - window_duration_) {
591 RTC_DCHECK_LE(packets[window_index_begin].size, bytes_in_window);
592 bytes_in_window -= packets[window_index_begin].size;
593 window_index_begin++;
594 }
595 float window_duration_in_seconds =
596 static_cast<float>(window_duration_) / 1000000;
597 float x = static_cast<float>(time - begin_time_) / 1000000;
598 float y = bytes_in_window * 8 / window_duration_in_seconds / 1000;
599 max_y = std::max(max_y, y);
600 plot->series.back().points.push_back(TimeSeriesPoint(x, y));
601 }
602
603 // Set labels.
604 if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
605 plot->series.back().label = "Incoming bitrate";
606 } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
607 plot->series.back().label = "Outgoing bitrate";
608 }
609 plot->series.back().style = LINE_GRAPH;
610
611 plot->xaxis_min = kDefaultXMin;
612 plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
613 plot->xaxis_label = "Time (s)";
614 plot->yaxis_min = kDefaultYMin;
615 plot->yaxis_max = max_y * kYMargin;
616 plot->yaxis_label = "Bitrate (kbps)";
617 if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
618 plot->title = "Incoming RTP bitrate";
619 } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
620 plot->title = "Outgoing RTP bitrate";
621 }
622 }
623
624 // For each SSRC, plot the bandwidth used by that stream.
625 void EventLogAnalyzer::CreateStreamBitrateGraph(
626 PacketDirection desired_direction,
627 Plot* plot) {
628 struct TimestampSize {
629 TimestampSize(uint64_t t, size_t s) : timestamp(t), size(s) {}
630 uint64_t timestamp;
631 size_t size;
632 };
633 std::map<uint32_t, std::vector<TimestampSize> > packets;
634
635 PacketDirection direction;
636 MediaType media_type;
637 uint8_t header[IP_PACKET_SIZE];
638 size_t header_length, total_length;
639
640 // Extract timestamps and sizes for the relevant packets.
641 for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) {
642 ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i);
643 if (event_type == ParsedRtcEventLog::RTP_EVENT) {
644 parsed_log_.GetRtpHeader(i, &direction, &media_type, header,
645 &header_length, &total_length);
646 if (direction == desired_direction) {
647 // Parse header to get SSRC.
648 RtpUtility::RtpHeaderParser rtp_parser(header, header_length);
649 RTPHeader parsed_header;
650 rtp_parser.Parse(&parsed_header);
651 // Filter on SSRC.
652 if (MatchingSsrc(parsed_header.ssrc, desired_ssrc_)) {
653 uint64_t timestamp = parsed_log_.GetTimestamp(i);
654 packets[parsed_header.ssrc].push_back(
655 TimestampSize(timestamp, total_length));
656 }
657 }
658 }
659 }
660
661 float max_y = 0;
662
663 for (auto& kv : packets) {
664 size_t window_index_begin = 0;
665 size_t window_index_end = 0;
666 size_t bytes_in_window = 0;
667
668 // Calculate a moving average of the bitrate and store in a TimeSeries.
669 plot->series.push_back(TimeSeries());
670 for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) {
671 while (window_index_end < kv.second.size() &&
672 kv.second[window_index_end].timestamp < time) {
673 bytes_in_window += kv.second[window_index_end].size;
674 window_index_end++;
675 }
676 while (window_index_begin < kv.second.size() &&
677 kv.second[window_index_begin].timestamp <
678 time - window_duration_) {
679 RTC_DCHECK_LE(kv.second[window_index_begin].size, bytes_in_window);
680 bytes_in_window -= kv.second[window_index_begin].size;
681 window_index_begin++;
682 }
683 float window_duration_in_seconds =
684 static_cast<float>(window_duration_) / 1000000;
685 float x = static_cast<float>(time - begin_time_) / 1000000;
686 float y = bytes_in_window * 8 / window_duration_in_seconds / 1000;
687 max_y = std::max(max_y, y);
688 plot->series.back().points.push_back(TimeSeriesPoint(x, y));
689 }
690
691 // Set labels.
692 plot->series.back().label = SsrcToString(kv.first);
693 plot->series.back().style = LINE_GRAPH;
694 }
695
696 plot->xaxis_min = kDefaultXMin;
697 plot->xaxis_max = (end_time_ - begin_time_) / 1000000 * kXMargin;
698 plot->xaxis_label = "Time (s)";
699 plot->yaxis_min = kDefaultYMin;
700 plot->yaxis_max = max_y * kYMargin;
701 plot->yaxis_label = "Bitrate (kbps)";
702 if (desired_direction == webrtc::PacketDirection::kIncomingPacket) {
703 plot->title = "Incoming bitrate per stream";
704 } else if (desired_direction == webrtc::PacketDirection::kOutgoingPacket) {
705 plot->title = "Outgoing bitrate per stream";
706 }
707 }
708
709 } // namespace plotting
710 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/tools/event_log_visualizer/analyzer.h ('k') | webrtc/tools/event_log_visualizer/generate_timeseries.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698