From 3d8dbcb686e87d2626ded6399a46defc1b201b44 Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Thu, 31 May 2018 12:32:37 +0200 Subject: [PATCH] Adds loss rate filter in BBR controller. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a simple loss rate filter to the BBR network congestion controller. The loss rate is used to control error correction. Previously the value was reported as zero which would disable error correction. Bug: webrtc:8415 Change-Id: Icec8f25fcc9509432ea91eaec30b39a024f92b42 Reviewed-on: https://webrtc-review.googlesource.com/78263 Commit-Queue: Sebastian Jansson Reviewed-by: Björn Terelius Cr-Commit-Position: refs/heads/master@{#23467} --- modules/congestion_controller/bbr/BUILD.gn | 14 ++++ .../bbr/bbr_network_controller.cc | 8 +++ .../bbr/bbr_network_controller.h | 2 + .../bbr/loss_rate_filter.cc | 48 +++++++++++++ .../bbr/loss_rate_filter.h | 38 ++++++++++ .../bbr/loss_rate_filter_unittest.cc | 71 +++++++++++++++++++ 6 files changed, 181 insertions(+) create mode 100644 modules/congestion_controller/bbr/loss_rate_filter.cc create mode 100644 modules/congestion_controller/bbr/loss_rate_filter.h create mode 100644 modules/congestion_controller/bbr/loss_rate_filter_unittest.cc diff --git a/modules/congestion_controller/bbr/BUILD.gn b/modules/congestion_controller/bbr/BUILD.gn index 68d74fe311..4ddf2c98d9 100644 --- a/modules/congestion_controller/bbr/BUILD.gn +++ b/modules/congestion_controller/bbr/BUILD.gn @@ -28,6 +28,7 @@ rtc_source_set("bbr_controller") { ] deps = [ ":bandwidth_sampler", + ":loss_rate_filter", ":rtt_stats", ":windowed_filter", "../../../api:optional", @@ -82,6 +83,16 @@ rtc_source_set("packet_number_indexed_queue") { ] } +rtc_source_set("loss_rate_filter") { + visibility = [ ":*" ] + sources = [ + "loss_rate_filter.cc", + "loss_rate_filter.h", + ] + deps = [ + "../../../api:optional", + ] +} rtc_source_set("rtt_stats") { visibility = [ ":*" ] sources = [ @@ -107,6 +118,7 @@ if (rtc_include_tests) { "bandwidth_sampler_unittest.cc", "bbr_network_controller_unittest.cc", "data_transfer_tracker_unittest.cc", + "loss_rate_filter_unittest.cc", "packet_number_indexed_queue_unittest.cc", "rtt_stats_unittest.cc", "windowed_filter_unittest.cc", @@ -116,12 +128,14 @@ if (rtc_include_tests) { ":bbr", ":bbr_controller", ":data_transfer_tracker", + ":loss_rate_filter", ":packet_number_indexed_queue", ":rtt_stats", ":windowed_filter", "../../../api/transport:network_control_test", "../../../api/units:data_rate", "../../../api/units:time_delta", + "../../../api/units:timestamp", "../../../test:test_support", ] if (!build_with_chromium && is_clang) { diff --git a/modules/congestion_controller/bbr/bbr_network_controller.cc b/modules/congestion_controller/bbr/bbr_network_controller.cc index 76de566244..03491e7e6a 100644 --- a/modules/congestion_controller/bbr/bbr_network_controller.cc +++ b/modules/congestion_controller/bbr/bbr_network_controller.cc @@ -163,6 +163,7 @@ BbrNetworkController::DebugState::DebugState(const DebugState& state) = default; BbrNetworkController::BbrNetworkController(NetworkControllerConfig config) : rtt_stats_(), random_(10), + loss_rate_(), mode_(STARTUP), sampler_(new BandwidthSampler()), round_trip_count_(0), @@ -398,6 +399,13 @@ NetworkControlUpdate BbrNetworkController::OnTransportPacketsFeedback( DiscardLostPackets(lost_packets); std::vector acked_packets = msg.ReceivedWithSendInfo(); + + int packets_sent = + static_cast(lost_packets.size() + acked_packets.size()); + int packets_lost = static_cast(lost_packets.size()); + loss_rate_.UpdateWithLossStatus(msg.feedback_time.ms(), packets_sent, + packets_lost); + // Input the new data into the BBR model of the connection. if (!acked_packets.empty()) { int64_t last_acked_packet = diff --git a/modules/congestion_controller/bbr/bbr_network_controller.h b/modules/congestion_controller/bbr/bbr_network_controller.h index 0f5a1ed0b2..20cda56dbc 100644 --- a/modules/congestion_controller/bbr/bbr_network_controller.h +++ b/modules/congestion_controller/bbr/bbr_network_controller.h @@ -22,6 +22,7 @@ #include "api/transport/network_control.h" #include "api/transport/network_types.h" #include "modules/congestion_controller/bbr/bandwidth_sampler.h" +#include "modules/congestion_controller/bbr/loss_rate_filter.h" #include "modules/congestion_controller/bbr/rtt_stats.h" #include "modules/congestion_controller/bbr/windowed_filter.h" @@ -215,6 +216,7 @@ class BbrNetworkController : public NetworkControllerInterface { RttStats rtt_stats_; webrtc::Random random_; + LossRateFilter loss_rate_; rtc::Optional constraints_; diff --git a/modules/congestion_controller/bbr/loss_rate_filter.cc b/modules/congestion_controller/bbr/loss_rate_filter.cc new file mode 100644 index 0000000000..302e64a429 --- /dev/null +++ b/modules/congestion_controller/bbr/loss_rate_filter.cc @@ -0,0 +1,48 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/congestion_controller/bbr/loss_rate_filter.h" + +namespace webrtc { +namespace bbr { +namespace { +// From SendSideBandwidthEstimation. +const int kLimitNumPackets = 20; +// From RTCPSender video report interval. +const int64_t kUpdateIntervalMs = 1000; +} // namespace + +LossRateFilter::LossRateFilter() + : lost_packets_since_last_loss_update_(0), + expected_packets_since_last_loss_update_(0), + loss_rate_estimate_(0.0), + next_loss_update_ms_(0) {} + +void LossRateFilter::UpdateWithLossStatus(int64_t feedback_time, + int packets_sent, + int packets_lost) { + lost_packets_since_last_loss_update_ += packets_lost; + expected_packets_since_last_loss_update_ += packets_sent; + + if (feedback_time >= next_loss_update_ms_ && + expected_packets_since_last_loss_update_ >= kLimitNumPackets) { + int64_t lost = lost_packets_since_last_loss_update_; + int64_t expected = expected_packets_since_last_loss_update_; + loss_rate_estimate_ = static_cast(lost) / expected; + next_loss_update_ms_ = feedback_time + kUpdateIntervalMs; + lost_packets_since_last_loss_update_ = 0; + expected_packets_since_last_loss_update_ = 0; + } +} + +double LossRateFilter::GetLossRate() const { + return loss_rate_estimate_; +} +} // namespace bbr +} // namespace webrtc diff --git a/modules/congestion_controller/bbr/loss_rate_filter.h b/modules/congestion_controller/bbr/loss_rate_filter.h new file mode 100644 index 0000000000..4cc0cbe8b1 --- /dev/null +++ b/modules/congestion_controller/bbr/loss_rate_filter.h @@ -0,0 +1,38 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#ifndef MODULES_CONGESTION_CONTROLLER_BBR_LOSS_RATE_FILTER_H_ +#define MODULES_CONGESTION_CONTROLLER_BBR_LOSS_RATE_FILTER_H_ + +#include "api/optional.h" + +namespace webrtc { +namespace bbr { + +// Loss rate filter based on the implementation in SendSideBandwidthEstimation +// and the RTCPSender receiver report interval for video. +class LossRateFilter { + public: + LossRateFilter(); + void UpdateWithLossStatus(int64_t feedback_time_ms, + int packets_sent, + int packets_lost); + double GetLossRate() const; + + private: + int lost_packets_since_last_loss_update_; + int expected_packets_since_last_loss_update_; + double loss_rate_estimate_; + int64_t next_loss_update_ms_; +}; + +} // namespace bbr +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_BBR_LOSS_RATE_FILTER_H_ diff --git a/modules/congestion_controller/bbr/loss_rate_filter_unittest.cc b/modules/congestion_controller/bbr/loss_rate_filter_unittest.cc new file mode 100644 index 0000000000..c007da8b52 --- /dev/null +++ b/modules/congestion_controller/bbr/loss_rate_filter_unittest.cc @@ -0,0 +1,71 @@ +/* + * Copyright 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ +#include "modules/congestion_controller/bbr/loss_rate_filter.h" +#include "api/units/timestamp.h" +#include "test/gtest.h" + +namespace webrtc { +namespace bbr { + +namespace { +const Timestamp kTestStartTime = Timestamp::seconds(100000); +} // namespace + +TEST(LossRateFilterTest, AccumulatesToOne) { + LossRateFilter filter; + Timestamp current_time = kTestStartTime; + for (int i = 0; i < 10; i++) { + filter.UpdateWithLossStatus(current_time.ms(), 10, 10); + current_time += TimeDelta::seconds(1); + } + EXPECT_NEAR(filter.GetLossRate(), 1.0, 0.01); +} + +TEST(LossRateFilterTest, StaysAtZero) { + LossRateFilter filter; + Timestamp current_time = kTestStartTime; + for (int i = 0; i < 10; i++) { + filter.UpdateWithLossStatus(current_time.ms(), 10, 0); + current_time += TimeDelta::seconds(1); + } + EXPECT_NEAR(filter.GetLossRate(), 0.0, 0.01); +} + +TEST(LossRateFilterTest, VariesWithInput) { + LossRateFilter filter; + Timestamp current_time = kTestStartTime; + for (int j = 0; j < 10; j++) { + for (int i = 0; i < 5; i++) { + filter.UpdateWithLossStatus(current_time.ms(), 10, 10); + current_time += TimeDelta::seconds(1); + } + EXPECT_NEAR(filter.GetLossRate(), 1.0, 0.1); + for (int i = 0; i < 5; i++) { + filter.UpdateWithLossStatus(current_time.ms(), 10, 0); + current_time += TimeDelta::seconds(1); + } + EXPECT_NEAR(filter.GetLossRate(), 0.0, 0.1); + } +} + +TEST(LossRateFilterTest, DetectsChangingRate) { + LossRateFilter filter; + Timestamp current_time = kTestStartTime; + for (int per_decile = 0; per_decile < 10; per_decile += 1) { + // Update every 200 ms for 2 seconds + for (int i = 0; i < 10; i++) { + current_time += TimeDelta::ms(200); + filter.UpdateWithLossStatus(current_time.ms(), 10, per_decile); + } + EXPECT_NEAR(filter.GetLossRate(), per_decile / 10.0, 0.05); + } +} +} // namespace bbr +} // namespace webrtc