zoukankan      html  css  js  c++  java
  • 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中主要用来进行帧率统计等工作。

  • 相关阅读:
    Spring AOP总结(三)
    Spring AOP源码解析(二)
    java9新特性
    BeanFactory和ApplicationContext的区别总结
    Elasticsearch7.X为什么移除类型(type)
    elasticsearch性能优化(二)
    elasticsearch性能优化(一)
    elasticsearch的master选举机制
    自动化构建和部署应用系统平台
    关系型数据库之mysql-01
  • 原文地址:https://www.cnblogs.com/xl2432/p/14088791.html
Copyright © 2011-2022 走看看