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

Side by Side Diff: webrtc/video/stats_counter_unittest.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 "testing/gtest/include/gtest/gtest.h"
14
15 #include "webrtc/system_wrappers/include/clock.h"
16
17 namespace webrtc {
18 namespace {
19 const int kProcessIntervalMs = 2000;
20
21 class AvgEncodeTimeMsObserver : public StatsCounterObserver {
22 public:
23 AvgEncodeTimeMsObserver() : num_calls_(0), last_sample_(-1) {}
24 void OnMetricUpdated(int sample) override {
25 // RTC_HISTOGRAM_COUNTS_1000("WebRTC.Video.AvgEncodeTimeMs", sample);
26 ++num_calls_;
27 last_sample_ = sample;
28 }
29 int num_calls_;
30 int last_sample_;
31 };
32 } // namespace
33
34 class StatsCounterTest : public ::testing::Test {
35 protected:
36 StatsCounterTest() : clock_(1234) {}
37
38 void AddSampleAndAdvance(int sample, int interval_ms, AvgCounter* counter) {
39 counter->Add(sample);
40 clock_.AdvanceTimeMilliseconds(interval_ms);
41 }
42
43 void SetSampleAndAdvance(int sample,
44 int interval_ms,
45 RateAccCounter* counter) {
46 counter->Set(sample);
47 clock_.AdvanceTimeMilliseconds(interval_ms);
48 }
49
50 void VerifyStatsIsNotSet(const StatsCounter::Histogram::Stats& stats) {
51 EXPECT_EQ(0, stats.num_samples);
52 EXPECT_EQ(-1, stats.min);
53 EXPECT_EQ(-1, stats.max);
54 EXPECT_EQ(-1, stats.average);
55 EXPECT_EQ(-1, stats.percentile10);
56 EXPECT_EQ(-1, stats.percentile50);
57 EXPECT_EQ(-1, stats.percentile90);
58 }
59
60 SimulatedClock clock_;
61 };
62
63 TEST_F(StatsCounterTest, NoSamples) {
64 AvgCounter counter(&clock_, 10, 10, nullptr);
65 StatsCounter::Histogram::Stats stats = counter.GetStats();
66 VerifyStatsIsNotSet(stats);
67 }
68
69 TEST_F(StatsCounterTest, TestMetric_AvgCounter) {
70 AvgCounter counter(&clock_, 50, 50, nullptr);
71 counter.Add(4);
72 counter.Add(8);
73 counter.Add(9);
74 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs);
75 // Trigger process (sample included in next interval).
76 counter.Add(111);
77 StatsCounter::Histogram::Stats stats = counter.GetStats();
78 // [7:1] metric: average per interval
79 EXPECT_EQ(1, stats.num_samples);
80 EXPECT_EQ(7, stats.min);
81 EXPECT_EQ(7, stats.max);
82 EXPECT_EQ(7, stats.average);
83 }
84
85 TEST_F(StatsCounterTest, TestMetric_PercentCounter) {
86 PercentCounter counter(&clock_, nullptr);
87 counter.Add(true);
88 counter.Add(false);
89 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs);
90 // Trigger process (sample included in next interval).
91 counter.Add(false);
92 StatsCounter::Histogram::Stats stats = counter.GetStats();
93 // [50:1] metric: percentage per interval
94 EXPECT_EQ(1, stats.num_samples);
95 EXPECT_EQ(50, stats.min);
96 EXPECT_EQ(50, stats.max);
97 }
98
99 TEST_F(StatsCounterTest, TestMetric_PermilleCounter) {
100 PermilleCounter counter(&clock_, 1001, nullptr);
101 counter.Add(true);
102 counter.Add(false);
103 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs);
104 // Trigger process (sample included in next interval).
105 counter.Add(false);
106 StatsCounter::Histogram::Stats stats = counter.GetStats();
107 // [500:1] metric: permille per interval
108 EXPECT_EQ(1, stats.num_samples);
109 EXPECT_EQ(500, stats.min);
110 EXPECT_EQ(500, stats.max);
111 }
112
113 TEST_F(StatsCounterTest, TestMetric_RateCounter) {
114 RateCounter counter(&clock_, 1000, 1000, true, nullptr);
115 counter.Add(186);
116 counter.Add(350);
117 counter.Add(22);
118 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs);
119 // Trigger process (sample included in next interval).
120 counter.Add(111);
121 StatsCounter::Histogram::Stats stats = counter.GetStats();
122 // [279:1] metric: rate per interval, (186+350+22)/2sec = 279 samples/sec
123 EXPECT_EQ(1, stats.num_samples);
124 EXPECT_EQ(279, stats.min);
125 EXPECT_EQ(279, stats.max);
126 }
127
128 TEST_F(StatsCounterTest, TestMetric_RateAccCounter) {
129 RateAccCounter counter(&clock_, 1000, 1000, true, nullptr);
130 counter.Set(175);
131 counter.Set(188);
132 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs);
133 // Trigger process (sample included in next interval).
134 counter.Set(192);
135 StatsCounter::Histogram::Stats stats = counter.GetStats();
136 // [94:1] metric: rate per interval, (188-0)/2sec = 94 samples/sec
137 EXPECT_EQ(1, stats.num_samples);
138 EXPECT_EQ(94, stats.min);
139 EXPECT_EQ(94, stats.max);
140 }
141
142 TEST_F(StatsCounterTest, TestRegisterObserver) {
143 AvgEncodeTimeMsObserver* observer = new AvgEncodeTimeMsObserver();
144 const int kSample = 22;
145 AvgCounter counter(&clock_, 50, 50, observer);
146 AddSampleAndAdvance(kSample, kProcessIntervalMs, &counter);
147 // Trigger process (sample included in next interval).
148 counter.Add(111);
149 EXPECT_EQ(1, observer->num_calls_);
150 EXPECT_EQ(kSample, observer->last_sample_);
151 }
152
153 TEST_F(StatsCounterTest, VerifyProcessInterval) {
154 AvgCounter counter(&clock_, 10, 10, nullptr);
155 counter.Add(4);
156 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs - 1);
157 // Try trigger process (interval has not passed).
158 counter.Add(8);
159 StatsCounter::Histogram::Stats stats = counter.GetStats();
160 VerifyStatsIsNotSet(stats);
161 // Make process interval pass.
162 clock_.AdvanceTimeMilliseconds(1);
163 // Trigger process (sample included in next interval).
164 counter.Add(111);
165 stats = counter.GetStats();
166 // [6:1]
167 EXPECT_EQ(1, stats.num_samples);
168 EXPECT_EQ(6, stats.min);
169 EXPECT_EQ(6, stats.max);
170 }
171
172 TEST_F(StatsCounterTest, TestHistogramUnderflow) {
173 const int kMin = 0;
174 const int kMax = 100;
175 const int kSample = -1;
176 // 8 buckets: [0-1),[1-2),[2-4),[4-9),[9-20),[20-45),[45-100),[100-inf)
177 AvgCounter counter(&clock_, 8, kMax, nullptr);
178 AddSampleAndAdvance(kSample, kProcessIntervalMs, &counter);
179 // Trigger process (sample included in next interval).
180 counter.Add(111);
181 StatsCounter::Histogram::Stats stats = counter.GetStats();
182 // [0:1],[1:0],[2:0],[4:0],[9:0],[20:0],[45:0],[100:0]
183 EXPECT_EQ(1, stats.num_samples);
184 EXPECT_EQ(kSample, stats.min);
185 EXPECT_EQ(kSample, stats.max);
186 EXPECT_EQ(kSample, stats.average);
187 EXPECT_EQ(kMin, stats.percentile10);
188 EXPECT_EQ(kMin, stats.percentile50);
189 EXPECT_EQ(kMin, stats.percentile90);
190 }
191
192 TEST_F(StatsCounterTest, TestHistogramOverflow) {
193 const int kMax = 100;
194 const int kSample = kMax + 1;
195 // 8 buckets: [0-1),[1-2),[2-4),[4-9),[9-20),[20-45),[45-100),[100-inf)
196 AvgCounter counter(&clock_, 8, kMax, nullptr);
197 AddSampleAndAdvance(kSample, kProcessIntervalMs, &counter);
198 // Trigger process (sample included in next interval).
199 counter.Add(111);
200 StatsCounter::Histogram::Stats stats = counter.GetStats();
201 // [0:0],[1:0],[2:0],[4:0],[9:0],[20:0],[45:0],[100:1]
202 EXPECT_EQ(1, stats.num_samples);
203 EXPECT_EQ(kSample, stats.min);
204 EXPECT_EQ(kSample, stats.max);
205 EXPECT_EQ(kSample, stats.average);
206 EXPECT_EQ(kMax, stats.percentile10);
207 EXPECT_EQ(kMax, stats.percentile50);
208 EXPECT_EQ(kMax, stats.percentile90);
209 }
210
211 TEST_F(StatsCounterTest, TestStats_LinearBuckets) {
212 AvgCounter counter(&clock_, 100, 100, nullptr);
213 const int kSample1 = 1;
214 const int kSample2 = 4;
215 const int kSample3 = 8;
216 const int kSample4 = kSample3;
217 const int kSample5 = 50;
218 AddSampleAndAdvance(kSample1, kProcessIntervalMs, &counter);
219 AddSampleAndAdvance(kSample2, kProcessIntervalMs, &counter);
220 AddSampleAndAdvance(kSample3, kProcessIntervalMs, &counter);
221 AddSampleAndAdvance(kSample4, kProcessIntervalMs, &counter);
222 AddSampleAndAdvance(kSample5, kProcessIntervalMs, &counter);
223 // Trigger process (sample included in next interval).
224 counter.Add(111);
225 StatsCounter::Histogram::Stats stats = counter.GetStats();
226 // [1:1],[4:1],[8:2],[50:1]
227 EXPECT_EQ(5, stats.num_samples);
228 EXPECT_EQ(kSample1, stats.min);
229 EXPECT_EQ(kSample5, stats.max);
230 EXPECT_EQ(14, stats.average);
231 EXPECT_EQ(kSample1, stats.percentile10);
232 EXPECT_EQ(kSample3, stats.percentile50);
233 EXPECT_EQ(kSample5, stats.percentile90);
234 }
235
236 TEST_F(StatsCounterTest, TestStats_ExponentialBuckets) {
237 AvgCounter counter(&clock_, 10, 50, nullptr);
238 const int kSample1 = 1;
239 const int kSample2 = 4;
240 const int kSample3 = 9;
241 const int kSample4 = kSample3;
242 const int kSample5 = 50;
243 AddSampleAndAdvance(kSample1, kProcessIntervalMs, &counter);
244 AddSampleAndAdvance(kSample2, kProcessIntervalMs, &counter);
245 AddSampleAndAdvance(kSample3, kProcessIntervalMs, &counter);
246 AddSampleAndAdvance(kSample4, kProcessIntervalMs, &counter);
247 AddSampleAndAdvance(kSample5, kProcessIntervalMs, &counter);
248 // Trigger process (sample included in next interval).
249 counter.Add(111);
250 StatsCounter::Histogram::Stats stats = counter.GetStats();
251 // [0:0],[1:1],[2:0],[3:1],[5:0],[8:2],[13:0],[20:0],[32:0],[50:1]
252 EXPECT_EQ(5, stats.num_samples);
253 EXPECT_EQ(kSample1, stats.min);
254 EXPECT_EQ(kSample5, stats.max);
255 EXPECT_EQ(15, stats.average);
256 EXPECT_EQ(kSample1, stats.percentile10);
257 EXPECT_EQ(kSample3 + 1, stats.percentile50); // Mid bin size used.
258 EXPECT_EQ(kSample5, stats.percentile90);
259 }
260
261 TEST_F(StatsCounterTest, TestGetStatsTwice) {
262 const int kSample1 = 4;
263 const int kSample2 = 7;
264 AvgCounter counter(&clock_, 20, 50, nullptr);
265 AddSampleAndAdvance(kSample1, kProcessIntervalMs, &counter);
266 // Trigger process (sample included in next interval).
267 counter.Add(kSample2);
268 StatsCounter::Histogram::Stats stats = counter.GetStats();
269 // [0:0],[1:0],[2:0],[3:0],[4:1],[5:0],[6:0],[7:0],[8:0],[9:0],...
270 EXPECT_EQ(1, stats.num_samples);
271 EXPECT_EQ(kSample1, stats.min);
272 EXPECT_EQ(kSample1, stats.max);
273 // Trigger process (sample included in next interval).
274 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs);
275 counter.Add(111);
276 stats = counter.GetStats();
277 // [0:0],[1:0],[2:0],[3:0],[4:1],[5:0],[6:0],[7:1],[8:0],[9:0],...
278 EXPECT_EQ(2, stats.num_samples);
279 EXPECT_EQ(kSample1, stats.min);
280 EXPECT_EQ(kSample2, stats.max);
281 EXPECT_EQ(6, stats.average);
282 EXPECT_EQ(kSample1, stats.percentile10);
283 EXPECT_EQ(kSample1, stats.percentile50);
284 EXPECT_EQ(kSample2, stats.percentile90);
285 }
286
287 TEST_F(StatsCounterTest, TestRateAccCounter) {
288 const int kSample1 = 200; // 200 / 2 sec
289 const int kSample2 = 800; // 600 / 2 sec
290 const int kSample3 = 1800; // 1000 / 2 sec
291 RateAccCounter counter(&clock_, 1000, 1000, true, nullptr);
292 SetSampleAndAdvance(kSample1, kProcessIntervalMs, &counter);
293 SetSampleAndAdvance(kSample2, kProcessIntervalMs, &counter);
294 SetSampleAndAdvance(kSample3, kProcessIntervalMs, &counter);
295 // Trigger process (sample included in next interval).
296 counter.Set(2000);
297 StatsCounter::Histogram::Stats stats = counter.GetStats();
298 // [100:1],[300:1],[500:1]
299 EXPECT_EQ(3, stats.num_samples);
300 EXPECT_EQ(100, stats.min);
301 EXPECT_EQ(500, stats.max);
302 EXPECT_EQ(300, stats.average);
303 }
304
305 TEST_F(StatsCounterTest, TestRateAccCounter_NegativeRateIgnored) {
306 const int kSample1 = 200; // 200 / 2 sec
307 const int kSample2 = 100; // -100 / 2 sec - negative ignored
308 const int kSample3 = 700; // 600 / 2 sec
309 RateAccCounter counter(&clock_, 1000, 1000, true, nullptr);
310 SetSampleAndAdvance(kSample1, kProcessIntervalMs, &counter);
311 SetSampleAndAdvance(kSample2, kProcessIntervalMs, &counter);
312 SetSampleAndAdvance(kSample3, kProcessIntervalMs, &counter);
313 // Trigger process (sample included in next interval).
314 counter.Set(2000);
315 StatsCounter::Histogram::Stats stats = counter.GetStats();
316 // [100:1],[300:1]
317 EXPECT_EQ(2, stats.num_samples);
318 EXPECT_EQ(100, stats.min);
319 EXPECT_EQ(300, stats.max);
320 EXPECT_EQ(200, stats.average);
321 }
322
323 TEST_F(StatsCounterTest, IntervalsWithoutSamplesIgnored_AvgCounter) {
324 AvgCounter counter(&clock_, 10, 10, nullptr);
325 AddSampleAndAdvance(6, kProcessIntervalMs * 4 - 1, &counter);
326 // Trigger process (sample included in next interval).
327 counter.Add(8);
328 StatsCounter::Histogram::Stats stats = counter.GetStats();
329 // [6:1], two intervals without samples passed.
330 EXPECT_EQ(1, stats.num_samples);
331 EXPECT_EQ(6, stats.min);
332 EXPECT_EQ(6, stats.max);
333 // Make last interval pass.
334 clock_.AdvanceTimeMilliseconds(1);
335 counter.Add(111); // Trigger process (sample included in next interval).
336 stats = counter.GetStats();
337 // [6:1],[8:1]
338 EXPECT_EQ(2, stats.num_samples);
339 EXPECT_EQ(6, stats.min);
340 EXPECT_EQ(8, stats.max);
341 }
342
343 TEST_F(StatsCounterTest, IntervalsWithoutSamplesIgnored_RateCounter) {
344 const int kSample1 = 50; // 50 / 2 sec
345 const int kSample2 = 20; // 20 / 2 sec
346 RateCounter counter(&clock_, 1000, 1000, false, nullptr);
347 counter.Add(kSample1);
348 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs * 4 - 1);
349 // Trigger process (sample included in next interval).
350 counter.Add(kSample2);
351 StatsCounter::Histogram::Stats stats = counter.GetStats();
352 // [25:1], two intervals without samples passed.
353 EXPECT_EQ(1, stats.num_samples);
354 EXPECT_EQ(25, stats.min);
355 EXPECT_EQ(25, stats.max);
356 // Make last interval pass.
357 clock_.AdvanceTimeMilliseconds(1);
358 counter.Add(111); // Trigger process (sample included in next interval).
359 stats = counter.GetStats();
360 // [10:1],[25:1]
361 EXPECT_EQ(2, stats.num_samples);
362 EXPECT_EQ(10, stats.min);
363 EXPECT_EQ(25, stats.max);
364 }
365
366 TEST_F(StatsCounterTest, RateCounter_IntervalsWithoutSamplesIncluded) {
367 const int kSample1 = 50; // 50 / 2 sec
368 const int kSample2 = 20; // 20 / 2 sec
369 RateCounter counter(&clock_, 1000, 1000, true, nullptr);
370 counter.Add(kSample1);
371 clock_.AdvanceTimeMilliseconds(kProcessIntervalMs * 3 - 1);
372 // Trigger process (sample included in next interval).
373 counter.Add(kSample2);
374 StatsCounter::Histogram::Stats stats = counter.GetStats();
375 // [0:1],[25:1], one interval without samples passed.
376 EXPECT_EQ(2, stats.num_samples);
377 EXPECT_EQ(0, stats.min);
378 EXPECT_EQ(25, stats.max);
379 // Make last interval pass.
380 clock_.AdvanceTimeMilliseconds(1);
381 counter.Add(111); // Trigger process (sample included in next interval).
382 stats = counter.GetStats();
383 // [0:1],[10:1],[25:1]
384 EXPECT_EQ(3, stats.num_samples);
385 EXPECT_EQ(0, stats.min);
386 EXPECT_EQ(25, stats.max);
387 EXPECT_EQ(10, stats.percentile50);
388 }
389
390 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698