Cleanup in congestion controller.
This CL removes some indirection and moves some constants. This is done to simplify understanding and debugging of the code. Bug: webrtc:9718 Change-Id: Ibe2b1da0163b4c97ffd1a5bc157f6aa59582d697 Reviewed-on: https://webrtc-review.googlesource.com/98240 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Christoffer Rodbro <crodbro@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24732}
This commit is contained in:
committed by
Commit Bot
parent
9eda327248
commit
c0af56b9fb
@ -30,6 +30,7 @@
|
||||
#include "system_wrappers/include/metrics.h"
|
||||
|
||||
namespace {
|
||||
static const int64_t kStreamTimeOutMs = 2000;
|
||||
constexpr int kTimestampGroupLengthMs = 5;
|
||||
constexpr int kAbsSendTimeFraction = 18;
|
||||
constexpr int kAbsSendTimeInterArrivalUpshift = 8;
|
||||
|
||||
@ -29,8 +29,6 @@ class RtcEventLog;
|
||||
|
||||
class DelayBasedBwe {
|
||||
public:
|
||||
static const int64_t kStreamTimeOutMs = 2000;
|
||||
|
||||
struct Result {
|
||||
Result();
|
||||
Result(bool probe, uint32_t target_bitrate_bps);
|
||||
|
||||
@ -37,8 +37,8 @@ void GoogCcStatePrinter::PrintValues(FILE* out) {
|
||||
controller_->delay_based_bwe_->rate_control_.rate_control_state_,
|
||||
controller_->delay_based_bwe_->rate_control_.rate_control_region_,
|
||||
controller_->alr_detector_->alr_started_time_ms_.has_value(),
|
||||
trendline_estimator->trendline_,
|
||||
trendline_estimator->prev_modified_offset_,
|
||||
trendline_estimator->prev_trend_,
|
||||
trendline_estimator->prev_modified_trend_,
|
||||
trendline_estimator->threshold_);
|
||||
}
|
||||
|
||||
|
||||
@ -49,11 +49,10 @@ absl::optional<double> LinearFitSlope(
|
||||
constexpr double kMaxAdaptOffsetMs = 15.0;
|
||||
constexpr double kOverUsingTimeThreshold = 10;
|
||||
constexpr int kMinNumDeltas = 60;
|
||||
constexpr int kDeltaCounterMax = 1000;
|
||||
|
||||
} // namespace
|
||||
|
||||
enum { kDeltaCounterMax = 1000 };
|
||||
|
||||
TrendlineEstimator::TrendlineEstimator(size_t window_size,
|
||||
double smoothing_coef,
|
||||
double threshold_gain)
|
||||
@ -65,14 +64,13 @@ TrendlineEstimator::TrendlineEstimator(size_t window_size,
|
||||
accumulated_delay_(0),
|
||||
smoothed_delay_(0),
|
||||
delay_hist_(),
|
||||
trendline_(0),
|
||||
k_up_(0.0087),
|
||||
k_down_(0.039),
|
||||
overusing_time_threshold_(kOverUsingTimeThreshold),
|
||||
threshold_(12.5),
|
||||
prev_modified_offset_(NAN),
|
||||
prev_modified_trend_(NAN),
|
||||
last_update_ms_(-1),
|
||||
prev_offset_(0.0),
|
||||
prev_trend_(0.0),
|
||||
time_over_using_(-1),
|
||||
overuse_counter_(0),
|
||||
hypothesis_(BandwidthUsage::kBwNormal) {}
|
||||
@ -84,8 +82,7 @@ void TrendlineEstimator::Update(double recv_delta_ms,
|
||||
int64_t arrival_time_ms) {
|
||||
const double delta_ms = recv_delta_ms - send_delta_ms;
|
||||
++num_of_deltas_;
|
||||
if (num_of_deltas_ > kDeltaCounterMax)
|
||||
num_of_deltas_ = kDeltaCounterMax;
|
||||
num_of_deltas_ = std::min(num_of_deltas_, kDeltaCounterMax);
|
||||
if (first_arrival_time_ms_ == -1)
|
||||
first_arrival_time_ms_ = arrival_time_ms;
|
||||
|
||||
@ -104,32 +101,36 @@ void TrendlineEstimator::Update(double recv_delta_ms,
|
||||
smoothed_delay_));
|
||||
if (delay_hist_.size() > window_size_)
|
||||
delay_hist_.pop_front();
|
||||
double trend = prev_trend_;
|
||||
if (delay_hist_.size() == window_size_) {
|
||||
// Only update trendline_ if it is possible to fit a line to the data.
|
||||
trendline_ = LinearFitSlope(delay_hist_).value_or(trendline_);
|
||||
// Update trend_ if it is possible to fit a line to the data. The delay
|
||||
// trend can be seen as an estimate of (send_rate - capacity)/capacity.
|
||||
// 0 < trend < 1 -> the delay increases, queues are filling up
|
||||
// trend == 0 -> the delay does not change
|
||||
// trend < 0 -> the delay decreases, queues are being emptied
|
||||
trend = LinearFitSlope(delay_hist_).value_or(trend);
|
||||
}
|
||||
|
||||
BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trendline_);
|
||||
BWE_TEST_LOGGING_PLOT(1, "trendline_slope", arrival_time_ms, trend);
|
||||
|
||||
Detect(trendline_slope(), send_delta_ms, num_of_deltas(), arrival_time_ms);
|
||||
Detect(trend, send_delta_ms, arrival_time_ms);
|
||||
}
|
||||
|
||||
BandwidthUsage TrendlineEstimator::State() const {
|
||||
return hypothesis_;
|
||||
}
|
||||
|
||||
void TrendlineEstimator::Detect(double offset,
|
||||
double ts_delta,
|
||||
int num_of_deltas,
|
||||
int64_t now_ms) {
|
||||
if (num_of_deltas < 2) {
|
||||
void TrendlineEstimator::Detect(double trend, double ts_delta, int64_t now_ms) {
|
||||
if (num_of_deltas_ < 2) {
|
||||
hypothesis_ = BandwidthUsage::kBwNormal;
|
||||
return;
|
||||
}
|
||||
const double T = std::min(num_of_deltas, kMinNumDeltas) * offset;
|
||||
BWE_TEST_LOGGING_PLOT(1, "T", now_ms, T);
|
||||
const double modified_trend =
|
||||
std::min(num_of_deltas_, kMinNumDeltas) * trend * threshold_gain_;
|
||||
prev_modified_trend_ = modified_trend;
|
||||
BWE_TEST_LOGGING_PLOT(1, "T", now_ms, modified_trend);
|
||||
BWE_TEST_LOGGING_PLOT(1, "threshold", now_ms, threshold_);
|
||||
if (T > threshold_) {
|
||||
if (modified_trend > threshold_) {
|
||||
if (time_over_using_ == -1) {
|
||||
// Initialize the timer. Assume that we've been
|
||||
// over-using half of the time since the previous
|
||||
@ -141,13 +142,13 @@ void TrendlineEstimator::Detect(double offset,
|
||||
}
|
||||
overuse_counter_++;
|
||||
if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 1) {
|
||||
if (offset >= prev_offset_) {
|
||||
if (trend >= prev_trend_) {
|
||||
time_over_using_ = 0;
|
||||
overuse_counter_ = 0;
|
||||
hypothesis_ = BandwidthUsage::kBwOverusing;
|
||||
}
|
||||
}
|
||||
} else if (T < -threshold_) {
|
||||
} else if (modified_trend < -threshold_) {
|
||||
time_over_using_ = -1;
|
||||
overuse_counter_ = 0;
|
||||
hypothesis_ = BandwidthUsage::kBwUnderusing;
|
||||
@ -156,28 +157,26 @@ void TrendlineEstimator::Detect(double offset,
|
||||
overuse_counter_ = 0;
|
||||
hypothesis_ = BandwidthUsage::kBwNormal;
|
||||
}
|
||||
prev_offset_ = offset;
|
||||
|
||||
UpdateThreshold(T, now_ms);
|
||||
prev_trend_ = trend;
|
||||
UpdateThreshold(modified_trend, now_ms);
|
||||
}
|
||||
|
||||
void TrendlineEstimator::UpdateThreshold(double modified_offset,
|
||||
void TrendlineEstimator::UpdateThreshold(double modified_trend,
|
||||
int64_t now_ms) {
|
||||
prev_modified_offset_ = modified_offset;
|
||||
if (last_update_ms_ == -1)
|
||||
last_update_ms_ = now_ms;
|
||||
|
||||
if (fabs(modified_offset) > threshold_ + kMaxAdaptOffsetMs) {
|
||||
if (fabs(modified_trend) > threshold_ + kMaxAdaptOffsetMs) {
|
||||
// Avoid adapting the threshold to big latency spikes, caused e.g.,
|
||||
// by a sudden capacity drop.
|
||||
last_update_ms_ = now_ms;
|
||||
return;
|
||||
}
|
||||
|
||||
const double k = fabs(modified_offset) < threshold_ ? k_down_ : k_up_;
|
||||
const double k = fabs(modified_trend) < threshold_ ? k_down_ : k_up_;
|
||||
const int64_t kMaxTimeDeltaMs = 100;
|
||||
int64_t time_delta_ms = std::min(now_ms - last_update_ms_, kMaxTimeDeltaMs);
|
||||
threshold_ += k * (fabs(modified_offset) - threshold_) * time_delta_ms;
|
||||
threshold_ += k * (fabs(modified_trend) - threshold_) * time_delta_ms;
|
||||
threshold_ = rtc::SafeClamp(threshold_, 6.f, 600.f);
|
||||
last_update_ms_ = now_ms;
|
||||
}
|
||||
|
||||
@ -43,21 +43,14 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface {
|
||||
|
||||
BandwidthUsage State() const override;
|
||||
|
||||
// Returns the estimated trend k multiplied by some gain.
|
||||
// 0 < k < 1 -> the delay increases, queues are filling up
|
||||
// k == 0 -> the delay does not change
|
||||
// k < 0 -> the delay decreases, queues are being emptied
|
||||
double trendline_slope() const { return trendline_ * threshold_gain_; }
|
||||
|
||||
// Returns the number of deltas which the current estimator state is based on.
|
||||
unsigned int num_of_deltas() const { return num_of_deltas_; }
|
||||
protected:
|
||||
// Used in unit tests.
|
||||
double modified_trend() const { return prev_trend_ * threshold_gain_; }
|
||||
|
||||
private:
|
||||
friend class GoogCcStatePrinter;
|
||||
void Detect(double offset,
|
||||
double ts_delta,
|
||||
int num_of_deltas,
|
||||
int64_t now_ms);
|
||||
|
||||
void Detect(double trend, double ts_delta, int64_t now_ms);
|
||||
|
||||
void UpdateThreshold(double modified_offset, int64_t now_ms);
|
||||
|
||||
@ -66,7 +59,7 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface {
|
||||
const double smoothing_coef_;
|
||||
const double threshold_gain_;
|
||||
// Used by the existing threshold.
|
||||
unsigned int num_of_deltas_;
|
||||
int num_of_deltas_;
|
||||
// Keep the arrival times small by using the change from the first packet.
|
||||
int64_t first_arrival_time_ms_;
|
||||
// Exponential backoff filtering.
|
||||
@ -74,15 +67,14 @@ class TrendlineEstimator : public DelayIncreaseDetectorInterface {
|
||||
double smoothed_delay_;
|
||||
// Linear least squares regression.
|
||||
std::deque<std::pair<double, double>> delay_hist_;
|
||||
double trendline_;
|
||||
|
||||
const double k_up_;
|
||||
const double k_down_;
|
||||
double overusing_time_threshold_;
|
||||
double threshold_;
|
||||
double prev_modified_offset_;
|
||||
double prev_modified_trend_;
|
||||
int64_t last_update_ms_;
|
||||
double prev_offset_;
|
||||
double prev_trend_;
|
||||
double time_over_using_;
|
||||
int overuse_counter_;
|
||||
BandwidthUsage hypothesis_;
|
||||
|
||||
@ -20,9 +20,13 @@ constexpr double kSmoothing = 0.0;
|
||||
constexpr double kGain = 1;
|
||||
constexpr int64_t kAvgTimeBetweenPackets = 10;
|
||||
constexpr size_t kPacketCount = 2 * kWindowSize + 1;
|
||||
|
||||
class TrendlineEstimatorForTest : public TrendlineEstimator {
|
||||
public:
|
||||
using TrendlineEstimator::TrendlineEstimator;
|
||||
using TrendlineEstimator::modified_trend;
|
||||
};
|
||||
void TestEstimator(double slope, double jitter_stddev, double tolerance) {
|
||||
TrendlineEstimator estimator(kWindowSize, kSmoothing, kGain);
|
||||
TrendlineEstimatorForTest estimator(kWindowSize, kSmoothing, kGain);
|
||||
Random random(0x1234567);
|
||||
int64_t send_times[kPacketCount];
|
||||
int64_t recv_times[kPacketCount];
|
||||
@ -39,9 +43,9 @@ void TestEstimator(double slope, double jitter_stddev, double tolerance) {
|
||||
double send_delta = send_times[i] - send_times[i - 1];
|
||||
estimator.Update(recv_delta, send_delta, recv_times[i]);
|
||||
if (i < kWindowSize)
|
||||
EXPECT_NEAR(estimator.trendline_slope(), 0, 0.001);
|
||||
EXPECT_NEAR(estimator.modified_trend(), 0, 0.001);
|
||||
else
|
||||
EXPECT_NEAR(estimator.trendline_slope(), slope, tolerance);
|
||||
EXPECT_NEAR(estimator.modified_trend(), slope, tolerance);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user