From 0182f85fd1f88974a3fac18679196b241a30d7c3 Mon Sep 17 00:00:00 2001 From: Sergey Ulanov Date: Wed, 16 Nov 2016 15:42:11 -0800 Subject: [PATCH] More reliable ALR detection Previously AlrDetector was measuring amount of data sent in each 100ms interval and would enter ALR mode after 5 consecutive intervals when average bandwidth usage doesn't exceed 30% of the current estimate estimate. This meant that an application that uses only slightely more than 6% of total bandwidth may stay out of ALR mode, e.g. if it sends a frame of size BW*30ms every 0.5 seconds. 100ms is too short interval to average over, particularly when frame-rate falls below 10fps. With this change AlrDetector averages BW usage over last 500ms. It then enters ALR state when usage falls below 30% and exits it when usage exceeds 50%. BUG=webrtc:6332 R=philipel@webrtc.org, stefan@webrtc.org Review URL: https://codereview.webrtc.org/2503643003 . Cr-Commit-Position: refs/heads/master@{#15109} --- webrtc/modules/pacing/alr_detector.cc | 63 ++++------- webrtc/modules/pacing/alr_detector.h | 17 +-- .../modules/pacing/alr_detector_unittest.cc | 103 ++++++++++++++---- webrtc/modules/pacing/paced_sender.cc | 2 +- 4 files changed, 116 insertions(+), 69 deletions(-) diff --git a/webrtc/modules/pacing/alr_detector.cc b/webrtc/modules/pacing/alr_detector.cc index 677c7e018e..90afe18fef 100644 --- a/webrtc/modules/pacing/alr_detector.cc +++ b/webrtc/modules/pacing/alr_detector.cc @@ -15,56 +15,39 @@ namespace { -// Time period over which outgoing traffic is measured and considered a single -// data point. -constexpr int kMeasurementPeriodMs = 100; +// Time period over which outgoing traffic is measured. +constexpr int kMeasurementPeriodMs = 500; -// Minimum number of consecutive measurements over |kMeasurementPeriodMs| time -// that indicate sending rate is below |kUsagePercent| to consider being -// application limited. -constexpr int kApplicationLimitedThreshold = 5; - -// Sent traffic percentage as a function of network capaicty to consider traffic -// as application limited. +// Sent traffic percentage as a function of network capacity used to determine +// application-limited region. ALR region start when bandwidth usage drops below +// kAlrStartUsagePercent and ends when it raises above kAlrEndUsagePercent. // NOTE: This is intentionally conservative at the moment until BW adjustments // of application limited region is fine tuned. -constexpr int kUsagePercent = 30; +constexpr int kAlrStartUsagePercent = 30; +constexpr int kAlrEndUsagePercent = 50; } // namespace namespace webrtc { AlrDetector::AlrDetector() - : measurement_interval_bytes_sent_(0), - measurement_interval_elapsed_time_ms_(0), - estimated_bitrate_bps_(0), - application_limited_count_(0) {} + : rate_(kMeasurementPeriodMs, RateStatistics::kBpsScale) {} AlrDetector::~AlrDetector() {} -void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t elapsed_time_ms) { - if (measurement_interval_elapsed_time_ms_ > kMeasurementPeriodMs) { - RTC_DCHECK(estimated_bitrate_bps_); - int max_bytes = - (measurement_interval_elapsed_time_ms_ * estimated_bitrate_bps_) / - (8 * 1000); - RTC_DCHECK_GT(max_bytes, 0); - int utilization = - static_cast((measurement_interval_bytes_sent_ * 100) / max_bytes); - if (utilization < kUsagePercent) { - application_limited_count_++; - if (application_limited_count_ == kApplicationLimitedThreshold) - LOG(LS_INFO) << "ALR start"; - } else { - if (application_limited_count_ >= kApplicationLimitedThreshold) - LOG(LS_INFO) << "ALR stop"; - application_limited_count_ = 0; - } - measurement_interval_elapsed_time_ms_ = elapsed_time_ms; - measurement_interval_bytes_sent_ = bytes_sent; - } else { - measurement_interval_elapsed_time_ms_ += elapsed_time_ms; - measurement_interval_bytes_sent_ += bytes_sent; +void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t now_ms) { + RTC_DCHECK(estimated_bitrate_bps_); + + rate_.Update(bytes_sent, now_ms); + rtc::Optional rate = rate_.Rate(now_ms); + if (!rate) + return; + + int percentage = static_cast(*rate) * 100 / estimated_bitrate_bps_; + if (percentage < kAlrStartUsagePercent && !application_limited_) { + application_limited_ = true; + } else if (percentage > kAlrEndUsagePercent && application_limited_) { + application_limited_ = false; } } @@ -73,8 +56,8 @@ void AlrDetector::SetEstimatedBitrate(int bitrate_bps) { estimated_bitrate_bps_ = bitrate_bps; } -bool AlrDetector::InApplicationLimitedRegion() { - return application_limited_count_ >= kApplicationLimitedThreshold; +bool AlrDetector::InApplicationLimitedRegion() const { + return application_limited_; } } // namespace webrtc diff --git a/webrtc/modules/pacing/alr_detector.h b/webrtc/modules/pacing/alr_detector.h index 6250cc9053..31b1644d30 100644 --- a/webrtc/modules/pacing/alr_detector.h +++ b/webrtc/modules/pacing/alr_detector.h @@ -11,6 +11,7 @@ #ifndef WEBRTC_MODULES_PACING_ALR_DETECTOR_H_ #define WEBRTC_MODULES_PACING_ALR_DETECTOR_H_ +#include "webrtc/base/rate_statistics.h" #include "webrtc/common_types.h" #include "webrtc/modules/pacing/paced_sender.h" #include "webrtc/typedefs.h" @@ -28,19 +29,19 @@ class AlrDetector { public: AlrDetector(); ~AlrDetector(); - void OnBytesSent(size_t bytes_sent, int64_t elapsed_time_ms); + + void OnBytesSent(size_t bytes_sent, int64_t now_ms); + // Set current estimated bandwidth. void SetEstimatedBitrate(int bitrate_bps); + // Returns true if currently in application-limited region. - bool InApplicationLimitedRegion(); + bool InApplicationLimitedRegion() const; private: - size_t measurement_interval_bytes_sent_; - int64_t measurement_interval_elapsed_time_ms_; - int estimated_bitrate_bps_; - // Number of consecutive periods over which we observe traffic is application - // limited. - int application_limited_count_; + RateStatistics rate_; + int estimated_bitrate_bps_ = 0; + bool application_limited_ = false; }; } // namespace webrtc diff --git a/webrtc/modules/pacing/alr_detector_unittest.cc b/webrtc/modules/pacing/alr_detector_unittest.cc index a30f9fa863..506b55c175 100644 --- a/webrtc/modules/pacing/alr_detector_unittest.cc +++ b/webrtc/modules/pacing/alr_detector_unittest.cc @@ -8,41 +8,104 @@ * be found in the AUTHORS file in the root of the source tree. */ -#include "webrtc/test/gtest.h" #include "webrtc/modules/pacing/alr_detector.h" +#include "webrtc/test/gtest.h" + namespace { -constexpr int kMeasuredIntervalMs = 110; constexpr int kEstimatedBitrateBps = 300000; -constexpr int kBytesInIntervalAtEstimatedBitrate = - (kEstimatedBitrateBps / 8) * kMeasuredIntervalMs / 1000; } // namespace namespace webrtc { -TEST(AlrDetectorTest, ApplicationLimitedWhenLittleDataSent) { - AlrDetector alr_detector; +class AlrDetectorTest : public testing::Test { + public: + void SetUp() override { + alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps); + } - alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps); - for (int i = 0; i < 6; i++) - alr_detector.OnBytesSent(0, kMeasuredIntervalMs); - EXPECT_EQ(alr_detector.InApplicationLimitedRegion(), true); + void SimulateOutgoingTraffic(int interval_ms, int usage_percentage) { + const int kTimeStepMs = 10; + for (int t = 0; t < interval_ms; t += kTimeStepMs) { + now_ms += kTimeStepMs; + alr_detector_.OnBytesSent(kEstimatedBitrateBps * usage_percentage * + kTimeStepMs / (8 * 100 * 1000), + now_ms); + } - for (int i = 0; i < 6; i++) - alr_detector.OnBytesSent(100, kMeasuredIntervalMs); - EXPECT_EQ(alr_detector.InApplicationLimitedRegion(), true); + int remainder_ms = interval_ms % kTimeStepMs; + now_ms += remainder_ms; + if (remainder_ms > 0) { + alr_detector_.OnBytesSent(kEstimatedBitrateBps * usage_percentage * + remainder_ms / (8 * 100 * 1000), + remainder_ms); + } + } + + protected: + AlrDetector alr_detector_; + int64_t now_ms = 1; +}; + +TEST_F(AlrDetectorTest, AlrDetection) { + // Start in non-ALR state. + EXPECT_FALSE(alr_detector_.InApplicationLimitedRegion()); + + // Stay in non-ALR state when usage is close to 100%. + SimulateOutgoingTraffic(500, 90); + EXPECT_FALSE(alr_detector_.InApplicationLimitedRegion()); + + // Verify that we ALR starts when bitrate drops below 20%. + SimulateOutgoingTraffic(500, 20); + EXPECT_TRUE(alr_detector_.InApplicationLimitedRegion()); + + // Verify that we remain in ALR state while usage is still below 50%. + SimulateOutgoingTraffic(500, 40); + EXPECT_TRUE(alr_detector_.InApplicationLimitedRegion()); + + // Verify that ALR ends when usage is above 50%. + SimulateOutgoingTraffic(500, 60); + EXPECT_FALSE(alr_detector_.InApplicationLimitedRegion()); } -TEST(AlrDetectorTest, NetworkLimitedWhenSendingCloseToEstimate) { - AlrDetector alr_detector; +TEST_F(AlrDetectorTest, ShortSpike) { + // Start in non-ALR state. + EXPECT_FALSE(alr_detector_.InApplicationLimitedRegion()); - alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps); - for (int i = 0; i < 6; i++) - alr_detector.OnBytesSent(kBytesInIntervalAtEstimatedBitrate, - kMeasuredIntervalMs); - EXPECT_EQ(alr_detector.InApplicationLimitedRegion(), false); + // Verify that we ALR starts when bitrate drops below 20%. + SimulateOutgoingTraffic(500, 20); + EXPECT_TRUE(alr_detector_.InApplicationLimitedRegion()); + + // Verify that we stay in ALR region even after a short bitrate spike. + SimulateOutgoingTraffic(100, 150); + EXPECT_TRUE(alr_detector_.InApplicationLimitedRegion()); + + SimulateOutgoingTraffic(200, 20); + EXPECT_TRUE(alr_detector_.InApplicationLimitedRegion()); + + // ALR ends when usage is above 50%. + SimulateOutgoingTraffic(500, 60); + EXPECT_FALSE(alr_detector_.InApplicationLimitedRegion()); +} + +TEST_F(AlrDetectorTest, BandwidthEstimateChanges) { + // Start in non-ALR state. + EXPECT_FALSE(alr_detector_.InApplicationLimitedRegion()); + + // ALR starts when bitrate drops below 20%. + SimulateOutgoingTraffic(500, 20); + EXPECT_TRUE(alr_detector_.InApplicationLimitedRegion()); + + // When bandwidth estimate drops the detector should stay in ALR mode and quit + // it shortly afterwards as the sender continues sending the same amount of + // traffic. This is necessary to ensure that ProbeController can still react + // to the BWE drop by initiating a new probe. + alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps / 5); + EXPECT_TRUE(alr_detector_.InApplicationLimitedRegion()); + SimulateOutgoingTraffic(10, 20); + EXPECT_FALSE(alr_detector_.InApplicationLimitedRegion()); } } // namespace webrtc diff --git a/webrtc/modules/pacing/paced_sender.cc b/webrtc/modules/pacing/paced_sender.cc index d38154a241..445d116ed7 100644 --- a/webrtc/modules/pacing/paced_sender.cc +++ b/webrtc/modules/pacing/paced_sender.cc @@ -451,7 +451,7 @@ void PacedSender::Process() { } if (is_probing && bytes_sent > 0) prober_->ProbeSent(clock_->TimeInMilliseconds(), bytes_sent); - alr_detector_->OnBytesSent(bytes_sent, elapsed_time_ms); + alr_detector_->OnBytesSent(bytes_sent, now_us / 1000); } bool PacedSender::SendPacket(const paced_sender::Packet& packet,