blob: 8f1a8384cf9ff00c86652b1672d64d3ded496264 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:251/*
stefan@webrtc.org9354cc92012-06-07 08:10:142 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:253 *
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
Jonas Olssona4d87372019-07-05 17:08:3311#include "rtc_base/rate_statistics.h"
12
Yves Gerey3e707812018-11-28 15:47:4913#include <cstdlib>
Stefan Holmerfb8fc532016-04-22 13:48:2314
Mirko Bonadei92ea95e2017-09-15 04:47:3115#include "test/gtest.h"
niklase@google.com470e71d2011-07-07 08:21:2516
17namespace {
18
sprang@webrtc.org37968a92013-12-03 10:31:5919using webrtc::RateStatistics;
niklase@google.com470e71d2011-07-07 08:21:2520
Stefan Holmerfb8fc532016-04-22 13:48:2321const int64_t kWindowMs = 500;
22
sprang@webrtc.org37968a92013-12-03 10:31:5923class RateStatisticsTest : public ::testing::Test {
solenberg@webrtc.orgd26457f2013-04-18 12:25:3224 protected:
Stefan Holmerfb8fc532016-04-22 13:48:2325 RateStatisticsTest() : stats_(kWindowMs, 8000) {}
sprang@webrtc.org37968a92013-12-03 10:31:5926 RateStatistics stats_;
niklase@google.com470e71d2011-07-07 08:21:2527};
28
sprang@webrtc.org37968a92013-12-03 10:31:5929TEST_F(RateStatisticsTest, TestStrictMode) {
solenberg@webrtc.orgd26457f2013-04-18 12:25:3230 int64_t now_ms = 0;
Erik Språng51e60302016-06-10 20:13:2131 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
32
33 const uint32_t kPacketSize = 1500u;
34 const uint32_t kExpectedRateBps = kPacketSize * 1000 * 8;
35
36 // Single data point is not enough for valid estimate.
37 stats_.Update(kPacketSize, now_ms++);
38 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
39
Stefan Holmerfb8fc532016-04-22 13:48:2340 // Expecting 1200 kbps since the window is initially kept small and grows as
41 // we have more data.
Erik Språng51e60302016-06-10 20:13:2142 stats_.Update(kPacketSize, now_ms);
43 EXPECT_EQ(kExpectedRateBps, *stats_.Rate(now_ms));
44
sprang@webrtc.org37968a92013-12-03 10:31:5945 stats_.Reset();
solenberg@webrtc.orgd26457f2013-04-18 12:25:3246 // Expecting 0 after init.
Erik Språng51e60302016-06-10 20:13:2147 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
48
49 const int kInterval = 10;
solenberg@webrtc.orgd26457f2013-04-18 12:25:3250 for (int i = 0; i < 100000; ++i) {
Erik Språng51e60302016-06-10 20:13:2151 if (i % kInterval == 0)
52 stats_.Update(kPacketSize, now_ms);
53
solenberg@webrtc.orgd26457f2013-04-18 12:25:3254 // Approximately 1200 kbps expected. Not exact since when packets
55 // are removed we will jump 10 ms to the next packet.
Erik Språng51e60302016-06-10 20:13:2156 if (i > kInterval) {
Danil Chapovalov0a1d1892018-06-21 09:48:2557 absl::optional<uint32_t> rate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:2158 EXPECT_TRUE(static_cast<bool>(rate));
59 uint32_t samples = i / kInterval + 1;
60 uint64_t total_bits = samples * kPacketSize * 8;
61 uint32_t rate_bps = static_cast<uint32_t>((1000 * total_bits) / (i + 1));
62 EXPECT_NEAR(rate_bps, *rate, 22000u);
solenberg@webrtc.orgd26457f2013-04-18 12:25:3263 }
64 now_ms += 1;
65 }
Stefan Holmerfb8fc532016-04-22 13:48:2366 now_ms += kWindowMs;
solenberg@webrtc.orgd26457f2013-04-18 12:25:3267 // The window is 2 seconds. If nothing has been received for that time
68 // the estimate should be 0.
Erik Språng51e60302016-06-10 20:13:2169 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
niklase@google.com470e71d2011-07-07 08:21:2570}
mikhal@webrtc.orgd89b52a2013-11-25 17:49:2871
sprang@webrtc.org37968a92013-12-03 10:31:5972TEST_F(RateStatisticsTest, IncreasingThenDecreasingBitrate) {
mikhal@webrtc.orgd89b52a2013-11-25 17:49:2873 int64_t now_ms = 0;
sprang@webrtc.org37968a92013-12-03 10:31:5974 stats_.Reset();
mikhal@webrtc.orgd89b52a2013-11-25 17:49:2875 // Expecting 0 after init.
Erik Språng51e60302016-06-10 20:13:2176 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
77
78 stats_.Update(1000, ++now_ms);
Stefan Holmerfb8fc532016-04-22 13:48:2379 const uint32_t kExpectedBitrate = 8000000;
mikhal@webrtc.orgd89b52a2013-11-25 17:49:2880 // 1000 bytes per millisecond until plateau is reached.
Stefan Holmerfb8fc532016-04-22 13:48:2381 int prev_error = kExpectedBitrate;
Danil Chapovalov0a1d1892018-06-21 09:48:2582 absl::optional<uint32_t> bitrate;
mikhal@webrtc.orgd89b52a2013-11-25 17:49:2883 while (++now_ms < 10000) {
84 stats_.Update(1000, now_ms);
Stefan Holmerfb8fc532016-04-22 13:48:2385 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:2186 EXPECT_TRUE(static_cast<bool>(bitrate));
87 int error = kExpectedBitrate - *bitrate;
Stefan Holmerfb8fc532016-04-22 13:48:2388 error = std::abs(error);
89 // Expect the estimation error to decrease as the window is extended.
90 EXPECT_LE(error, prev_error + 1);
91 prev_error = error;
mikhal@webrtc.orgd89b52a2013-11-25 17:49:2892 }
Stefan Holmerfb8fc532016-04-22 13:48:2393 // Window filled, expect to be close to 8000000.
Erik Språng51e60302016-06-10 20:13:2194 EXPECT_EQ(kExpectedBitrate, *bitrate);
Stefan Holmerfb8fc532016-04-22 13:48:2395
mikhal@webrtc.orgd89b52a2013-11-25 17:49:2896 // 1000 bytes per millisecond until 10-second mark, 8000 kbps expected.
97 while (++now_ms < 10000) {
98 stats_.Update(1000, now_ms);
sprang@webrtc.org37968a92013-12-03 10:31:5999 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:21100 EXPECT_EQ(kExpectedBitrate, *bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28101 }
Erik Språng51e60302016-06-10 20:13:21102
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28103 // Zero bytes per millisecond until 0 is reached.
104 while (++now_ms < 20000) {
105 stats_.Update(0, now_ms);
Danil Chapovalov0a1d1892018-06-21 09:48:25106 absl::optional<uint32_t> new_bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:21107 if (static_cast<bool>(new_bitrate) && *new_bitrate != *bitrate) {
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28108 // New bitrate must be lower than previous one.
Erik Språng51e60302016-06-10 20:13:21109 EXPECT_LT(*new_bitrate, *bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28110 } else {
111 // 0 kbps expected.
Erik Språng51e60302016-06-10 20:13:21112 EXPECT_EQ(0u, *new_bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28113 break;
114 }
115 bitrate = new_bitrate;
116 }
Erik Språng51e60302016-06-10 20:13:21117
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28118 // Zero bytes per millisecond until 20-second mark, 0 kbps expected.
119 while (++now_ms < 20000) {
120 stats_.Update(0, now_ms);
Erik Språng51e60302016-06-10 20:13:21121 EXPECT_EQ(0u, *stats_.Rate(now_ms));
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28122 }
123}
Stefan Holmerfb8fc532016-04-22 13:48:23124
125TEST_F(RateStatisticsTest, ResetAfterSilence) {
126 int64_t now_ms = 0;
127 stats_.Reset();
128 // Expecting 0 after init.
Erik Språng51e60302016-06-10 20:13:21129 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
130
Stefan Holmerfb8fc532016-04-22 13:48:23131 const uint32_t kExpectedBitrate = 8000000;
132 // 1000 bytes per millisecond until the window has been filled.
133 int prev_error = kExpectedBitrate;
Danil Chapovalov0a1d1892018-06-21 09:48:25134 absl::optional<uint32_t> bitrate;
Stefan Holmerfb8fc532016-04-22 13:48:23135 while (++now_ms < 10000) {
136 stats_.Update(1000, now_ms);
137 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:21138 if (bitrate) {
139 int error = kExpectedBitrate - *bitrate;
140 error = std::abs(error);
141 // Expect the estimation error to decrease as the window is extended.
142 EXPECT_LE(error, prev_error + 1);
143 prev_error = error;
144 }
Stefan Holmerfb8fc532016-04-22 13:48:23145 }
146 // Window filled, expect to be close to 8000000.
Erik Språng51e60302016-06-10 20:13:21147 EXPECT_EQ(kExpectedBitrate, *bitrate);
Stefan Holmerfb8fc532016-04-22 13:48:23148
149 now_ms += kWindowMs + 1;
Erik Språng51e60302016-06-10 20:13:21150 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
Yun Zhang4774a9f2021-11-23 09:11:20151 // Silence over window size should trigger auto reset for coming sample.
Stefan Holmerfb8fc532016-04-22 13:48:23152 stats_.Update(1000, now_ms);
Erik Språng51e60302016-06-10 20:13:21153 ++now_ms;
154 stats_.Update(1000, now_ms);
155 // We expect two samples of 1000 bytes, and that the bitrate is measured over
Yun Zhang4774a9f2021-11-23 09:11:20156 // active window instead of full window, which is now_ms - first_timestamp + 1
157 EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
Erik Språng51e60302016-06-10 20:13:21158
Yun Zhang4774a9f2021-11-23 09:11:20159 // Manual reset, add the same samples again.
Erik Språng51e60302016-06-10 20:13:21160 stats_.Reset();
161 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
162 stats_.Update(1000, now_ms);
163 ++now_ms;
164 stats_.Update(1000, now_ms);
165 // We expect two samples of 1000 bytes, and that the bitrate is measured over
166 // 2 ms (window size has been reset) i.e. 2 * 8 * 1000 / 0.002 = 8000000.
167 EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
168}
169
170TEST_F(RateStatisticsTest, HandlesChangingWindowSize) {
171 int64_t now_ms = 0;
172 stats_.Reset();
173
174 // Sanity test window size.
175 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
176 EXPECT_FALSE(stats_.SetWindowSize(kWindowMs + 1, now_ms));
177 EXPECT_FALSE(stats_.SetWindowSize(0, now_ms));
178 EXPECT_TRUE(stats_.SetWindowSize(1, now_ms));
179 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
180
181 // Fill the buffer at a rate of 1 byte / millisecond (8 kbps).
182 const int kBatchSize = 10;
183 for (int i = 0; i <= kWindowMs; i += kBatchSize)
184 stats_.Update(kBatchSize, now_ms += kBatchSize);
185 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
186
187 // Halve the window size, rate should stay the same.
188 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs / 2, now_ms));
189 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
190
191 // Double the window size again, rate should stay the same. (As the window
192 // won't actually expand until new bit and bobs fall into it.
193 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
194 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
195
196 // Fill the now empty half with bits it twice the rate.
197 for (int i = 0; i < kWindowMs / 2; i += kBatchSize)
198 stats_.Update(kBatchSize * 2, now_ms += kBatchSize);
199
200 // Rate should have increase be 50%.
201 EXPECT_EQ(static_cast<uint32_t>((8000 * 3) / 2), *stats_.Rate(now_ms));
202}
203
204TEST_F(RateStatisticsTest, RespectsWindowSizeEdges) {
205 int64_t now_ms = 0;
206 stats_.Reset();
207 // Expecting 0 after init.
208 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
209
210 // One byte per ms, using one big sample.
211 stats_.Update(kWindowMs, now_ms);
212 now_ms += kWindowMs - 2;
213 // Shouldn't work! (Only one sample, not full window size.)
214 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
215
216 // Window size should be full, and the single data point should be accepted.
217 ++now_ms;
Danil Chapovalov0a1d1892018-06-21 09:48:25218 absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:21219 EXPECT_TRUE(static_cast<bool>(bitrate));
220 EXPECT_EQ(1000 * 8u, *bitrate);
221
222 // Add another, now we have twice the bitrate.
223 stats_.Update(kWindowMs, now_ms);
224 bitrate = stats_.Rate(now_ms);
225 EXPECT_TRUE(static_cast<bool>(bitrate));
226 EXPECT_EQ(2 * 1000 * 8u, *bitrate);
227
228 // Now that first sample should drop out...
229 now_ms += 1;
230 bitrate = stats_.Rate(now_ms);
231 EXPECT_TRUE(static_cast<bool>(bitrate));
232 EXPECT_EQ(1000 * 8u, *bitrate);
233}
234
235TEST_F(RateStatisticsTest, HandlesZeroCounts) {
236 int64_t now_ms = 0;
237 stats_.Reset();
238 // Expecting 0 after init.
239 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
240
241 stats_.Update(kWindowMs, now_ms);
242 now_ms += kWindowMs - 1;
243 stats_.Update(0, now_ms);
Danil Chapovalov0a1d1892018-06-21 09:48:25244 absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:21245 EXPECT_TRUE(static_cast<bool>(bitrate));
246 EXPECT_EQ(1000 * 8u, *bitrate);
247
248 // Move window along so first data point falls out.
249 ++now_ms;
250 bitrate = stats_.Rate(now_ms);
251 EXPECT_TRUE(static_cast<bool>(bitrate));
252 EXPECT_EQ(0u, *bitrate);
253
254 // Move window so last data point falls out.
255 now_ms += kWindowMs;
256 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
257}
258
259TEST_F(RateStatisticsTest, HandlesQuietPeriods) {
260 int64_t now_ms = 0;
261 stats_.Reset();
262 // Expecting 0 after init.
263 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
264
265 stats_.Update(0, now_ms);
266 now_ms += kWindowMs - 1;
Danil Chapovalov0a1d1892018-06-21 09:48:25267 absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:21268 EXPECT_TRUE(static_cast<bool>(bitrate));
269 EXPECT_EQ(0u, *bitrate);
270
271 // Move window along so first data point falls out.
272 ++now_ms;
273 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
274
275 // Move window a long way out.
Yun Zhang4774a9f2021-11-23 09:11:20276 // This will cause an automatic reset of the window
277 // First data point won't give a valid result
Erik Språng51e60302016-06-10 20:13:21278 now_ms += 2 * kWindowMs;
279 stats_.Update(0, now_ms);
280 bitrate = stats_.Rate(now_ms);
Yun Zhang4774a9f2021-11-23 09:11:20281 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
282 // Second data point gives valid result
283 ++now_ms;
284 stats_.Update(0, now_ms);
285 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 20:13:21286 EXPECT_TRUE(static_cast<bool>(bitrate));
287 EXPECT_EQ(0u, *bitrate);
Stefan Holmerfb8fc532016-04-22 13:48:23288}
Harald Alvestranda846cef2020-01-15 13:02:12289
290TEST_F(RateStatisticsTest, HandlesBigNumbers) {
291 int64_t large_number = 0x100000000u;
292 int64_t now_ms = 0;
293 stats_.Update(large_number, now_ms++);
294 stats_.Update(large_number, now_ms);
295 EXPECT_TRUE(stats_.Rate(now_ms));
296 EXPECT_EQ(large_number * RateStatistics::kBpsScale, *stats_.Rate(now_ms));
297}
298
299TEST_F(RateStatisticsTest, HandlesTooLargeNumbers) {
300 int64_t very_large_number = std::numeric_limits<int64_t>::max();
301 int64_t now_ms = 0;
302 stats_.Update(very_large_number, now_ms++);
303 stats_.Update(very_large_number, now_ms);
304 // This should overflow the internal accumulator.
305 EXPECT_FALSE(stats_.Rate(now_ms));
306}
307
308TEST_F(RateStatisticsTest, HandlesSomewhatLargeNumbers) {
309 int64_t very_large_number = std::numeric_limits<int64_t>::max();
310 int64_t now_ms = 0;
311 stats_.Update(very_large_number / 4, now_ms++);
312 stats_.Update(very_large_number / 4, now_ms);
313 // This should generate a rate of more than int64_t max, but still
314 // accumulate less than int64_t overflow.
315 EXPECT_FALSE(stats_.Rate(now_ms));
316}
317
solenberg@webrtc.orgd26457f2013-04-18 12:25:32318} // namespace