Line data Source code
1 : /*
2 : * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "webrtc/base/rate_statistics.h"
12 :
13 : #include <algorithm>
14 :
15 : #include "webrtc/base/checks.h"
16 :
17 : namespace webrtc {
18 :
19 0 : RateStatistics::RateStatistics(int64_t window_size_ms, float scale)
20 0 : : buckets_(new Bucket[window_size_ms]()),
21 : accumulated_count_(0),
22 : num_samples_(0),
23 0 : oldest_time_(-window_size_ms),
24 : oldest_index_(0),
25 : scale_(scale),
26 : max_window_size_ms_(window_size_ms),
27 0 : current_window_size_ms_(max_window_size_ms_) {}
28 :
29 0 : RateStatistics::~RateStatistics() {}
30 :
31 0 : void RateStatistics::Reset() {
32 0 : accumulated_count_ = 0;
33 0 : num_samples_ = 0;
34 0 : oldest_time_ = -max_window_size_ms_;
35 0 : oldest_index_ = 0;
36 0 : current_window_size_ms_ = max_window_size_ms_;
37 0 : for (int64_t i = 0; i < max_window_size_ms_; i++)
38 0 : buckets_[i] = Bucket();
39 0 : }
40 :
41 0 : void RateStatistics::Update(size_t count, int64_t now_ms) {
42 0 : if (now_ms < oldest_time_) {
43 : // Too old data is ignored.
44 0 : return;
45 : }
46 :
47 0 : EraseOld(now_ms);
48 :
49 : // First ever sample, reset window to start now.
50 0 : if (!IsInitialized())
51 0 : oldest_time_ = now_ms;
52 :
53 0 : uint32_t now_offset = static_cast<uint32_t>(now_ms - oldest_time_);
54 0 : RTC_DCHECK_LT(now_offset, max_window_size_ms_);
55 0 : uint32_t index = oldest_index_ + now_offset;
56 0 : if (index >= max_window_size_ms_)
57 0 : index -= max_window_size_ms_;
58 0 : buckets_[index].sum += count;
59 0 : ++buckets_[index].samples;
60 0 : accumulated_count_ += count;
61 0 : ++num_samples_;
62 : }
63 :
64 0 : rtc::Optional<uint32_t> RateStatistics::Rate(int64_t now_ms) const {
65 : // Yeah, this const_cast ain't pretty, but the alternative is to declare most
66 : // of the members as mutable...
67 0 : const_cast<RateStatistics*>(this)->EraseOld(now_ms);
68 :
69 : // If window is a single bucket or there is only one sample in a data set that
70 : // has not grown to the full window size, treat this as rate unavailable.
71 0 : int64_t active_window_size = now_ms - oldest_time_ + 1;
72 0 : if (num_samples_ == 0 || active_window_size <= 1 ||
73 0 : (num_samples_ <= 1 && active_window_size < current_window_size_ms_)) {
74 0 : return rtc::Optional<uint32_t>();
75 : }
76 :
77 0 : float scale = scale_ / active_window_size;
78 : return rtc::Optional<uint32_t>(
79 0 : static_cast<uint32_t>(accumulated_count_ * scale + 0.5f));
80 : }
81 :
82 0 : void RateStatistics::EraseOld(int64_t now_ms) {
83 0 : if (!IsInitialized())
84 0 : return;
85 :
86 : // New oldest time that is included in data set.
87 0 : int64_t new_oldest_time = now_ms - current_window_size_ms_ + 1;
88 :
89 : // New oldest time is older than the current one, no need to cull data.
90 0 : if (new_oldest_time <= oldest_time_)
91 0 : return;
92 :
93 : // Loop over buckets and remove too old data points.
94 0 : while (num_samples_ > 0 && oldest_time_ < new_oldest_time) {
95 0 : const Bucket& oldest_bucket = buckets_[oldest_index_];
96 0 : RTC_DCHECK_GE(accumulated_count_, oldest_bucket.sum);
97 0 : RTC_DCHECK_GE(num_samples_, oldest_bucket.samples);
98 0 : accumulated_count_ -= oldest_bucket.sum;
99 0 : num_samples_ -= oldest_bucket.samples;
100 0 : buckets_[oldest_index_] = Bucket();
101 0 : if (++oldest_index_ >= max_window_size_ms_)
102 0 : oldest_index_ = 0;
103 0 : ++oldest_time_;
104 : }
105 0 : oldest_time_ = new_oldest_time;
106 : }
107 :
108 0 : bool RateStatistics::SetWindowSize(int64_t window_size_ms, int64_t now_ms) {
109 0 : if (window_size_ms <= 0 || window_size_ms > max_window_size_ms_)
110 0 : return false;
111 :
112 0 : current_window_size_ms_ = window_size_ms;
113 0 : EraseOld(now_ms);
114 0 : return true;
115 : }
116 :
117 0 : bool RateStatistics::IsInitialized() const {
118 0 : return oldest_time_ != -max_window_size_ms_;
119 : }
120 :
121 : } // namespace webrtc
|