SCReAMv2: Visualize newly lost, recovered, and CE marked packet events Calculates newly lost, recovered, and CE marked packet feedback events over a rolling window of one smoothed RTT (using ScreamV2::rtt()), as well as per individual feedback message (filtering out zero events). Adds a new graph to analyze_bwe.cc displaying: - Lost per smoothed RTT (continuous line) - Recovered per smoothed RTT (continuous line) - CE marked per smoothed RTT (continuous line) - Lost per feedback (scatter points, non-zero only) - Recovered per feedback (scatter points, non-zero only) - CE marked per feedback (scatter points, non-zero only) Bug: webrtc:436707095 Change-Id: I5fda4d5ec12c998ba32e56739fd629d75d0ef50c Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/475501 Reviewed-by: Björn Terelius <terelius@webrtc.org> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#47831}
diff --git a/rtc_tools/rtc_event_log_visualizer/analyze_bwe.cc b/rtc_tools/rtc_event_log_visualizer/analyze_bwe.cc index e30a546..d52729d 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyze_bwe.cc +++ b/rtc_tools/rtc_event_log_visualizer/analyze_bwe.cc
@@ -862,6 +862,60 @@ plot->SetTitle("Simulated Scream Ratios"); } +void CreateScreamSimulationFeedbackEventsPerRttGraph( + const ParsedRtcEventLog& parsed_log, + const AnalyzerConfig& config, + Plot* plot) { + TimeSeries lost_series("Lost per smoothed RTT", LineStyle::kLine); + TimeSeries recovered_series("Recovered per smoothed RTT", LineStyle::kLine); + TimeSeries ce_marked_series("CE marked per smoothed RTT", LineStyle::kLine); + + TimeSeries lost_per_feedback_series("Lost per feedback", LineStyle::kNone, + PointStyle::kHighlight); + TimeSeries recovered_per_feedback_series( + "Recovered per feedback", LineStyle::kNone, PointStyle::kHighlight); + TimeSeries ce_marked_per_feedback_series( + "CE marked per feedback", LineStyle::kNone, PointStyle::kHighlight); + + LogScreamSimulation simulation({.rate_window = config.window_duration_}, + config.env_); + simulation.ProcessEventsInLog(parsed_log); + + for (const LogScreamSimulation::State& state : simulation.updates()) { + lost_series.points.emplace_back(config.GetCallTimeSec(state.time), + state.packets_lost_per_rtt); + recovered_series.points.emplace_back(config.GetCallTimeSec(state.time), + state.packets_recovered_per_rtt); + ce_marked_series.points.emplace_back(config.GetCallTimeSec(state.time), + state.ce_marked_per_rtt); + + if (state.packets_lost_per_feedback > 0) { + lost_per_feedback_series.points.emplace_back( + config.GetCallTimeSec(state.time), state.packets_lost_per_feedback); + } + if (state.packets_recovered_per_feedback > 0) { + recovered_per_feedback_series.points.emplace_back( + config.GetCallTimeSec(state.time), + state.packets_recovered_per_feedback); + } + if (state.ce_marked_per_feedback > 0) { + ce_marked_per_feedback_series.points.emplace_back( + config.GetCallTimeSec(state.time), state.ce_marked_per_feedback); + } + } + plot->AppendTimeSeries(std::move(lost_series)); + plot->AppendTimeSeries(std::move(recovered_series)); + plot->AppendTimeSeries(std::move(ce_marked_series)); + plot->AppendTimeSeriesIfNotEmpty(std::move(lost_per_feedback_series)); + plot->AppendTimeSeriesIfNotEmpty(std::move(recovered_per_feedback_series)); + plot->AppendTimeSeriesIfNotEmpty(std::move(ce_marked_per_feedback_series)); + + plot->SetXAxis(config.CallBeginTimeSec(), config.CallEndTimeSec(), "Time (s)", + kLeftMargin, kRightMargin); + plot->SetSuggestedYAxis(0, 10, "Packets", kBottomMargin, kTopMargin); + plot->SetTitle("Simulated Scream feedback events per smoothed RTT"); +} + void CreateScreamRefWindowGraph(const ParsedRtcEventLog& parsed_log, const AnalyzerConfig& config, Plot* plot) {
diff --git a/rtc_tools/rtc_event_log_visualizer/analyze_bwe.h b/rtc_tools/rtc_event_log_visualizer/analyze_bwe.h index 5de8598..0216381 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyze_bwe.h +++ b/rtc_tools/rtc_event_log_visualizer/analyze_bwe.h
@@ -55,6 +55,11 @@ const AnalyzerConfig& config, Plot* plot); +void CreateScreamSimulationFeedbackEventsPerRttGraph( + const ParsedRtcEventLog& parsed_log, + const AnalyzerConfig& config, + Plot* plot); + void CreateScreamRefWindowGraph(const ParsedRtcEventLog& parsed_log, const AnalyzerConfig& config, Plot* plot);
diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.cc b/rtc_tools/rtc_event_log_visualizer/analyzer.cc index 5821ad7..c878b18 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer.cc +++ b/rtc_tools/rtc_event_log_visualizer/analyzer.cc
@@ -190,6 +190,10 @@ plots_.RegisterPlot("simulated_scream_ratios", [this](Plot* plot) { this->CreateScreamSimulationRatiosGraph(plot); }); + plots_.RegisterPlot( + "simulated_scream_feedback_events_per_rtt", [this](Plot* plot) { + this->CreateScreamSimulationFeedbackEventsPerRttGraph(plot); + }); plots_.RegisterPlot("outgoing_loss", [this](Plot* plot) { this->CreateOutgoingLossRateGraph(plot); }); @@ -428,6 +432,12 @@ webrtc::CreateScreamSimulationRatiosGraph(parsed_log_, config_, plot); } +void EventLogAnalyzer::CreateScreamSimulationFeedbackEventsPerRttGraph( + Plot* plot) const { + webrtc::CreateScreamSimulationFeedbackEventsPerRttGraph(parsed_log_, config_, + plot); +} + void EventLogAnalyzer::CreateScreamRefWindowGraph(Plot* plot) const { webrtc::CreateScreamRefWindowGraph(parsed_log_, config_, plot); }
diff --git a/rtc_tools/rtc_event_log_visualizer/analyzer.h b/rtc_tools/rtc_event_log_visualizer/analyzer.h index 60d2244..6ccf192 100644 --- a/rtc_tools/rtc_event_log_visualizer/analyzer.h +++ b/rtc_tools/rtc_event_log_visualizer/analyzer.h
@@ -135,6 +135,7 @@ void CreateScreamSimulationBitrateGraph(Plot* plot) const; void CreateScreamSimulationRefWindowGraph(Plot* plot) const; void CreateScreamSimulationRatiosGraph(Plot* plot) const; + void CreateScreamSimulationFeedbackEventsPerRttGraph(Plot* plot) const; void CreateSendSideBweSimulationGraph(Plot* plot) const; void CreateReceiveSideBweSimulationGraph(Plot* plot) const;
diff --git a/rtc_tools/rtc_event_log_visualizer/log_scream_simulation.cc b/rtc_tools/rtc_event_log_visualizer/log_scream_simulation.cc index 2ae08b7..3aa26b4 100644 --- a/rtc_tools/rtc_event_log_visualizer/log_scream_simulation.cc +++ b/rtc_tools/rtc_event_log_visualizer/log_scream_simulation.cc
@@ -14,6 +14,7 @@ #include <vector> #include "api/environment/environment.h" +#include "api/transport/ecn_marking.h" #include "api/transport/network_types.h" #include "api/units/data_rate.h" #include "api/units/data_size.h" @@ -123,10 +124,11 @@ // ScreamNetworkController::OnNetworkRouteChange. scream_.emplace(env_); scream_->SetTargetBitrateConstraints( - /*min=*/DataRate::Zero() /*max=*/, DataRate::PlusInfinity(), + /*min=*/DataRate::Zero(), /*max=*/DataRate::PlusInfinity(), /*start=*/DataRate::KilobitsPerSec(300)); local_candidate_type_ = candidate.local_candidate_type; remote_candidate_type_ = candidate.remote_candidate_type; + feedback_history_.clear(); } } } @@ -160,6 +162,43 @@ } void LogScreamSimulation::LogState(const TransportPacketsFeedback& msg) { + int lost_count = 0; + int recovered_count = 0; + int ce_marked_count = 0; + for (const auto& packet : msg.packet_feedbacks) { + if (packet.reported_lost_for_the_first_time) { + lost_count++; + } + if (packet.reported_recovered_for_the_first_time) { + recovered_count++; + } + if (packet.ecn == EcnMarking::kCe) { + ce_marked_count++; + } + } + + feedback_history_.push_back(FeedbackEvent{ + .time = msg.feedback_time, + .lost_count = lost_count, + .recovered_count = recovered_count, + .ce_marked_count = ce_marked_count, + }); + + TimeDelta rtt = scream_->rtt(); + while (!feedback_history_.empty() && + feedback_history_.front().time < msg.feedback_time - rtt) { + feedback_history_.pop_front(); + } + + int total_lost = 0; + int total_recovered = 0; + int total_ce_marked = 0; + for (const auto& event : feedback_history_) { + total_lost += event.lost_count; + total_recovered += event.recovered_count; + total_ce_marked += event.ce_marked_count; + } + state_.emplace_back(State{ .time = msg.feedback_time, .target_rate = scream_->target_rate(), @@ -192,6 +231,12 @@ .l4s_alpha = scream_->l4s_alpha(), .l4s_alpha_v = scream_->delay_based_congestion_control().l4s_alpha_v(), .loss_event_rate = scream_->loss_event_rate(), + .packets_lost_per_rtt = total_lost, + .packets_recovered_per_rtt = total_recovered, + .ce_marked_per_rtt = total_ce_marked, + .packets_lost_per_feedback = lost_count, + .packets_recovered_per_feedback = recovered_count, + .ce_marked_per_feedback = ce_marked_count, }); }
diff --git a/rtc_tools/rtc_event_log_visualizer/log_scream_simulation.h b/rtc_tools/rtc_event_log_visualizer/log_scream_simulation.h index 6c6e88c..a9458f6 100644 --- a/rtc_tools/rtc_event_log_visualizer/log_scream_simulation.h +++ b/rtc_tools/rtc_event_log_visualizer/log_scream_simulation.h
@@ -11,6 +11,7 @@ #define RTC_TOOLS_RTC_EVENT_LOG_VISUALIZER_LOG_SCREAM_SIMULATION_H_ #include <cstdint> +#include <deque> #include <optional> #include <vector> @@ -68,6 +69,12 @@ double l4s_alpha = 0.0; double l4s_alpha_v = 0.0; double loss_event_rate = 0.0; + int packets_lost_per_rtt = 0; + int packets_recovered_per_rtt = 0; + int ce_marked_per_rtt = 0; + int packets_lost_per_feedback = 0; + int packets_recovered_per_feedback = 0; + int ce_marked_per_feedback = 0; }; struct Config { @@ -105,6 +112,14 @@ std::optional<IceCandidateType> local_candidate_type_; std::optional<IceCandidateType> remote_candidate_type_; + struct FeedbackEvent { + Timestamp time; + int lost_count = 0; + int recovered_count = 0; + int ce_marked_count = 0; + }; + std::deque<FeedbackEvent> feedback_history_; + std::vector<State> state_; }; } // namespace webrtc
diff --git a/rtc_tools/rtc_event_log_visualizer/main.cc b/rtc_tools/rtc_event_log_visualizer/main.cc index f299d9a..3068855 100644 --- a/rtc_tools/rtc_event_log_visualizer/main.cc +++ b/rtc_tools/rtc_event_log_visualizer/main.cc
@@ -253,7 +253,8 @@ {"scream", {"scream_ref_window", "simulated_scream_delay", "simulated_scream_bitrates", "simulated_scream_ref_window", - "simulated_scream_ratios", "network_delay_feedback", "pacer_delay"}}}; + "simulated_scream_ratios", "simulated_scream_feedback_events_per_rtt", + "network_delay_feedback", "pacer_delay"}}}; if (absl::GetFlag(FLAGS_list_plots)) { std::cerr << "List of registered plots (for use with the --plot flag):"