WebRTC源码分析--RateTracker

RateTracker主要作用是求最近一段时间间隔内的平均速率,先看它的定义:

class RateTracker {
 public:
  RateTracker(int64_t bucket_milliseconds, size_t bucket_count);
  virtual ~RateTracker();

  // Computes the average rate over the most recent interval_milliseconds,
  // or if the first sample was added within this period, computes the rate
  // since the first sample was added.
  double ComputeRateForInterval(int64_t interval_milliseconds) const;

  // Computes the average rate over the rate tracker‘s recording interval
  // of bucket_milliseconds * bucket_count.
  double ComputeRate() const {
    return ComputeRateForInterval(bucket_milliseconds_ *
                                  static_cast<int64_t>(bucket_count_));
  }

  // Computes the average rate since the first sample was added to the
  // rate tracker.
  double ComputeTotalRate() const;

  // The total number of samples added.
  int64_t TotalSampleCount() const;

  // Reads the current time in order to determine the appropriate bucket for
  // these samples, and increments the count for that bucket by sample_count.
  void AddSamples(int64_t sample_count);

 protected:
  // overrideable for tests
  virtual int64_t Time() const;

 private:
  void EnsureInitialized();
  size_t NextBucketIndex(size_t bucket_index) const;

  const int64_t bucket_milliseconds_;
  const size_t bucket_count_;
  int64_t* sample_buckets_;
  size_t total_sample_count_;
  size_t current_bucket_;
  int64_t bucket_start_time_milliseconds_;
  int64_t initialization_time_milliseconds_;
};

构造函数

RateTracker::RateTracker(int64_t bucket_milliseconds, size_t bucket_count)
    : bucket_milliseconds_(bucket_milliseconds),
      bucket_count_(bucket_count),
      sample_buckets_(new in// 进行初始化
void RateTracker::EnsureInitialized() {
  if (bucket_start_time_milliseconds_ == kTimeUnset) {
    initialization_time_milliseconds_ = Time();
    bucket_start_time_milliseconds_ = initialization_time_milliseconds_;
    // 当前桶的序号
    current_bucket_ = 0;
    // We only need to initialize the first bucket because we reset buckets when
    // current_bucket_ increments.
    // 初始化第一个桶的数量
    sample_buckets_[current_bucket_] = 0;
  }
}t64_t[bucket_count + 1]),
      total_sample_count_(0u),
      bucket_start_time_milliseconds_(kTimeUnset) {
  RTC_CHECK(bucket_milliseconds > 0);
  RTC_CHECK(bucket_count > 0);
}
  • bucket_milliseconds: 表示桶的时间间隔,在RateStatistic里,桶的间隔是1ms,也就是每毫秒一个桶,而这里是bucket_milliseconds
  • bucket_count: 预设的桶的数量,也即准备使用的桶的数量是bucket_count_+1

EnsureInitialized: 初始化

void RateTracker::EnsureInitialized() {
  if (bucket_start_time_milliseconds_ == kTimeUnset) {
    initialization_time_milliseconds_ = Time();
    bucket_start_time_milliseconds_ = initialization_time_milliseconds_;
    // 当前桶的序号
    current_bucket_ = 0;
    // We only need to initialize the first bucket because we reset buckets when
    // current_bucket_ increments.
    // 初始化第一个桶的数量
    sample_buckets_[current_bucket_] = 0;
  }
}

NextBucketIndex: 下一个桶的序号

size_t RateTracker::NextBucketIndex(size_t bucket_index) const {
  return (bucket_index + 1u) % (bucket_count_ + 1u);
}

求模,这回导致形成一个循环,即桶的数量虽然是一定的,但是是循环利用的。

AddSamples: 添加sample

void RateTracker::AddSamples(int64_t sample_count) {
  RTC_DCHECK_LE(0, sample_count);
  // 确保进行初始化
  EnsureInitialized();
  int64_t current_time = Time();
  // Advance the current bucket as needed for the current time, and reset
  // bucket counts as we advance.
  // 根据当前时间,对比当前桶的起始时间bucket_start_time_milliseconds_,每一个bucket_milliseconds_间隔,就初始化一个桶
  // 在当前桶的时间范围内,就停止
  for (size_t i = 0;
       i <= bucket_count_ &&
       current_time >= bucket_start_time_milliseconds_ + bucket_milliseconds_;
       ++i) {
    bucket_start_time_milliseconds_ += bucket_milliseconds_;
    current_bucket_ = NextBucketIndex(current_bucket_);
    sample_buckets_[current_bucket_] = 0;
  }
  // Ensure that bucket_start_time_milliseconds_ is updated appropriately if
  // the entire buffer of samples has been expired.
  // // 确保bucket_start_time_milliseconds_的时间正确(有种情况就是桶的数量已达上限)
  bucket_start_time_milliseconds_ +=
      bucket_milliseconds_ *
      ((current_time - bucket_start_time_milliseconds_) / bucket_milliseconds_);
  // Add all samples in the bucket that includes the current time.
  // 更新当前桶的样本数量和总的样本数量
  sample_buckets_[current_bucket_] += sample_count;
  total_sample_count_ += sample_count;
}

