blob: 9dd82327ba29707428627d91d276a5045f3c71f5 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
stefan@webrtc.org9354cc92012-06-07 08:10:14 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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 19:08:33 +020011#include "rtc_base/rate_statistics.h"
12
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <cstdlib>
Stefan Holmerfb8fc532016-04-22 15:48:23 +020014
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020015#include "test/gtest.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000016
17namespace {
18
sprang@webrtc.org37968a92013-12-03 10:31:59 +000019using webrtc::RateStatistics;
niklase@google.com470e71d2011-07-07 08:21:25 +000020
Stefan Holmerfb8fc532016-04-22 15:48:23 +020021const int64_t kWindowMs = 500;
22
sprang@webrtc.org37968a92013-12-03 10:31:59 +000023class RateStatisticsTest : public ::testing::Test {
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000024 protected:
Stefan Holmerfb8fc532016-04-22 15:48:23 +020025 RateStatisticsTest() : stats_(kWindowMs, 8000) {}
sprang@webrtc.org37968a92013-12-03 10:31:59 +000026 RateStatistics stats_;
niklase@google.com470e71d2011-07-07 08:21:25 +000027};
28
sprang@webrtc.org37968a92013-12-03 10:31:59 +000029TEST_F(RateStatisticsTest, TestStrictMode) {
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000030 int64_t now_ms = 0;
Erik Språng51e60302016-06-10 22:13:21 +020031 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 15:48:23 +020040 // Expecting 1200 kbps since the window is initially kept small and grows as
41 // we have more data.
Erik Språng51e60302016-06-10 22:13:21 +020042 stats_.Update(kPacketSize, now_ms);
43 EXPECT_EQ(kExpectedRateBps, *stats_.Rate(now_ms));
44
sprang@webrtc.org37968a92013-12-03 10:31:59 +000045 stats_.Reset();
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000046 // Expecting 0 after init.
Erik Språng51e60302016-06-10 22:13:21 +020047 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
48
49 const int kInterval = 10;
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000050 for (int i = 0; i < 100000; ++i) {
Erik Språng51e60302016-06-10 22:13:21 +020051 if (i % kInterval == 0)
52 stats_.Update(kPacketSize, now_ms);
53
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000054 // 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 22:13:21 +020056 if (i > kInterval) {
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020057 absl::optional<uint32_t> rate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +020058 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:32 +000063 }
64 now_ms += 1;
65 }
Stefan Holmerfb8fc532016-04-22 15:48:23 +020066 now_ms += kWindowMs;
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +000067 // The window is 2 seconds. If nothing has been received for that time
68 // the estimate should be 0.
Erik Språng51e60302016-06-10 22:13:21 +020069 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
niklase@google.com470e71d2011-07-07 08:21:25 +000070}
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000071
sprang@webrtc.org37968a92013-12-03 10:31:59 +000072TEST_F(RateStatisticsTest, IncreasingThenDecreasingBitrate) {
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000073 int64_t now_ms = 0;
sprang@webrtc.org37968a92013-12-03 10:31:59 +000074 stats_.Reset();
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000075 // Expecting 0 after init.
Erik Språng51e60302016-06-10 22:13:21 +020076 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
77
78 stats_.Update(1000, ++now_ms);
Stefan Holmerfb8fc532016-04-22 15:48:23 +020079 const uint32_t kExpectedBitrate = 8000000;
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000080 // 1000 bytes per millisecond until plateau is reached.
Stefan Holmerfb8fc532016-04-22 15:48:23 +020081 int prev_error = kExpectedBitrate;
Danil Chapovalov0a1d1892018-06-21 11:48:25 +020082 absl::optional<uint32_t> bitrate;
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000083 while (++now_ms < 10000) {
84 stats_.Update(1000, now_ms);
Stefan Holmerfb8fc532016-04-22 15:48:23 +020085 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +020086 EXPECT_TRUE(static_cast<bool>(bitrate));
87 int error = kExpectedBitrate - *bitrate;
Stefan Holmerfb8fc532016-04-22 15:48:23 +020088 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:28 +000092 }
Stefan Holmerfb8fc532016-04-22 15:48:23 +020093 // Window filled, expect to be close to 8000000.
Erik Språng51e60302016-06-10 22:13:21 +020094 EXPECT_EQ(kExpectedBitrate, *bitrate);
Stefan Holmerfb8fc532016-04-22 15:48:23 +020095
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +000096 // 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:59 +000099 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200100 EXPECT_EQ(kExpectedBitrate, *bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000101 }
Erik Språng51e60302016-06-10 22:13:21 +0200102
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000103 // Zero bytes per millisecond until 0 is reached.
104 while (++now_ms < 20000) {
105 stats_.Update(0, now_ms);
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200106 absl::optional<uint32_t> new_bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200107 if (static_cast<bool>(new_bitrate) && *new_bitrate != *bitrate) {
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000108 // New bitrate must be lower than previous one.
Erik Språng51e60302016-06-10 22:13:21 +0200109 EXPECT_LT(*new_bitrate, *bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000110 } else {
111 // 0 kbps expected.
Erik Språng51e60302016-06-10 22:13:21 +0200112 EXPECT_EQ(0u, *new_bitrate);
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000113 break;
114 }
115 bitrate = new_bitrate;
116 }
Erik Språng51e60302016-06-10 22:13:21 +0200117
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000118 // 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 22:13:21 +0200121 EXPECT_EQ(0u, *stats_.Rate(now_ms));
mikhal@webrtc.orgd89b52a2013-11-25 17:49:28 +0000122 }
123}
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200124
125TEST_F(RateStatisticsTest, ResetAfterSilence) {
126 int64_t now_ms = 0;
127 stats_.Reset();
128 // Expecting 0 after init.
Erik Språng51e60302016-06-10 22:13:21 +0200129 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
130
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200131 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 11:48:25 +0200134 absl::optional<uint32_t> bitrate;
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200135 while (++now_ms < 10000) {
136 stats_.Update(1000, now_ms);
137 bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200138 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 15:48:23 +0200145 }
146 // Window filled, expect to be close to 8000000.
Erik Språng51e60302016-06-10 22:13:21 +0200147 EXPECT_EQ(kExpectedBitrate, *bitrate);
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200148
149 now_ms += kWindowMs + 1;
Erik Språng51e60302016-06-10 22:13:21 +0200150 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200151 stats_.Update(1000, now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200152 ++now_ms;
153 stats_.Update(1000, now_ms);
154 // We expect two samples of 1000 bytes, and that the bitrate is measured over
155 // 500 ms, i.e. 2 * 8 * 1000 / 0.500 = 32000.
156 EXPECT_EQ(32000u, *stats_.Rate(now_ms));
157
158 // Reset, add the same samples again.
159 stats_.Reset();
160 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
161 stats_.Update(1000, now_ms);
162 ++now_ms;
163 stats_.Update(1000, now_ms);
164 // We expect two samples of 1000 bytes, and that the bitrate is measured over
165 // 2 ms (window size has been reset) i.e. 2 * 8 * 1000 / 0.002 = 8000000.
166 EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
167}
168
169TEST_F(RateStatisticsTest, HandlesChangingWindowSize) {
170 int64_t now_ms = 0;
171 stats_.Reset();
172
173 // Sanity test window size.
174 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
175 EXPECT_FALSE(stats_.SetWindowSize(kWindowMs + 1, now_ms));
176 EXPECT_FALSE(stats_.SetWindowSize(0, now_ms));
177 EXPECT_TRUE(stats_.SetWindowSize(1, now_ms));
178 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
179
180 // Fill the buffer at a rate of 1 byte / millisecond (8 kbps).
181 const int kBatchSize = 10;
182 for (int i = 0; i <= kWindowMs; i += kBatchSize)
183 stats_.Update(kBatchSize, now_ms += kBatchSize);
184 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
185
186 // Halve the window size, rate should stay the same.
187 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs / 2, now_ms));
188 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
189
190 // Double the window size again, rate should stay the same. (As the window
191 // won't actually expand until new bit and bobs fall into it.
192 EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
193 EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
194
195 // Fill the now empty half with bits it twice the rate.
196 for (int i = 0; i < kWindowMs / 2; i += kBatchSize)
197 stats_.Update(kBatchSize * 2, now_ms += kBatchSize);
198
199 // Rate should have increase be 50%.
200 EXPECT_EQ(static_cast<uint32_t>((8000 * 3) / 2), *stats_.Rate(now_ms));
201}
202
203TEST_F(RateStatisticsTest, RespectsWindowSizeEdges) {
204 int64_t now_ms = 0;
205 stats_.Reset();
206 // Expecting 0 after init.
207 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
208
209 // One byte per ms, using one big sample.
210 stats_.Update(kWindowMs, now_ms);
211 now_ms += kWindowMs - 2;
212 // Shouldn't work! (Only one sample, not full window size.)
213 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
214
215 // Window size should be full, and the single data point should be accepted.
216 ++now_ms;
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200217 absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200218 EXPECT_TRUE(static_cast<bool>(bitrate));
219 EXPECT_EQ(1000 * 8u, *bitrate);
220
221 // Add another, now we have twice the bitrate.
222 stats_.Update(kWindowMs, now_ms);
223 bitrate = stats_.Rate(now_ms);
224 EXPECT_TRUE(static_cast<bool>(bitrate));
225 EXPECT_EQ(2 * 1000 * 8u, *bitrate);
226
227 // Now that first sample should drop out...
228 now_ms += 1;
229 bitrate = stats_.Rate(now_ms);
230 EXPECT_TRUE(static_cast<bool>(bitrate));
231 EXPECT_EQ(1000 * 8u, *bitrate);
232}
233
234TEST_F(RateStatisticsTest, HandlesZeroCounts) {
235 int64_t now_ms = 0;
236 stats_.Reset();
237 // Expecting 0 after init.
238 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
239
240 stats_.Update(kWindowMs, now_ms);
241 now_ms += kWindowMs - 1;
242 stats_.Update(0, now_ms);
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200243 absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200244 EXPECT_TRUE(static_cast<bool>(bitrate));
245 EXPECT_EQ(1000 * 8u, *bitrate);
246
247 // Move window along so first data point falls out.
248 ++now_ms;
249 bitrate = stats_.Rate(now_ms);
250 EXPECT_TRUE(static_cast<bool>(bitrate));
251 EXPECT_EQ(0u, *bitrate);
252
253 // Move window so last data point falls out.
254 now_ms += kWindowMs;
255 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
256}
257
258TEST_F(RateStatisticsTest, HandlesQuietPeriods) {
259 int64_t now_ms = 0;
260 stats_.Reset();
261 // Expecting 0 after init.
262 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
263
264 stats_.Update(0, now_ms);
265 now_ms += kWindowMs - 1;
Danil Chapovalov0a1d1892018-06-21 11:48:25 +0200266 absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
Erik Språng51e60302016-06-10 22:13:21 +0200267 EXPECT_TRUE(static_cast<bool>(bitrate));
268 EXPECT_EQ(0u, *bitrate);
269
270 // Move window along so first data point falls out.
271 ++now_ms;
272 EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
273
274 // Move window a long way out.
275 now_ms += 2 * kWindowMs;
276 stats_.Update(0, now_ms);
277 bitrate = stats_.Rate(now_ms);
278 EXPECT_TRUE(static_cast<bool>(bitrate));
279 EXPECT_EQ(0u, *bitrate);
Stefan Holmerfb8fc532016-04-22 15:48:23 +0200280}
solenberg@webrtc.orgd26457f2013-04-18 12:25:32 +0000281} // namespace