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}
This commit is contained in:
Diep Bui 2023-10-13 09:29:30 +00:00 committed by WebRTC LUCI CQ
parent ec48886da9
commit 636c3f24b8
3 changed files with 106 additions and 1 deletions

View File

@ -12,6 +12,7 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <deque>
#include <limits> #include <limits>
#include <map> #include <map>
#include <memory> #include <memory>
@ -406,6 +407,12 @@ RtpPacketReceived RtpPacketForBWEFromHeader(const RTPHeader& header) {
return rtp_packet; return rtp_packet;
} }
struct PacketLossSummary {
size_t num_packets = 0;
size_t num_lost_packets = 0;
Timestamp base_time = Timestamp::MinusInfinity();
};
} // namespace } // namespace
EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log, EventLogAnalyzer::EventLogAnalyzer(const ParsedRtcEventLog& log,
@ -1298,6 +1305,100 @@ void EventLogAnalyzer::CreateGoogCcSimulationGraph(Plot* plot) {
plot->SetTitle("Simulated BWE behavior"); 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) { void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
using RtpPacketType = LoggedRtpPacketOutgoing; using RtpPacketType = LoggedRtpPacketOutgoing;
using TransportFeedbackType = LoggedRtcpPacketTransportFeedback; using TransportFeedbackType = LoggedRtcpPacketTransportFeedback;

View File

@ -67,6 +67,7 @@ class EventLogAnalyzer {
void CreateStreamBitrateGraph(PacketDirection direction, Plot* plot); void CreateStreamBitrateGraph(PacketDirection direction, Plot* plot);
void CreateBitrateAllocationGraph(PacketDirection direction, Plot* plot); void CreateBitrateAllocationGraph(PacketDirection direction, Plot* plot);
void CreateOutgoingTWCCLossRateGraph(Plot* plot);
void CreateGoogCcSimulationGraph(Plot* plot); void CreateGoogCcSimulationGraph(Plot* plot);
void CreateSendSideBweSimulationGraph(Plot* plot); void CreateSendSideBweSimulationGraph(Plot* plot);
void CreateReceiveSideBweSimulationGraph(Plot* plot); void CreateReceiveSideBweSimulationGraph(Plot* plot);

View File

@ -227,7 +227,7 @@ int main(int argc, char* argv[]) {
{"sendside_bwe", {"sendside_bwe",
{"outgoing_packet_sizes", "outgoing_bitrate", "outgoing_stream_bitrate", {"outgoing_packet_sizes", "outgoing_bitrate", "outgoing_stream_bitrate",
"simulated_sendside_bwe", "network_delay_feedback", "simulated_sendside_bwe", "network_delay_feedback",
"fraction_loss_feedback"}}, "fraction_loss_feedback", "outgoing_twcc_loss"}},
{"receiveside_bwe", {"receiveside_bwe",
{"incoming_packet_sizes", "incoming_delay", "incoming_loss_rate", {"incoming_packet_sizes", "incoming_delay", "incoming_loss_rate",
"incoming_bitrate", "incoming_stream_bitrate", "incoming_bitrate", "incoming_stream_bitrate",
@ -377,6 +377,9 @@ int main(int argc, char* argv[]) {
plots.RegisterPlot("simulated_goog_cc", [&](Plot* plot) { plots.RegisterPlot("simulated_goog_cc", [&](Plot* plot) {
analyzer.CreateGoogCcSimulationGraph(plot); analyzer.CreateGoogCcSimulationGraph(plot);
}); });
plots.RegisterPlot("outgoing_twcc_loss", [&](Plot* plot) {
analyzer.CreateOutgoingTWCCLossRateGraph(plot);
});
plots.RegisterPlot("network_delay_feedback", [&](Plot* plot) { plots.RegisterPlot("network_delay_feedback", [&](Plot* plot) {
analyzer.CreateNetworkDelayFeedbackGraph(plot); analyzer.CreateNetworkDelayFeedbackGraph(plot);
}); });