ComputeTotalRate: 统计自初始化开始后的平均速率

double RateTracker::ComputeTotalRate() const {
  if (bucket_start_time_milliseconds_ == kTimeUnset) {
    return 0.0;
  }
  int64_t current_time = Time();
  if (current_time <= initialization_time_milliseconds_) {
    return 0.0;
  }
  return static_cast<double>(total_sample_count_ * 1000) /
         static_cast<double>(
             TimeDiff(current_time, initialization_time_milliseconds_));
}

ComputeRateForInterval: 给出最近interval_milliseconds的时间内的平均速率

double RateTracker::ComputeRateForInterval(
    int64_t interval_milliseconds) const {
  if (bucket_start_time_milliseconds_ == kTimeUnset) {
    return 0.0;
  }
  int64_t current_time = Time();
  // Calculate which buckets to sum up given the current time.  If the time
  // has passed to a new bucket then we have to skip some of the oldest buckets.
  // 时间间隔限制在当前所有桶的范围,已经被覆盖的不能包含在内
  int64_t available_interval_milliseconds =
      std::min(interval_milliseconds,
               bucket_milliseconds_ * static_cast<int64_t>(bucket_count_));
  // number of old buckets (i.e. after the current bucket in the ring buffer)
  // that are expired given our current time interval.
  size_t buckets_to_skip;
  // Number of milliseconds of the first bucket that are not a portion of the
  // current interval.
  int64_t milliseconds_to_skip;
  // 判断发生了桶覆盖的情况,也即超过当前桶的表示范围
  if (current_time >
      initialization_time_milliseconds_ + available_interval_milliseconds) {
    //需要跳过的时间
    int64_t time_to_skip =
        current_time - bucket_start_time_milliseconds_ +
        static_cast<int64_t>(bucket_count_) * bucket_milliseconds_ -
        available_interval_milliseconds;
    //需要跳过的桶数量
    buckets_to_skip = time_to_skip / bucket_milliseconds_;
    //桶内时间偏移
    milliseconds_to_skip = time_to_skip % bucket_milliseconds_;
  } else {
    buckets_to_skip = bucket_count_ - current_bucket_;
    milliseconds_to_skip = 0;
    available_interval_milliseconds =
        TimeDiff(current_time, initialization_time_milliseconds_);
    // 连一个桶的时间都不到
    // Let one bucket interval pass after initialization before reporting.
    if (available_interval_milliseconds < bucket_milliseconds_) {
      return 0.0;
    }
  }
  // If we‘re skipping all buckets that means that there have been no samples
  // within the sampling interval so report 0.
  if (buckets_to_skip > bucket_count_ || available_interval_milliseconds == 0) {
    return 0.0;
  }
  size_t start_bucket = NextBucketIndex(current_bucket_ + buckets_to_skip);
  // Only count a portion of the first bucket according to how much of the
  // first bucket is within the current interval.
  int64_t total_samples = ((sample_buckets_[start_bucket] *
                            (bucket_milliseconds_ - milliseconds_to_skip)) +
                           (bucket_milliseconds_ >> 1)) /
                          bucket_milliseconds_;
  // All other buckets in the interval are counted in their entirety.
  for (size_t i = NextBucketIndex(start_bucket);
       i != NextBucketIndex(current_bucket_); i = NextBucketIndex(i)) {
    total_samples += sample_buckets_[i];
  }
  // Convert to samples per second.
  return static_cast<double>(total_samples * 1000) /
         static_cast<double>(available_interval_milliseconds);
}

看的还是有些糊涂,大致意思就是求最近一段时间间隔内的平均速率(当间隔超过所有桶能表示的范围,就是所有桶周期内的平均速率)。在webrtc中主要用来进行帧率统计等工作。

WebRTC源码分析--RateTracker

上一篇:ajax 遮罩层总是在执行完后显示或显示不出来


下一篇:Asp.netcore 托管模型- 进程内托管和进程外托管(inprocess out OutOfProcess)