From 051251f59832e625c0b8a8310aa3965e09819bdd Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Thu, 29 Nov 2018 18:36:42 +0100 Subject: [PATCH] Extracts LinkCapacityEstimator from AimdRateControl. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares for future refactoring of rate controller. Bug: webrtc:9718 Change-Id: I425c8c547399bda98b4271a0d24a0bb7ee06bc13 Reviewed-on: https://webrtc-review.googlesource.com/c/112420 Commit-Queue: Sebastian Jansson Reviewed-by: Björn Terelius Cr-Commit-Position: refs/heads/master@{#25846} --- .../congestion_controller/goog_cc/BUILD.gn | 12 ++++ .../goog_cc/link_capacity_estimator.cc | 71 +++++++++++++++++++ .../goog_cc/link_capacity_estimator.h | 36 ++++++++++ .../goog_cc/test/goog_cc_printer.cc | 4 +- modules/remote_bitrate_estimator/BUILD.gn | 1 + .../aimd_rate_control.cc | 71 ++++--------------- .../aimd_rate_control.h | 9 +-- 7 files changed, 137 insertions(+), 67 deletions(-) create mode 100644 modules/congestion_controller/goog_cc/link_capacity_estimator.cc create mode 100644 modules/congestion_controller/goog_cc/link_capacity_estimator.h diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index 35577cabcf..237769b5a6 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -52,6 +52,18 @@ rtc_static_library("goog_cc") { ] } +rtc_source_set("link_capacity_estimator") { + sources = [ + "link_capacity_estimator.cc", + "link_capacity_estimator.h", + ] + deps = [ + "../../../api/units:data_rate", + "../../../rtc_base:safe_minmax", + "//third_party/abseil-cpp/absl/types:optional", + ] +} + rtc_source_set("pushback_controller") { sources = [ "congestion_window_pushback_controller.cc", diff --git a/modules/congestion_controller/goog_cc/link_capacity_estimator.cc b/modules/congestion_controller/goog_cc/link_capacity_estimator.cc new file mode 100644 index 0000000000..d16f07482e --- /dev/null +++ b/modules/congestion_controller/goog_cc/link_capacity_estimator.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/goog_cc/link_capacity_estimator.h" + +#include + +#include "rtc_base/numerics/safe_minmax.h" + +namespace webrtc { +LinkCapacityEstimator::LinkCapacityEstimator() {} + +DataRate LinkCapacityEstimator::UpperBound() const { + if (estimate_kbps_.has_value()) + return DataRate::kbps(estimate_kbps_.value() + + 3 * deviation_estimate_kbps()); + return DataRate::Infinity(); +} + +DataRate LinkCapacityEstimator::LowerBound() const { + if (estimate_kbps_.has_value()) + return DataRate::kbps(estimate_kbps_.value() - + 3 * deviation_estimate_kbps()); + return DataRate::Zero(); +} + +void LinkCapacityEstimator::Reset() { + estimate_kbps_.reset(); +} + +void LinkCapacityEstimator::OnOveruseDetected(DataRate acknowledged_rate) { + double ack_rate_kbps = acknowledged_rate.kbps(); + const float alpha = 0.05f; + if (!estimate_kbps_.has_value()) { + estimate_kbps_ = ack_rate_kbps; + } else { + estimate_kbps_ = + (1 - alpha) * estimate_kbps_.value() + alpha * ack_rate_kbps; + } + // Estimate the variance of the link capacity estimate and normalize the + // variance with the link capacity estimate. + const double norm = std::max(estimate_kbps_.value(), 1.0); + double error_kbps = estimate_kbps_.value() - ack_rate_kbps; + deviation_kbps_ = + (1 - alpha) * deviation_kbps_ + alpha * error_kbps * error_kbps / norm; + // 0.4 ~= 14 kbit/s at 500 kbit/s + // 2.5f ~= 35 kbit/s at 500 kbit/s + deviation_kbps_ = rtc::SafeClamp(deviation_kbps_, 0.4f, 2.5f); +} + +bool LinkCapacityEstimator::has_estimate() const { + return estimate_kbps_.has_value(); +} + +DataRate LinkCapacityEstimator::estimate() const { + return DataRate::kbps(*estimate_kbps_); +} + +double LinkCapacityEstimator::deviation_estimate_kbps() const { + // Calculate the max bit rate std dev given the normalized + // variance and the current throughput bitrate. The standard deviation will + // only be used if estimate_kbps_ has a value. + return sqrt(deviation_kbps_ * estimate_kbps_.value()); +} +} // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/link_capacity_estimator.h b/modules/congestion_controller/goog_cc/link_capacity_estimator.h new file mode 100644 index 0000000000..cf7e799836 --- /dev/null +++ b/modules/congestion_controller/goog_cc/link_capacity_estimator.h @@ -0,0 +1,36 @@ +/* + * 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_GOOG_CC_LINK_CAPACITY_ESTIMATOR_H_ +#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_LINK_CAPACITY_ESTIMATOR_H_ + +#include "absl/types/optional.h" +#include "api/units/data_rate.h" + +namespace webrtc { +class LinkCapacityEstimator { + public: + LinkCapacityEstimator(); + DataRate UpperBound() const; + DataRate LowerBound() const; + void Reset(); + void OnOveruseDetected(DataRate acknowledged_rate); + bool has_estimate() const; + DataRate estimate() const; + + private: + friend class GoogCcStatePrinter; + + double deviation_estimate_kbps() const; + absl::optional estimate_kbps_; + double deviation_kbps_ = 0.4; +}; +} // namespace webrtc + +#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_LINK_CAPACITY_ESTIMATOR_H_ diff --git a/modules/congestion_controller/goog_cc/test/goog_cc_printer.cc b/modules/congestion_controller/goog_cc/test/goog_cc_printer.cc index f206125516..717f554e07 100644 --- a/modules/congestion_controller/goog_cc/test/goog_cc_printer.cc +++ b/modules/congestion_controller/goog_cc/test/goog_cc_printer.cc @@ -43,8 +43,8 @@ void GoogCcStatePrinter::PrintValues(FILE* out) { auto* trendline_estimator = reinterpret_cast(detector); fprintf(out, "%i %f %i %.6lf %.6lf %.6lf", controller_->delay_based_bwe_->rate_control_.rate_control_state_, - controller_->delay_based_bwe_->rate_control_ - .link_capacity_estimate_kbps_.value_or(NAN) * + controller_->delay_based_bwe_->rate_control_.link_capacity_ + .estimate_kbps_.value_or(NAN) * 1000 / 8, controller_->alr_detector_->alr_started_time_ms_.has_value(), trendline_estimator->prev_trend_, diff --git a/modules/remote_bitrate_estimator/BUILD.gn b/modules/remote_bitrate_estimator/BUILD.gn index acc7a3537a..77aba179d0 100644 --- a/modules/remote_bitrate_estimator/BUILD.gn +++ b/modules/remote_bitrate_estimator/BUILD.gn @@ -46,6 +46,7 @@ rtc_static_library("remote_bitrate_estimator") { "../../api/units:timestamp", "../../modules:module_api", "../../modules:module_api_public", + "../../modules/congestion_controller/goog_cc:link_capacity_estimator", "../../modules/rtp_rtcp:rtp_rtcp_format", "../../rtc_base:checks", "../../rtc_base:rtc_base_approved", diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.cc b/modules/remote_bitrate_estimator/aimd_rate_control.cc index b2ca801288..1dd87d5895 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control.cc +++ b/modules/remote_bitrate_estimator/aimd_rate_control.cc @@ -25,7 +25,6 @@ #include "system_wrappers/include/field_trial.h" namespace webrtc { - constexpr TimeDelta kDefaultRtt = TimeDelta::Millis<200>(); constexpr double kDefaultBackoffFactor = 0.85; constexpr TimeDelta kDefaultInitialBackOffInterval = TimeDelta::Millis<200>(); @@ -78,8 +77,7 @@ AimdRateControl::AimdRateControl() max_configured_bitrate_(DataRate::kbps(30000)), current_bitrate_(max_configured_bitrate_), latest_estimated_throughput_(current_bitrate_), - link_capacity_estimate_kbps_(), - var_link_capacity_estimate_kbps_(0.4), + link_capacity_(), rate_control_state_(kRcHold), time_last_bitrate_change_(Timestamp::MinusInfinity()), time_last_bitrate_decrease_(Timestamp::MinusInfinity()), @@ -254,30 +252,17 @@ DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate, return current_bitrate_; ChangeState(input, at_time); - // Calculated here because it's used in multiple places. - const double estimated_throughput_kbps = estimated_throughput.kbps(); - // Calculate the max bit rate std dev given the normalized - // variance and the current throughput bitrate. The standard deviation will - // only be used if link_capacity_estimate_kbps_ has a value. - const double std_link_capacity_kbps = - sqrt(var_link_capacity_estimate_kbps_ * - link_capacity_estimate_kbps_.value_or(0)); switch (rate_control_state_) { case kRcHold: break; case kRcIncrease: - if (link_capacity_estimate_kbps_.has_value() && - estimated_throughput_kbps > link_capacity_estimate_kbps_.value() + - 3 * std_link_capacity_kbps) { - // The link capacity appears to have changed. Forget the previous - // estimate and use multiplicative increase to quickly discover new - // capacity. - link_capacity_estimate_kbps_.reset(); - } - if (link_capacity_estimate_kbps_.has_value()) { - // The link_capacity_estimate_kbps_ is reset if the measured throughput + if (estimated_throughput > link_capacity_.UpperBound()) + link_capacity_.Reset(); + + if (link_capacity_.has_estimate()) { + // The link_capacity estimate is reset if the measured throughput // is too far from the estimate. We can therefore assume that our target // rate is reasonably close to link capacity and use additive increase. DataRate additive_increase = @@ -300,9 +285,8 @@ DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate, new_bitrate = estimated_throughput * beta_; if (new_bitrate > current_bitrate_) { // Avoid increasing the rate when over-using. - if (link_capacity_estimate_kbps_.has_value()) { - new_bitrate = - DataRate::kbps(beta_ * link_capacity_estimate_kbps_.value()); + if (link_capacity_.has_estimate()) { + new_bitrate = beta_ * link_capacity_.estimate(); } new_bitrate = std::min(new_bitrate, current_bitrate_); } @@ -319,16 +303,14 @@ DataRate AimdRateControl::ChangeBitrate(DataRate new_bitrate, last_decrease_ = current_bitrate_ - new_bitrate; } } - if (link_capacity_estimate_kbps_.has_value() && - estimated_throughput_kbps < link_capacity_estimate_kbps_.value() - - 3 * std_link_capacity_kbps) { + if (estimated_throughput < link_capacity_.LowerBound()) { // The current throughput is far from the estimated link capacity. Clear - // the estimate to allow an fast update in UpdateLinkCapacityEstimate. - link_capacity_estimate_kbps_.reset(); + // the estimate to allow an immediate update in OnOveruseDetected. + link_capacity_.Reset(); } bitrate_is_initialized_ = true; - UpdateLinkCapacityEstimate(estimated_throughput_kbps); + link_capacity_.OnOveruseDetected(estimated_throughput); // Stay on hold until the pipes are cleared. rate_control_state_ = kRcHold; time_last_bitrate_change_ = at_time; @@ -376,35 +358,6 @@ DataRate AimdRateControl::AdditiveRateIncrease(Timestamp at_time, return DataRate::bps(data_rate_increase_bps); } -void AimdRateControl::UpdateLinkCapacityEstimate( - double estimated_throughput_kbps) { - const double alpha = 0.05; - if (!link_capacity_estimate_kbps_.has_value()) { - link_capacity_estimate_kbps_ = estimated_throughput_kbps; - } else { - link_capacity_estimate_kbps_ = - (1 - alpha) * link_capacity_estimate_kbps_.value() + - alpha * estimated_throughput_kbps; - } - // Estimate the variance of the link capacity estimate and normalize the - // variance with the link capacity estimate. - const double norm = std::max(link_capacity_estimate_kbps_.value(), 1.0); - var_link_capacity_estimate_kbps_ = - (1 - alpha) * var_link_capacity_estimate_kbps_ + - alpha * - (link_capacity_estimate_kbps_.value() - estimated_throughput_kbps) * - (link_capacity_estimate_kbps_.value() - estimated_throughput_kbps) / - norm; - // 0.4 ~= 14 kbit/s at 500 kbit/s - if (var_link_capacity_estimate_kbps_ < 0.4) { - var_link_capacity_estimate_kbps_ = 0.4; - } - // 2.5 ~= 35 kbit/s at 500 kbit/s - if (var_link_capacity_estimate_kbps_ > 2.5) { - var_link_capacity_estimate_kbps_ = 2.5; - } -} - void AimdRateControl::ChangeState(const RateControlInput& input, Timestamp at_time) { switch (input.bw_state) { diff --git a/modules/remote_bitrate_estimator/aimd_rate_control.h b/modules/remote_bitrate_estimator/aimd_rate_control.h index adb959a14b..7a4fd02d25 100644 --- a/modules/remote_bitrate_estimator/aimd_rate_control.h +++ b/modules/remote_bitrate_estimator/aimd_rate_control.h @@ -14,13 +14,12 @@ #include #include "absl/types/optional.h" -#include "modules/remote_bitrate_estimator/include/bwe_defines.h" - #include "api/units/data_rate.h" #include "api/units/timestamp.h" +#include "modules/congestion_controller/goog_cc/link_capacity_estimator.h" +#include "modules/remote_bitrate_estimator/include/bwe_defines.h" namespace webrtc { - // A rate control implementation based on additive increases of // bitrate when no over-use is detected and multiplicative decreases when // over-uses are detected. When we think the available bandwidth has changes or @@ -80,15 +79,13 @@ class AimdRateControl { DataRate current_bitrate) const; DataRate AdditiveRateIncrease(Timestamp at_time, Timestamp last_time) const; void UpdateChangePeriod(Timestamp at_time); - void UpdateLinkCapacityEstimate(double estimated_throughput_kbps); void ChangeState(const RateControlInput& input, Timestamp at_time); DataRate min_configured_bitrate_; DataRate max_configured_bitrate_; DataRate current_bitrate_; DataRate latest_estimated_throughput_; - absl::optional link_capacity_estimate_kbps_; - double var_link_capacity_estimate_kbps_; + LinkCapacityEstimator link_capacity_; RateControlState rate_control_state_; Timestamp time_last_bitrate_change_; Timestamp time_last_bitrate_decrease_;