Index: webrtc/tools/event_log_visualizer/analyzer.cc |
diff --git a/webrtc/tools/event_log_visualizer/analyzer.cc b/webrtc/tools/event_log_visualizer/analyzer.cc |
index 42115e8943c0363970d0917fc0dfa0b62335ee70..9b03cc8e350a2d90058e38aa69fa34719d6ee0e4 100644 |
--- a/webrtc/tools/event_log_visualizer/analyzer.cc |
+++ b/webrtc/tools/event_log_visualizer/analyzer.cc |
@@ -80,6 +80,12 @@ int64_t WrappingDifference(uint32_t later, uint32_t earlier, int64_t modulus) { |
if (difference < min_difference) { |
difference += modulus; |
} |
+ if (difference > max_difference / 2 || difference < min_difference / 2) { |
+ LOG(LS_WARNING) << "Difference between" << later << " and " << earlier |
+ << " expected to be in the range (" << min_difference / 2 |
+ << "," << max_difference / 2 << ") but is " << difference |
+ << ". Correct unwrapping is uncertain."; |
+ } |
return difference; |
} |
@@ -98,6 +104,26 @@ constexpr float kRightMargin = 0.02f; |
constexpr float kBottomMargin = 0.02f; |
constexpr float kTopMargin = 0.05f; |
+class PacketSizeBytes { |
+ public: |
+ using DataType = LoggedRtpPacket; |
+ using ResultType = size_t; |
+ size_t operator()(const LoggedRtpPacket& packet) { |
+ return packet.total_length; |
+ } |
+}; |
+ |
+class SequenceNumberDiff { |
+ public: |
+ using DataType = LoggedRtpPacket; |
+ using ResultType = int64_t; |
+ int64_t operator()(const LoggedRtpPacket& old_packet, |
+ const LoggedRtpPacket& new_packet) { |
+ return WrappingDifference(new_packet.header.sequenceNumber, |
+ old_packet.header.sequenceNumber, 1ul << 16); |
+ } |
+}; |
+ |
class NetworkDelayDiff { |
public: |
class AbsSendTime { |
@@ -140,6 +166,19 @@ class NetworkDelayDiff { |
double delay_change = |
static_cast<double>(recv_time_diff) / 1000 - |
static_cast<double>(send_time_diff) / kVideoSampleRate * 1000; |
+ if (delay_change < -10000 || 10000 < delay_change) { |
stefan-webrtc
2016/08/11 15:40:15
I'd say you could argue that 10 seconds delay chan
terelius
2016/08/19 15:12:19
Though real-time communications won't work if the
stefan-webrtc
2016/08/23 10:01:57
Ok, no risk of it becoming too spammy?
terelius
2016/08/23 18:17:30
No, I think the risk is minimal. I haven't seen it
|
+ LOG(LS_WARNING) << "Unrealistic delay change."; |
+ LOG(LS_WARNING) << "Old capture time " << old_packet.header.timestamp |
+ << ", received time " << old_packet.timestamp; |
+ LOG(LS_WARNING) << "New capture time " << new_packet.header.timestamp |
+ << ", received time " << new_packet.timestamp; |
+ LOG(LS_WARNING) << "Receive time difference " << recv_time_diff << " = " |
+ << static_cast<double>(recv_time_diff) / 1000000 << "s"; |
+ LOG(LS_WARNING) << "Send time difference " << send_time_diff << " = " |
+ << static_cast<double>(send_time_diff) / |
+ kVideoSampleRate |
+ << "s"; |
+ } |
return delay_change; |
} |
}; |
@@ -162,6 +201,18 @@ class Accumulated { |
}; |
template <typename Extractor> |
+void Pointwise(const std::vector<typename Extractor::DataType>& data, |
+ uint64_t begin_time, |
+ TimeSeries* result) { |
+ Extractor extract; |
+ for (size_t i = 0; i < data.size(); i++) { |
+ float x = static_cast<float>(data[i].timestamp - begin_time) / 1000000; |
+ float y = extract(data[i]); |
+ result->points.emplace_back(x, y); |
+ } |
+} |
+ |
+template <typename Extractor> |
void Pairwise(const std::vector<typename Extractor::DataType>& data, |
uint64_t begin_time, |
TimeSeries* result) { |
@@ -173,6 +224,38 @@ void Pairwise(const std::vector<typename Extractor::DataType>& data, |
} |
} |
+template <typename Extractor> |
+void MovingAverage(const std::vector<typename Extractor::DataType>& data, |
stefan-webrtc
2016/08/11 15:40:15
Comment on what this does, e.g. something like, co
terelius
2016/08/19 15:12:19
Done.
|
+ uint64_t begin_time, |
+ uint64_t end_time, |
+ uint64_t window_duration_us, |
+ uint64_t step, |
+ float y_scaling, |
+ webrtc::plotting::TimeSeries* result) { |
+ size_t window_index_begin = 0; |
+ size_t window_index_end = 0; |
+ typename Extractor::ResultType sum_in_window = 0; |
+ |
+ Extractor extract; |
+ // Calculate a moving average of the bitrate and store in a TimeSeries. |
stefan-webrtc
2016/08/11 15:40:15
Not necessarily a bitrate now right?
terelius
2016/08/19 15:12:19
Done.
|
+ for (uint64_t t = begin_time; t < end_time + step; t += step) { |
+ while (window_index_end < data.size() && |
+ data[window_index_end].timestamp < t) { |
+ sum_in_window += extract(data[window_index_end]); |
+ window_index_end++; |
stefan-webrtc
2016/08/11 15:40:15
++window...;
terelius
2016/08/19 15:12:19
Done.
|
+ } |
+ while (window_index_begin < data.size() && |
+ data[window_index_begin].timestamp < t - window_duration_us) { |
+ sum_in_window -= extract(data[window_index_begin]); |
+ window_index_begin++; |
stefan-webrtc
2016/08/11 15:40:15
++window...;
terelius
2016/08/19 15:12:19
Done.
|
+ } |
+ float window_duration_s = static_cast<float>(window_duration_us) / 1000000; |
+ float x = static_cast<float>(t - begin_time) / 1000000; |
+ float y = sum_in_window / window_duration_s * y_scaling; |
+ result->points.emplace_back(x, y); |
+ } |
+} |
+ |
} // namespace |
EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log) |
@@ -381,40 +464,20 @@ bool EventLogAnalyzer::IsAudioSsrc(StreamId stream_id) { |
void EventLogAnalyzer::CreatePacketGraph(PacketDirection desired_direction, |
Plot* plot) { |
- std::map<uint32_t, TimeSeries> time_series; |
- |
- PacketDirection direction; |
- MediaType media_type; |
- uint8_t header[IP_PACKET_SIZE]; |
- size_t header_length, total_length; |
- |
- for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) { |
- ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i); |
- if (event_type == ParsedRtcEventLog::RTP_EVENT) { |
- parsed_log_.GetRtpHeader(i, &direction, &media_type, header, |
- &header_length, &total_length); |
- if (direction == desired_direction) { |
- // Parse header to get SSRC. |
- RtpUtility::RtpHeaderParser rtp_parser(header, header_length); |
- RTPHeader parsed_header; |
- rtp_parser.Parse(&parsed_header); |
- // Filter on SSRC. |
- if (MatchingSsrc(parsed_header.ssrc, desired_ssrc_)) { |
- uint64_t timestamp = parsed_log_.GetTimestamp(i); |
- float x = static_cast<float>(timestamp - begin_time_) / 1000000; |
- float y = total_length; |
- time_series[parsed_header.ssrc].points.push_back( |
- TimeSeriesPoint(x, y)); |
- } |
- } |
+ for (auto& kv : rtp_packets_) { |
+ StreamId stream_id = kv.first; |
+ const std::vector<LoggedRtpPacket>& packet_stream = kv.second; |
+ // Filter on direction and SSRC. |
+ if (stream_id.GetDirection() != desired_direction || |
+ !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { |
+ continue; |
} |
- } |
- // Set labels and put in graph. |
- for (auto& kv : time_series) { |
- kv.second.label = SsrcToString(kv.first); |
- kv.second.style = BAR_GRAPH; |
- plot->series_list_.push_back(std::move(kv.second)); |
+ TimeSeries time_series; |
+ time_series.label = SsrcToString(stream_id.GetSsrc()); |
+ time_series.style = BAR_GRAPH; |
+ Pointwise<PacketSizeBytes>(packet_stream, begin_time_, &time_series); |
+ plot->series_list_.push_back(std::move(time_series)); |
} |
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); |
@@ -468,48 +531,20 @@ void EventLogAnalyzer::CreatePlayoutGraph(Plot* plot) { |
// For each SSRC, plot the time between the consecutive playouts. |
void EventLogAnalyzer::CreateSequenceNumberGraph(Plot* plot) { |
- std::map<uint32_t, TimeSeries> time_series; |
- std::map<uint32_t, uint16_t> last_seqno; |
- |
- PacketDirection direction; |
- MediaType media_type; |
- uint8_t header[IP_PACKET_SIZE]; |
- size_t header_length, total_length; |
- |
- for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) { |
- ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i); |
- if (event_type == ParsedRtcEventLog::RTP_EVENT) { |
- parsed_log_.GetRtpHeader(i, &direction, &media_type, header, |
- &header_length, &total_length); |
- uint64_t timestamp = parsed_log_.GetTimestamp(i); |
- if (direction == PacketDirection::kIncomingPacket) { |
- // Parse header to get SSRC. |
- RtpUtility::RtpHeaderParser rtp_parser(header, header_length); |
- RTPHeader parsed_header; |
- rtp_parser.Parse(&parsed_header); |
- // Filter on SSRC. |
- if (MatchingSsrc(parsed_header.ssrc, desired_ssrc_)) { |
- float x = static_cast<float>(timestamp - begin_time_) / 1000000; |
- int y = WrappingDifference(parsed_header.sequenceNumber, |
- last_seqno[parsed_header.ssrc], 1ul << 16); |
- if (time_series[parsed_header.ssrc].points.size() == 0) { |
- // There were no previusly logged playout for this SSRC. |
- // Generate a point, but place it on the x-axis. |
- y = 0; |
- } |
- time_series[parsed_header.ssrc].points.push_back( |
- TimeSeriesPoint(x, y)); |
- last_seqno[parsed_header.ssrc] = parsed_header.sequenceNumber; |
- } |
- } |
+ for (auto& kv : rtp_packets_) { |
+ StreamId stream_id = kv.first; |
+ const std::vector<LoggedRtpPacket>& packet_stream = kv.second; |
+ // Filter on direction and SSRC. |
+ if (stream_id.GetDirection() != kIncomingPacket || |
+ !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { |
+ continue; |
} |
- } |
- // Set labels and put in graph. |
- for (auto& kv : time_series) { |
- kv.second.label = SsrcToString(kv.first); |
- kv.second.style = BAR_GRAPH; |
- plot->series_list_.push_back(std::move(kv.second)); |
+ TimeSeries time_series; |
+ time_series.label = SsrcToString(stream_id.GetSsrc()); |
+ time_series.style = BAR_GRAPH; |
+ Pairwise<SequenceNumberDiff>(packet_stream, begin_time_, &time_series); |
+ plot->series_list_.push_back(std::move(time_series)); |
} |
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); |
@@ -687,69 +722,23 @@ void EventLogAnalyzer::CreateTotalBitrateGraph( |
void EventLogAnalyzer::CreateStreamBitrateGraph( |
PacketDirection desired_direction, |
Plot* plot) { |
- struct TimestampSize { |
- TimestampSize(uint64_t t, size_t s) : timestamp(t), size(s) {} |
- uint64_t timestamp; |
- size_t size; |
- }; |
- std::map<uint32_t, std::vector<TimestampSize>> packets; |
- |
- PacketDirection direction; |
- MediaType media_type; |
- uint8_t header[IP_PACKET_SIZE]; |
- size_t header_length, total_length; |
- |
- // Extract timestamps and sizes for the relevant packets. |
- for (size_t i = 0; i < parsed_log_.GetNumberOfEvents(); i++) { |
- ParsedRtcEventLog::EventType event_type = parsed_log_.GetEventType(i); |
- if (event_type == ParsedRtcEventLog::RTP_EVENT) { |
- parsed_log_.GetRtpHeader(i, &direction, &media_type, header, |
- &header_length, &total_length); |
- if (direction == desired_direction) { |
- // Parse header to get SSRC. |
- RtpUtility::RtpHeaderParser rtp_parser(header, header_length); |
- RTPHeader parsed_header; |
- rtp_parser.Parse(&parsed_header); |
- // Filter on SSRC. |
- if (MatchingSsrc(parsed_header.ssrc, desired_ssrc_)) { |
- uint64_t timestamp = parsed_log_.GetTimestamp(i); |
- packets[parsed_header.ssrc].push_back( |
- TimestampSize(timestamp, total_length)); |
- } |
- } |
- } |
- } |
- |
- for (auto& kv : packets) { |
- size_t window_index_begin = 0; |
- size_t window_index_end = 0; |
- size_t bytes_in_window = 0; |
- |
- // Calculate a moving average of the bitrate and store in a TimeSeries. |
- plot->series_list_.push_back(TimeSeries()); |
- for (uint64_t time = begin_time_; time < end_time_ + step_; time += step_) { |
- while (window_index_end < kv.second.size() && |
- kv.second[window_index_end].timestamp < time) { |
- bytes_in_window += kv.second[window_index_end].size; |
- window_index_end++; |
- } |
- while (window_index_begin < kv.second.size() && |
- kv.second[window_index_begin].timestamp < |
- time - window_duration_) { |
- RTC_DCHECK_LE(kv.second[window_index_begin].size, bytes_in_window); |
- bytes_in_window -= kv.second[window_index_begin].size; |
- window_index_begin++; |
- } |
- float window_duration_in_seconds = |
- static_cast<float>(window_duration_) / 1000000; |
- float x = static_cast<float>(time - begin_time_) / 1000000; |
- float y = bytes_in_window * 8 / window_duration_in_seconds / 1000; |
- plot->series_list_.back().points.push_back(TimeSeriesPoint(x, y)); |
+ for (auto& kv : rtp_packets_) { |
+ StreamId stream_id = kv.first; |
+ const std::vector<LoggedRtpPacket>& packet_stream = kv.second; |
+ // Filter on direction and SSRC. |
+ if (stream_id.GetDirection() != desired_direction || |
+ !MatchingSsrc(stream_id.GetSsrc(), desired_ssrc_)) { |
+ continue; |
} |
- // Set labels. |
- plot->series_list_.back().label = SsrcToString(kv.first); |
- plot->series_list_.back().style = LINE_GRAPH; |
+ TimeSeries time_series; |
+ time_series.label = SsrcToString(stream_id.GetSsrc()); |
+ time_series.style = LINE_GRAPH; |
+ double bytes_to_kilobits = 8.0 / 1000; |
+ MovingAverage<PacketSizeBytes>(packet_stream, begin_time_, end_time_, |
+ window_duration_, step_, bytes_to_kilobits, |
+ &time_series); |
+ plot->series_list_.push_back(std::move(time_series)); |
} |
plot->SetXAxis(0, call_duration_s_, "Time (s)", kLeftMargin, kRightMargin); |