Add outgoing TWCC loss and missing packet feedback plots to event log analyzer.
Bug: webrtc:12707
Change-Id: I737177e6b6737c8c2e7d8803a68e29e9998ba9f8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/321140
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Commit-Queue: Diep Bui <diepbp@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#40925}
diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.cc b/rtc_tools/rtc_event_log_visualizer/analyzer.cc
index d78fea4..01adfc5 100644
--- a/rtc_tools/rtc_event_log_visualizer/analyzer.cc
+++ b/rtc_tools/rtc_event_log_visualizer/analyzer.cc
@@ -12,6 +12,7 @@
#include <algorithm>
#include <cmath>
+#include <deque>
#include <limits>
#include <map>
#include <memory>
@@ -406,6 +407,12 @@
return rtp_packet;
}
+struct PacketLossSummary {
+ size_t num_packets = 0;
+ size_t num_lost_packets = 0;
+ Timestamp base_time = Timestamp::MinusInfinity();
+};
+
} // namespace
EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log,
@@ -1298,6 +1305,100 @@
plot->SetTitle("Simulated BWE behavior");
}
+void EventLogAnalyzer::CreateOutgoingTWCCLossRateGraph(Plot* plot) {
+ TimeSeries loss_rate_series("Loss rate (from packet feedback)",
+ LineStyle::kLine, PointStyle::kHighlight);
+ TimeSeries average_loss_rate_series("Average loss rate last 5s",
+ LineStyle::kLine, PointStyle::kHighlight);
+ TimeSeries missing_feedback_series("Missing feedback", LineStyle::kNone,
+ PointStyle::kHighlight);
+ PacketLossSummary window_summary;
+ Timestamp last_observation_receive_time = Timestamp::Zero();
+
+ // Use loss based bwe 2 observation duration and observation window size.
+ constexpr TimeDelta kObservationDuration = TimeDelta::Millis(250);
+ constexpr uint32_t kObservationWindowSize = 20;
+ std::deque<PacketLossSummary> observations;
+ SeqNumUnwrapper<uint16_t> unwrapper;
+ int64_t last_acked = 1;
+ if (!parsed_log_.transport_feedbacks(kIncomingPacket).empty()) {
+ last_acked =
+ unwrapper.Unwrap(parsed_log_.transport_feedbacks(kIncomingPacket)[0]
+ .transport_feedback.GetBaseSequence());
+ }
+ for (auto& feedback : parsed_log_.transport_feedbacks(kIncomingPacket)) {
+ const rtcp::TransportFeedback& transport_feedback =
+ feedback.transport_feedback;
+ size_t base_seq_num =
+ unwrapper.Unwrap(transport_feedback.GetBaseSequence());
+ // Collect packets that do not have feedback, which are from the last acked
+ // packet, to the current base packet.
+ for (size_t seq_num = last_acked; seq_num < base_seq_num; ++seq_num) {
+ missing_feedback_series.points.emplace_back(
+ config_.GetCallTimeSec(feedback.timestamp),
+ 100 + seq_num - last_acked);
+ }
+ last_acked = base_seq_num + transport_feedback.GetPacketStatusCount();
+
+ // Compute loss rate from the transport feedback.
+ auto loss_rate =
+ static_cast<float>((transport_feedback.GetPacketStatusCount() -
+ transport_feedback.GetReceivedPackets().size()) *
+ 100.0 / transport_feedback.GetPacketStatusCount());
+ loss_rate_series.points.emplace_back(
+ config_.GetCallTimeSec(feedback.timestamp), loss_rate);
+
+ // Compute loss rate in a window of kObservationWindowSize.
+ if (window_summary.num_packets == 0) {
+ window_summary.base_time = feedback.log_time();
+ }
+ window_summary.num_packets += transport_feedback.GetPacketStatusCount();
+ window_summary.num_lost_packets +=
+ transport_feedback.GetPacketStatusCount() -
+ transport_feedback.GetReceivedPackets().size();
+
+ const Timestamp last_received_time = feedback.log_time();
+ const TimeDelta observation_duration =
+ window_summary.base_time == Timestamp::Zero()
+ ? TimeDelta::Zero()
+ : last_received_time - window_summary.base_time;
+ if (observation_duration > kObservationDuration) {
+ last_observation_receive_time = last_received_time;
+ observations.push_back(window_summary);
+ if (observations.size() > kObservationWindowSize) {
+ observations.pop_front();
+ }
+
+ // Compute average loss rate in a number of windows.
+ int total_packets = 0;
+ int total_loss = 0;
+ for (const auto& observation : observations) {
+ total_loss += observation.num_lost_packets;
+ total_packets += observation.num_packets;
+ }
+ if (total_packets > 0) {
+ float average_loss_rate = total_loss * 100.0 / total_packets;
+ average_loss_rate_series.points.emplace_back(
+ config_.GetCallTimeSec(feedback.timestamp), average_loss_rate);
+ } else {
+ average_loss_rate_series.points.emplace_back(
+ config_.GetCallTimeSec(feedback.timestamp), 0);
+ }
+ window_summary = PacketLossSummary();
+ }
+ }
+ // Add the data set to the plot.
+ plot->AppendTimeSeriesIfNotEmpty(std::move(loss_rate_series));
+ plot->AppendTimeSeriesIfNotEmpty(std::move(average_loss_rate_series));
+ plot->AppendTimeSeriesIfNotEmpty(std::move(missing_feedback_series));
+
+ plot->SetXAxis(config_.CallBeginTimeSec(), config_.CallEndTimeSec(),
+ "Time (s)", kLeftMargin, kRightMargin);
+ plot->SetSuggestedYAxis(0, 100, "Loss rate (percent)", kBottomMargin,
+ kTopMargin);
+ plot->SetTitle("Outgoing loss rate (from TWCC feedback)");
+}
+
void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
using RtpPacketType = LoggedRtpPacketOutgoing;
using TransportFeedbackType = LoggedRtcpPacketTransportFeedback;
diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.h b/rtc_tools/rtc_event_log_visualizer/analyzer.h
index e58a482..f63e9a6 100644
--- a/rtc_tools/rtc_event_log_visualizer/analyzer.h
+++ b/rtc_tools/rtc_event_log_visualizer/analyzer.h
@@ -67,6 +67,7 @@
void CreateStreamBitrateGraph(PacketDirection direction, Plot* plot);
void CreateBitrateAllocationGraph(PacketDirection direction, Plot* plot);
+ void CreateOutgoingTWCCLossRateGraph(Plot* plot);
void CreateGoogCcSimulationGraph(Plot* plot);
void CreateSendSideBweSimulationGraph(Plot* plot);
void CreateReceiveSideBweSimulationGraph(Plot* plot);
diff --git a/rtc_tools/rtc_event_log_visualizer/main.cc b/rtc_tools/rtc_event_log_visualizer/main.cc
index aa52527..3e4f3e4 100644
--- a/rtc_tools/rtc_event_log_visualizer/main.cc
+++ b/rtc_tools/rtc_event_log_visualizer/main.cc
@@ -227,7 +227,7 @@
{"sendside_bwe",
{"outgoing_packet_sizes", "outgoing_bitrate", "outgoing_stream_bitrate",
"simulated_sendside_bwe", "network_delay_feedback",
- "fraction_loss_feedback"}},
+ "fraction_loss_feedback", "outgoing_twcc_loss"}},
{"receiveside_bwe",
{"incoming_packet_sizes", "incoming_delay", "incoming_loss_rate",
"incoming_bitrate", "incoming_stream_bitrate",
@@ -377,6 +377,9 @@
plots.RegisterPlot("simulated_goog_cc", [&](Plot* plot) {
analyzer.CreateGoogCcSimulationGraph(plot);
});
+ plots.RegisterPlot("outgoing_twcc_loss", [&](Plot* plot) {
+ analyzer.CreateOutgoingTWCCLossRateGraph(plot);
+ });
plots.RegisterPlot("network_delay_feedback", [&](Plot* plot) {
analyzer.CreateNetworkDelayFeedbackGraph(plot);
});