xref: /aosp_15_r20/external/webrtc/rtc_base/rate_statistics_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2012 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 "rtc_base/rate_statistics.h"
12 
13 #include <cstdlib>
14 
15 #include "test/gtest.h"
16 
17 namespace {
18 
19 using webrtc::RateStatistics;
20 
21 const int64_t kWindowMs = 500;
22 
23 class RateStatisticsTest : public ::testing::Test {
24  protected:
RateStatisticsTest()25   RateStatisticsTest() : stats_(kWindowMs, 8000) {}
26   RateStatistics stats_;
27 };
28 
TEST_F(RateStatisticsTest,TestStrictMode)29 TEST_F(RateStatisticsTest, TestStrictMode) {
30   int64_t now_ms = 0;
31   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 
40   // Expecting 1200 kbps since the window is initially kept small and grows as
41   // we have more data.
42   stats_.Update(kPacketSize, now_ms);
43   EXPECT_EQ(kExpectedRateBps, *stats_.Rate(now_ms));
44 
45   stats_.Reset();
46   // Expecting 0 after init.
47   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
48 
49   const int kInterval = 10;
50   for (int i = 0; i < 100000; ++i) {
51     if (i % kInterval == 0)
52       stats_.Update(kPacketSize, now_ms);
53 
54     // Approximately 1200 kbps expected. Not exact since when packets
55     // are removed we will jump 10 ms to the next packet.
56     if (i > kInterval) {
57       absl::optional<uint32_t> rate = stats_.Rate(now_ms);
58       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);
63     }
64     now_ms += 1;
65   }
66   now_ms += kWindowMs;
67   // The window is 2 seconds. If nothing has been received for that time
68   // the estimate should be 0.
69   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
70 }
71 
TEST_F(RateStatisticsTest,IncreasingThenDecreasingBitrate)72 TEST_F(RateStatisticsTest, IncreasingThenDecreasingBitrate) {
73   int64_t now_ms = 0;
74   stats_.Reset();
75   // Expecting 0 after init.
76   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
77 
78   stats_.Update(1000, ++now_ms);
79   const uint32_t kExpectedBitrate = 8000000;
80   // 1000 bytes per millisecond until plateau is reached.
81   int prev_error = kExpectedBitrate;
82   absl::optional<uint32_t> bitrate;
83   while (++now_ms < 10000) {
84     stats_.Update(1000, now_ms);
85     bitrate = stats_.Rate(now_ms);
86     EXPECT_TRUE(static_cast<bool>(bitrate));
87     int error = kExpectedBitrate - *bitrate;
88     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;
92   }
93   // Window filled, expect to be close to 8000000.
94   EXPECT_EQ(kExpectedBitrate, *bitrate);
95 
96   // 1000 bytes per millisecond until 10-second mark, 8000 kbps expected.
97   while (++now_ms < 10000) {
98     stats_.Update(1000, now_ms);
99     bitrate = stats_.Rate(now_ms);
100     EXPECT_EQ(kExpectedBitrate, *bitrate);
101   }
102 
103   // Zero bytes per millisecond until 0 is reached.
104   while (++now_ms < 20000) {
105     stats_.Update(0, now_ms);
106     absl::optional<uint32_t> new_bitrate = stats_.Rate(now_ms);
107     if (static_cast<bool>(new_bitrate) && *new_bitrate != *bitrate) {
108       // New bitrate must be lower than previous one.
109       EXPECT_LT(*new_bitrate, *bitrate);
110     } else {
111       // 0 kbps expected.
112       EXPECT_EQ(0u, *new_bitrate);
113       break;
114     }
115     bitrate = new_bitrate;
116   }
117 
118   // Zero bytes per millisecond until 20-second mark, 0 kbps expected.
119   while (++now_ms < 20000) {
120     stats_.Update(0, now_ms);
121     EXPECT_EQ(0u, *stats_.Rate(now_ms));
122   }
123 }
124 
TEST_F(RateStatisticsTest,ResetAfterSilence)125 TEST_F(RateStatisticsTest, ResetAfterSilence) {
126   int64_t now_ms = 0;
127   stats_.Reset();
128   // Expecting 0 after init.
129   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
130 
131   const uint32_t kExpectedBitrate = 8000000;
132   // 1000 bytes per millisecond until the window has been filled.
133   int prev_error = kExpectedBitrate;
134   absl::optional<uint32_t> bitrate;
135   while (++now_ms < 10000) {
136     stats_.Update(1000, now_ms);
137     bitrate = stats_.Rate(now_ms);
138     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     }
145   }
146   // Window filled, expect to be close to 8000000.
147   EXPECT_EQ(kExpectedBitrate, *bitrate);
148 
149   now_ms += kWindowMs + 1;
150   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
151   // Silence over window size should trigger auto reset for coming sample.
152   stats_.Update(1000, now_ms);
153   ++now_ms;
154   stats_.Update(1000, now_ms);
155   // We expect two samples of 1000 bytes, and that the bitrate is measured over
156   // active window instead of full window, which is now_ms - first_timestamp + 1
157   EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
158 
159   // Manual reset, add the same samples again.
160   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 
TEST_F(RateStatisticsTest,HandlesChangingWindowSize)170 TEST_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 
TEST_F(RateStatisticsTest,RespectsWindowSizeEdges)204 TEST_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;
218   absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
219   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 
TEST_F(RateStatisticsTest,HandlesZeroCounts)235 TEST_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);
244   absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
245   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 
TEST_F(RateStatisticsTest,HandlesQuietPeriods)259 TEST_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;
267   absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
268   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.
276   // This will cause an automatic reset of the window
277   // First data point won't give a valid result
278   now_ms += 2 * kWindowMs;
279   stats_.Update(0, now_ms);
280   bitrate = stats_.Rate(now_ms);
281   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);
286   EXPECT_TRUE(static_cast<bool>(bitrate));
287   EXPECT_EQ(0u, *bitrate);
288 }
289 
TEST_F(RateStatisticsTest,HandlesBigNumbers)290 TEST_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 
TEST_F(RateStatisticsTest,HandlesTooLargeNumbers)299 TEST_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 
TEST_F(RateStatisticsTest,HandlesSomewhatLargeNumbers)308 TEST_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 
318 }  // namespace
319