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}
This commit is contained in:
parent
3a1c40a60a
commit
0182f85fd1
@ -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<int>((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<uint32_t> rate = rate_.Rate(now_ms);
|
||||
if (!rate)
|
||||
return;
|
||||
|
||||
int percentage = static_cast<int>(*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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user