Webrtc delay-base-bwe代码分析(4): OveruseDetector模块

来源:互联网 发布:python 函数是对象 编辑:程序博客网 时间:2024/06/16 19:31

@(webrtc)[webrtc, congestion control]

Webrtc delay-base-bwe代码分析(4): OveruseDetector模块

0. 简介

这个模块主要是根据OveruseEstimator模块校正后的到达时间差来对链路使用状态进行评估,为有限自动状态机提供状态转换的条件,同时本模块还有GCC文档中提到的自适应阈值计算。

阈值自适应原因如下:
个人理解:
- 防止某些网络状态比较极端,使链路评估总是处于比较极端的情况。
- 由于基于RTT算法的公平性问题,在对抗基于丢包的拥塞控制算法衰减快,容易造成自身饿死,例如除了GCC外还有一条TCP流。

We show that the threshold (ti), used by the over-use detector, must be made adaptive otherwise two issues can occur: 1) the delay-based control action may have no effect when the size of the bottleneck queue along the path is not sufficiently large and 2) the GCC flow may be starved by a concurrent loss-based TCP flow.

1. 原理


公式如上,delta_T为到达时间差,k为增益系数,m(ti)为ti时刻的延迟。
增益系数是自适应的,当本次延迟值在上一轮迭代的阈值范围内时,增益系数k会进行衰减,其他时候增益系数k将会增加。
参数选择是一个可以调优的过程,这里暂不讨论,webrtc中也开辟了对应的实验性接口可供配置。

2. 代码

代码实现比较简单明了,基本就是按照上述公式进行实现:

BandwidthUsage OveruseDetector::Detect(double offset,                                       double ts_delta,                                       int num_of_deltas,                                       int64_t now_ms) {  if (num_of_deltas < 2) {    return kBwNormal;  }  const double prev_offset = prev_offset_;  prev_offset_ = offset;  // 更新delta T.  const double T = std::min(num_of_deltas, 60) * offset;  BWE_TEST_LOGGING_PLOT(1, "offset", now_ms, T);  BWE_TEST_LOGGING_PLOT(1, "threshold", now_ms, threshold_);  if (T > threshold_) {    // 过载,更新对应的过载时间,过载次数统计。    if (time_over_using_ == -1) {      // Initialize the timer. Assume that we've been      // over-using half of the time since the previous      // sample.      time_over_using_ = ts_delta / 2;    } else {      // Increment timer      time_over_using_ += ts_delta;    }    overuse_counter_++;    // 当且仅当总过载时间超过过载时间阈值,且其曲线仍成上升趋势(offset >= prev_offset),    // 进入过载状态    // 其他场景维持原状态。    // 判断具有一定容忍,防止因某些爆发式场景导致异常的过载判断影响网络吞吐量。    // 过载状态解除只有T降低至阈值之下。    if (time_over_using_ > overusing_time_threshold_ && overuse_counter_ > 1) {      if (offset >= prev_offset) {        time_over_using_ = 0;        overuse_counter_ = 0;        hypothesis_ = kBwOverusing;      }    }  }  // 清除过载相关参数  else if (T < -threshold_) {    // 低负载    time_over_using_ = -1;    overuse_counter_ = 0;    hypothesis_ = kBwUnderusing;  } else {    // 正常状态    time_over_using_ = -1;    overuse_counter_ = 0;    hypothesis_ = kBwNormal;  }  // 当过载发生时,T总是大于阈值,因此此时阈值增大。  // 当未发生过载时,T总是小于阈值,此时阈值缩小。  UpdateThreshold(T, now_ms);  return hypothesis_;}void OveruseDetector::UpdateThreshold(double modified_offset, int64_t now_ms) {  // 实验性质  if (!in_experiment_)    return;  // 初始化  if (last_update_ms_ == -1)    last_update_ms_ = now_ms;  // 修正值超过阈值可控制的最大范围,这里啥都不做,防止阈值过大。  if (fabs(modified_offset) > threshold_ + kMaxAdaptOffsetMs) {    // Avoid adapting the threshold to big latency spikes, caused e.g.,    // by a sudden capacity drop.    last_update_ms_ = now_ms;    return;  }  // 第二个公式,根据修正值的绝对值和当前阈值(即i - 1时刻)比较,计算增益系数  // 默认k_down_ = 0.00006, k_up_ = 0.004。  // 这里两个值虽然都是正的,  // 但是增长和减小的符号在第一个式子中的fabs(modified_offset) - threshold_  const double k = fabs(modified_offset) < 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;  // 阈值上下限内修正。  const double kMinThreshold = 6;  const double kMaxThreshold = 600;  threshold_ = std::min(std::max(threshold_, kMinThreshold), kMaxThreshold);  last_update_ms_ = now_ms;}

参考资料:

1 google congestion control

阅读全文
0 0
原创粉丝点击