Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(980)

Side by Side Diff: webrtc/video/stats_counter.cc

Issue 1640053003: Add class which periodically computes statistics. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2016 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/video/stats_counter.h"
12
13 #include <algorithm>
14
15 #include "webrtc/base/checks.h"
16 #include "webrtc/base/logging.h"
17 #include "webrtc/system_wrappers/include/clock.h"
18
19 namespace webrtc {
20
21 namespace {
22 // Periodic time interval for processing samples.
23 const int64_t kProcessIntervalMs = 2000;
24
25 // Limit for the maximum number of buckets to use.
26 const size_t kMaxBuckets = 250;
27 } // namespace
28
29 StatsCounter::Histogram::Stats::Stats()
30 : num_samples(0),
31 min(-1),
32 max(-1),
33 average(-1),
34 percentile10(-1),
35 percentile50(-1),
36 percentile90(-1) {}
37
38 // Histogram class.
39 StatsCounter::Histogram::Histogram(size_t bucket_count, size_t bucket_max)
40 : bucket_count_(bucket_count),
41 bucket_max_(bucket_max),
42 bucket_size1_(bucket_count == bucket_max),
stefan-webrtc 2016/01/29 15:22:46 I don't think I fully understand what this variabl
43 sum_(0) {
44 RTC_CHECK_GT(kProcessIntervalMs, 0);
45 RTC_CHECK_GT(bucket_count, 0u);
46 RTC_CHECK_GT(bucket_max, 0u);
47 RTC_CHECK_LE(bucket_count, bucket_max);
48 InitializeBuckets();
49 }
50
51 void StatsCounter::Histogram::InitializeBuckets() {
52 if (bucket_size1_) {
53 // Buckets created when needed.
54 return;
55 }
56 RTC_CHECK_LE(bucket_count_, kMaxBuckets);
57 double log_max = log(static_cast<double>(bucket_max_));
58 buckets_[0] = 0; // [0, bucket min)
59 size_t cur = 1; // bucket min
60 buckets_[cur] = 0; // [bucket min,...)
61 for (size_t i = 2; i < bucket_count_; ++i) {
62 // cur * x^(remaining buckets) = max
63 double log_cur = log(static_cast<double>(cur));
64 double log_x = (log_max - log_cur) / (bucket_count_ - i);
65 double log_next = log_cur + log_x;
stefan-webrtc 2016/01/29 15:22:46 I'm trying to follow this and I have a bit of a ha
66 size_t next = static_cast<size_t>(exp(log_next) + 0.5);
67 cur = (next > cur) ? next : (cur + 1);
68 buckets_[cur] = 0; // [cur,...)
69 }
70 RTC_DCHECK(buckets_.rbegin()->first == 1 ||
71 buckets_.rbegin()->first == bucket_max_);
72 }
73
74 void StatsCounter::Histogram::Add(int sample) {
75 sum_ += sample;
76 ++stats_.num_samples;
77 if (stats_.num_samples == 1) {
78 stats_.min = sample;
79 stats_.max = sample;
80 }
81 stats_.min = std::min(sample, stats_.min);
82 stats_.max = std::max(sample, stats_.max);
83
84 if (sample < 0)
85 sample = 0;
86
87 AddToBucket(sample);
88 }
89
90 void StatsCounter::Histogram::AddToBucket(size_t sample) {
91 if (sample > bucket_max_)
92 sample = bucket_max_;
93
94 if (bucket_size1_) {
95 if (buckets_.size() == kMaxBuckets &&
96 buckets_.find(sample) == buckets_.end()) {
97 LOG(LS_WARNING) << "Max buckets reached. Sample not added " << sample;
98 return;
99 }
100 ++buckets_[sample];
101 return;
102 }
103
104 // Find bucket.
105 RTC_DCHECK(buckets_.size() >= 2);
106 auto it = buckets_.upper_bound(sample);
107 --it;
108 it->second++;
109 }
110
111 StatsCounter::Histogram::Stats StatsCounter::Histogram::stats() {
112 Compute();
113 return stats_;
114 }
115
116 void StatsCounter::Histogram::Compute() {
117 if (stats_.num_samples == 0)
118 return;
119
120 stats_.average = (sum_ + (stats_.num_samples / 2)) / stats_.num_samples;
121
122 size_t sample10 = round(std::max(stats_.num_samples * 0.1f, 1.0f));
123 size_t sample50 = round(std::max(stats_.num_samples * 0.5f, 1.0f));
124 size_t sample90 = round(std::max(stats_.num_samples * 0.9f, 1.0f));
125
126 stats_.percentile10 = -1;
127 stats_.percentile50 = -1;
128 stats_.percentile90 = -1;
129
130 size_t samples = 0;
131 int last = 0;
132 for (const auto bucket : buckets_) {
133 int cur = static_cast<int>(bucket.first);
134 samples += bucket.second;
135 // 10th percentile.
136 if (!bucket_size1_ && stats_.percentile10 == last)
137 stats_.percentile10 += ((cur - last) / 2);
138 if (samples >= sample10 && stats_.percentile10 == -1)
139 stats_.percentile10 = cur;
140 // 50th percentile.
141 if (!bucket_size1_ && stats_.percentile50 == last)
142 stats_.percentile50 += ((cur - last) / 2);
143 if (samples >= sample50 && stats_.percentile50 == -1)
144 stats_.percentile50 = cur;
145 // 90th percentile.
146 if (!bucket_size1_ && stats_.percentile90 == last)
147 stats_.percentile90 += ((cur - last) / 2);
148 if (samples >= sample90 && stats_.percentile90 == -1)
149 stats_.percentile90 = cur;
150 last = cur;
151 }
152
153 // Limit percentiles by max (mid bucket value used).
154 if (stats_.max > 0) {
155 stats_.percentile10 = std::min(stats_.percentile10, stats_.max);
156 stats_.percentile50 = std::min(stats_.percentile50, stats_.max);
157 stats_.percentile90 = std::min(stats_.percentile90, stats_.max);
158 }
159 }
160
161 // StatsCounter class.
162 StatsCounter::StatsCounter(Clock* clock,
163 size_t bucket_count,
164 size_t bucket_max,
165 bool include_empty_intervals,
166 StatsCounterObserver* observer)
167 : sum_(0),
168 num_samples_(0),
169 last_sum_(0),
170 clock_(clock),
171 include_empty_intervals_(include_empty_intervals),
172 observer_(observer),
173 last_process_time_ms_(-1),
174 histogram_(bucket_count, bucket_max) {}
175
176 StatsCounter::Histogram::Stats StatsCounter::GetStats() {
177 return histogram_.stats();
178 }
179
180 bool StatsCounter::TimeToProcess() {
181 int64_t now = clock_->TimeInMilliseconds();
182 if (last_process_time_ms_ == -1)
183 last_process_time_ms_ = now;
184
185 int64_t diff_ms = now - last_process_time_ms_;
186 if (diff_ms < kProcessIntervalMs)
187 return false;
188
189 // Advance number of complete kProcessIntervalMs that have passed.
190 int64_t num_intervals = diff_ms / kProcessIntervalMs;
191 last_process_time_ms_ += num_intervals * kProcessIntervalMs;
192
193 // Add zero for intervals without samples.
194 if (include_empty_intervals_) {
195 for (int64_t i = 0; i < num_intervals - 1; ++i) {
196 histogram_.Add(0);
197 if (observer_)
198 observer_->OnMetricUpdated(0);
199 }
200 }
201 return true;
202 }
203
204 void StatsCounter::Set(int sample) {
205 Process();
206 ++num_samples_;
207 sum_ = sample;
208 }
209
210 void StatsCounter::Add(int sample) {
211 Process();
212 ++num_samples_;
213 sum_ += sample;
214 }
215
216 void StatsCounter::Process() {
217 if (!TimeToProcess())
218 return;
219
220 int metric;
221 if (GetMetric(&metric)) {
222 histogram_.Add(metric);
223 if (observer_)
224 observer_->OnMetricUpdated(metric);
225 }
226 last_sum_ = sum_;
227 sum_ = 0;
228 num_samples_ = 0;
229 }
230
231 // StatsCounter sub-classes.
232 AvgCounter::AvgCounter(Clock* clock,
233 size_t bucket_count,
234 size_t bucket_max,
235 StatsCounterObserver* observer)
236 : StatsCounter::StatsCounter(clock,
237 bucket_count,
238 bucket_max,
239 false, // include_empty_intervals
240 observer) {}
241
242 void AvgCounter::Add(int sample) {
243 StatsCounter::Add(sample);
244 }
245
246 bool AvgCounter::GetMetric(int* metric) const {
247 if (num_samples_ == 0)
248 return false;
249 *metric = (sum_ + (num_samples_ / 2)) / num_samples_;
250 return true;
251 }
252
253 PercentCounter::PercentCounter(Clock* clock, StatsCounterObserver* observer)
254 : StatsCounter::StatsCounter(clock,
255 101, // bucket_count
256 101, // bucket_max
257 false, // include_empty_intervals
258 observer) {}
259
260 void PercentCounter::Add(bool sample) {
261 StatsCounter::Add(sample ? 1 : 0);
262 }
263
264 bool PercentCounter::GetMetric(int* metric) const {
265 if (num_samples_ == 0)
266 return false;
267 *metric = (sum_ * 100 + (num_samples_ / 2)) / num_samples_;
268 return true;
269 }
270
271 PermilleCounter::PermilleCounter(Clock* clock,
272 size_t bucket_count,
273 StatsCounterObserver* observer)
274 : StatsCounter::StatsCounter(clock,
275 bucket_count,
276 1001, // bucket_max
277 false, // include_empty_intervals
278 observer) {}
279
280 void PermilleCounter::Add(bool sample) {
281 StatsCounter::Add(sample ? 1 : 0);
282 }
283
284 bool PermilleCounter::GetMetric(int* metric) const {
285 if (num_samples_ == 0)
286 return false;
287 *metric = (sum_ * 1000 + (num_samples_ / 2)) / num_samples_;
288 return true;
289 }
290
291 RateCounter::RateCounter(Clock* clock,
292 size_t bucket_count,
293 size_t bucket_max,
294 bool include_empty_intervals,
295 StatsCounterObserver* observer)
296 : StatsCounter::StatsCounter(clock,
297 bucket_count,
298 bucket_max,
299 include_empty_intervals,
300 observer) {}
301
302 void RateCounter::Add(int sample) {
303 StatsCounter::Add(sample);
304 }
305
306 bool RateCounter::GetMetric(int* metric) const {
307 if (num_samples_ == 0)
308 return false;
309 *metric = (sum_ * 1000 + (kProcessIntervalMs / 2)) / kProcessIntervalMs;
310 return true;
311 }
312
313 RateAccCounter::RateAccCounter(Clock* clock,
314 size_t bucket_count,
315 size_t bucket_max,
316 bool include_empty_intervals,
317 StatsCounterObserver* observer)
318 : StatsCounter::StatsCounter(clock,
319 bucket_count,
320 bucket_max,
321 include_empty_intervals,
322 observer) {}
323
324 void RateAccCounter::Set(int sample) {
325 StatsCounter::Set(sample);
326 }
327
328 bool RateAccCounter::GetMetric(int* metric) const {
329 if (num_samples_ == 0 || last_sum_ > sum_)
330 return false;
331 *metric = ((sum_ - last_sum_) * 1000 + (kProcessIntervalMs / 2)) /
332 kProcessIntervalMs;
333 return true;
334 }
335
336 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698