• 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中主要用来进行帧率统计等工作。

  • 相关阅读:
    topcoder srm 320 div1
    topcoder srm 325 div1
    topcoder srm 330 div1
    topcoder srm 335 div1
    topcoder srm 340 div1
    topcoder srm 300 div1
    topcoder srm 305 div1
    topcoder srm 310 div1
    topcoder srm 315 div1
    如何统计iOS产品不同渠道的下载量?
  • 原文地址:https://www.cnblogs.com/xl2432/p/14088791.html
Copyright © 2020-2023  润新知