blob: 3f80e211749c07da45df4c5947281b8cd5254e32 [file] [log] [blame]
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +02001/*
2 * Copyright (c) 2018 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 <utility>
12
13#include "absl/memory/memory.h"
14#include "modules/congestion_controller/pcc/bitrate_controller.h"
15#include "modules/congestion_controller/pcc/monitor_interval.h"
16#include "test/gmock.h"
17#include "test/gtest.h"
18
19namespace webrtc {
20namespace pcc {
21namespace test {
22namespace {
23constexpr double kInitialConversionFactor = 1;
24constexpr double kInitialDynamicBoundary = 0.05;
25constexpr double kDynamicBoundaryIncrement = 0.1;
26
27constexpr double kDelayGradientCoefficient = 900;
28constexpr double kLossCoefficient = 11.35;
29constexpr double kThroughputCoefficient = 500 * 1000;
30constexpr double kThroughputPower = 0.99;
31constexpr double kDelayGradientThreshold = 0.01;
32constexpr double kDelayGradientNegativeBound = 10;
33
34const DataRate kTargetSendingRate = DataRate::kbps(300);
35const double kEpsilon = 0.05;
36const Timestamp kStartTime = Timestamp::us(0);
37const TimeDelta kPacketsDelta = TimeDelta::ms(1);
38const TimeDelta kIntervalDuration = TimeDelta::ms(1000);
39const TimeDelta kDefaultRtt = TimeDelta::ms(1000);
40const DataSize kDefaultDataSize = DataSize::bytes(100);
41
42std::vector<PacketResult> CreatePacketResults(
43 const std::vector<Timestamp>& packets_send_times,
44 const std::vector<Timestamp>& packets_received_times = {},
45 const std::vector<DataSize>& packets_sizes = {}) {
46 std::vector<PacketResult> packet_results;
47 PacketResult packet_result;
48 SentPacket sent_packet;
49 for (size_t i = 0; i < packets_send_times.size(); ++i) {
50 sent_packet.send_time = packets_send_times[i];
51 if (packets_sizes.empty()) {
52 sent_packet.size = kDefaultDataSize;
53 } else {
54 sent_packet.size = packets_sizes[i];
55 }
56 packet_result.sent_packet = sent_packet;
57 if (packets_received_times.empty()) {
58 packet_result.receive_time = packets_send_times[i] + kDefaultRtt;
59 } else {
60 packet_result.receive_time = packets_received_times[i];
61 }
62 packet_results.push_back(packet_result);
63 }
64 return packet_results;
65}
66
67class MockUtilityFunction : public PccUtilityFunctionInterface {
68 public:
69 MOCK_CONST_METHOD1(Compute,
70 double(const PccMonitorInterval& monitor_interval));
71};
72
73} // namespace
74
75TEST(PccBitrateControllerTest, IncreaseRateWhenNoChangesForTestBitrates) {
76 PccBitrateController bitrate_controller(
77 kInitialConversionFactor, kInitialDynamicBoundary,
78 kDynamicBoundaryIncrement, kDelayGradientCoefficient, kLossCoefficient,
79 kThroughputCoefficient, kThroughputPower, kDelayGradientThreshold,
80 kDelayGradientNegativeBound);
81 VivaceUtilityFunction utility_function(
82 kDelayGradientCoefficient, kLossCoefficient, kThroughputCoefficient,
83 kThroughputPower, kDelayGradientThreshold, kDelayGradientNegativeBound);
84 std::vector<PccMonitorInterval> monitor_block{
85 PccMonitorInterval(kTargetSendingRate * (1 + kEpsilon), kStartTime,
86 kIntervalDuration),
87 PccMonitorInterval(kTargetSendingRate * (1 - kEpsilon),
88 kStartTime + kIntervalDuration, kIntervalDuration)};
89 monitor_block[0].OnPacketsFeedback(
90 CreatePacketResults({kStartTime + kPacketsDelta,
91 kStartTime + kIntervalDuration + kPacketsDelta,
92 kStartTime + 3 * kIntervalDuration},
93 {}, {}));
94 monitor_block[1].OnPacketsFeedback(
95 CreatePacketResults({kStartTime + kPacketsDelta,
96 kStartTime + kIntervalDuration + kPacketsDelta,
97 kStartTime + 3 * kIntervalDuration},
98 {}, {}));
99 // For both of the monitor intervals there were no change in rtt gradient
100 // and in packet loss. Since the only difference is in the sending rate,
101 // the higher sending rate should be chosen by congestion controller.
102 EXPECT_GT(bitrate_controller
103 .ComputeRateUpdateForOnlineLearningMode(monitor_block,
104 kTargetSendingRate)
105 .bps(),
106 kTargetSendingRate.bps());
107}
108
109TEST(PccBitrateControllerTest, NoChangesWhenUtilityFunctionDoesntChange) {
110 std::unique_ptr<MockUtilityFunction> mock_utility_function =
111 absl::make_unique<MockUtilityFunction>();
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200112 EXPECT_CALL(*mock_utility_function, Compute(::testing::_))
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200113 .Times(2)
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200114 .WillOnce(::testing::Return(100))
115 .WillOnce(::testing::Return(100));
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200116
117 PccBitrateController bitrate_controller(
118 kInitialConversionFactor, kInitialDynamicBoundary,
119 kDynamicBoundaryIncrement, std::move(mock_utility_function));
120 std::vector<PccMonitorInterval> monitor_block{
121 PccMonitorInterval(kTargetSendingRate * (1 + kEpsilon), kStartTime,
122 kIntervalDuration),
123 PccMonitorInterval(kTargetSendingRate * (1 - kEpsilon),
124 kStartTime + kIntervalDuration, kIntervalDuration)};
125 // To complete collecting feedback within monitor intervals.
126 monitor_block[0].OnPacketsFeedback(
127 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
128 monitor_block[1].OnPacketsFeedback(
129 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
130 // Because we don't have any packets inside of monitor intervals, utility
131 // function should be zero for both of them and the sending rate should not
132 // change.
133 EXPECT_EQ(bitrate_controller
134 .ComputeRateUpdateForOnlineLearningMode(monitor_block,
135 kTargetSendingRate)
136 .bps(),
137 kTargetSendingRate.bps());
138}
139
140TEST(PccBitrateControllerTest, NoBoundaryWhenSmallGradient) {
141 std::unique_ptr<MockUtilityFunction> mock_utility_function =
142 absl::make_unique<MockUtilityFunction>();
143 constexpr double kFirstMonitorIntervalUtility = 0;
144 const double kSecondMonitorIntervalUtility =
145 2 * kTargetSendingRate.bps() * kEpsilon;
146
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200147 EXPECT_CALL(*mock_utility_function, Compute(::testing::_))
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200148 .Times(2)
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200149 .WillOnce(::testing::Return(kFirstMonitorIntervalUtility))
150 .WillOnce(::testing::Return(kSecondMonitorIntervalUtility));
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200151
152 PccBitrateController bitrate_controller(
153 kInitialConversionFactor, kInitialDynamicBoundary,
154 kDynamicBoundaryIncrement, std::move(mock_utility_function));
155 std::vector<PccMonitorInterval> monitor_block{
156 PccMonitorInterval(kTargetSendingRate * (1 + kEpsilon), kStartTime,
157 kIntervalDuration),
158 PccMonitorInterval(kTargetSendingRate * (1 - kEpsilon),
159 kStartTime + kIntervalDuration, kIntervalDuration)};
160 // To complete collecting feedback within monitor intervals.
161 monitor_block[0].OnPacketsFeedback(
162 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
163 monitor_block[1].OnPacketsFeedback(
164 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
165
166 double gradient =
167 (kFirstMonitorIntervalUtility - kSecondMonitorIntervalUtility) /
168 (kTargetSendingRate.bps() * 2 * kEpsilon);
169 // When the gradient is small we don't hit the dynamic boundary.
170 EXPECT_EQ(bitrate_controller
171 .ComputeRateUpdateForOnlineLearningMode(monitor_block,
172 kTargetSendingRate)
173 .bps(),
174 kTargetSendingRate.bps() + kInitialConversionFactor * gradient);
175}
176
177TEST(PccBitrateControllerTest, FaceBoundaryWhenLargeGradient) {
178 std::unique_ptr<MockUtilityFunction> mock_utility_function =
179 absl::make_unique<MockUtilityFunction>();
180 constexpr double kFirstMonitorIntervalUtility = 0;
181 const double kSecondMonitorIntervalUtility =
182 10 * kInitialDynamicBoundary * kTargetSendingRate.bps() * 2 *
183 kTargetSendingRate.bps() * kEpsilon;
184
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200185 EXPECT_CALL(*mock_utility_function, Compute(::testing::_))
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200186 .Times(4)
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200187 .WillOnce(::testing::Return(kFirstMonitorIntervalUtility))
188 .WillOnce(::testing::Return(kSecondMonitorIntervalUtility))
189 .WillOnce(::testing::Return(kFirstMonitorIntervalUtility))
190 .WillOnce(::testing::Return(kSecondMonitorIntervalUtility));
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200191
192 PccBitrateController bitrate_controller(
193 kInitialConversionFactor, kInitialDynamicBoundary,
194 kDynamicBoundaryIncrement, std::move(mock_utility_function));
195 std::vector<PccMonitorInterval> monitor_block{
196 PccMonitorInterval(kTargetSendingRate * (1 + kEpsilon), kStartTime,
197 kIntervalDuration),
198 PccMonitorInterval(kTargetSendingRate * (1 - kEpsilon),
199 kStartTime + kIntervalDuration, kIntervalDuration)};
200 // To complete collecting feedback within monitor intervals.
201 monitor_block[0].OnPacketsFeedback(
202 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
203 monitor_block[1].OnPacketsFeedback(
204 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
205 // The utility function gradient is too big and we hit the dynamic boundary.
206 EXPECT_EQ(bitrate_controller.ComputeRateUpdateForOnlineLearningMode(
207 monitor_block, kTargetSendingRate),
208 kTargetSendingRate * (1 - kInitialDynamicBoundary));
209 // For the second time we hit the dynamic boundary in the same direction, the
210 // boundary should increase.
211 EXPECT_EQ(bitrate_controller
212 .ComputeRateUpdateForOnlineLearningMode(monitor_block,
213 kTargetSendingRate)
214 .bps(),
215 kTargetSendingRate.bps() *
216 (1 - kInitialDynamicBoundary - kDynamicBoundaryIncrement));
217}
218
219TEST(PccBitrateControllerTest, SlowStartMode) {
220 std::unique_ptr<MockUtilityFunction> mock_utility_function =
221 absl::make_unique<MockUtilityFunction>();
222 constexpr double kFirstUtilityFunction = 1000;
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200223 EXPECT_CALL(*mock_utility_function, Compute(::testing::_))
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200224 .Times(4)
225 // For first 3 calls we expect to stay in the SLOW_START mode and double
226 // the sending rate since the utility function increases its value. For
227 // the last call utility function decreases its value, this means that
228 // we should not double the sending rate and exit SLOW_START mode.
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200229 .WillOnce(::testing::Return(kFirstUtilityFunction))
230 .WillOnce(::testing::Return(kFirstUtilityFunction + 1))
231 .WillOnce(::testing::Return(kFirstUtilityFunction + 2))
232 .WillOnce(::testing::Return(kFirstUtilityFunction + 1));
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200233
234 PccBitrateController bitrate_controller(
235 kInitialConversionFactor, kInitialDynamicBoundary,
236 kDynamicBoundaryIncrement, std::move(mock_utility_function));
237 std::vector<PccMonitorInterval> monitor_block{PccMonitorInterval(
238 2 * kTargetSendingRate, kStartTime, kIntervalDuration)};
239 // To complete collecting feedback within monitor intervals.
240 monitor_block[0].OnPacketsFeedback(
241 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
242 EXPECT_EQ(
243 bitrate_controller.ComputeRateUpdateForSlowStartMode(monitor_block[0]),
244 kTargetSendingRate * 2);
245 EXPECT_EQ(
246 bitrate_controller.ComputeRateUpdateForSlowStartMode(monitor_block[0]),
247 kTargetSendingRate * 2);
248 EXPECT_EQ(
249 bitrate_controller.ComputeRateUpdateForSlowStartMode(monitor_block[0]),
250 kTargetSendingRate * 2);
251 EXPECT_EQ(
252 bitrate_controller.ComputeRateUpdateForSlowStartMode(monitor_block[0]),
253 absl::nullopt);
254}
255
256TEST(PccBitrateControllerTest, StepSizeIncrease) {
257 std::unique_ptr<MockUtilityFunction> mock_utility_function =
258 absl::make_unique<MockUtilityFunction>();
259 constexpr double kFirstMiUtilityFunction = 0;
260 const double kSecondMiUtilityFunction =
261 2 * kTargetSendingRate.bps() * kEpsilon;
262
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200263 EXPECT_CALL(*mock_utility_function, Compute(::testing::_))
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200264 .Times(4)
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200265 .WillOnce(::testing::Return(kFirstMiUtilityFunction))
266 .WillOnce(::testing::Return(kSecondMiUtilityFunction))
267 .WillOnce(::testing::Return(kFirstMiUtilityFunction))
268 .WillOnce(::testing::Return(kSecondMiUtilityFunction));
Anastasia Koloskovaea9249e2018-08-21 16:12:55 +0200269 std::vector<PccMonitorInterval> monitor_block{
270 PccMonitorInterval(kTargetSendingRate * (1 + kEpsilon), kStartTime,
271 kIntervalDuration),
272 PccMonitorInterval(kTargetSendingRate * (1 - kEpsilon),
273 kStartTime + kIntervalDuration, kIntervalDuration)};
274 // To complete collecting feedback within monitor intervals.
275 monitor_block[0].OnPacketsFeedback(
276 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
277 monitor_block[1].OnPacketsFeedback(
278 CreatePacketResults({kStartTime + 3 * kIntervalDuration}, {}, {}));
279
280 double gradient = (kFirstMiUtilityFunction - kSecondMiUtilityFunction) /
281 (kTargetSendingRate.bps() * 2 * kEpsilon);
282 PccBitrateController bitrate_controller(
283 kInitialConversionFactor, kInitialDynamicBoundary,
284 kDynamicBoundaryIncrement, std::move(mock_utility_function));
285 // If we are moving in the same direction - the step size should increase.
286 EXPECT_EQ(bitrate_controller
287 .ComputeRateUpdateForOnlineLearningMode(monitor_block,
288 kTargetSendingRate)
289 .bps(),
290 kTargetSendingRate.bps() + kInitialConversionFactor * gradient);
291 EXPECT_EQ(bitrate_controller
292 .ComputeRateUpdateForOnlineLearningMode(monitor_block,
293 kTargetSendingRate)
294 .bps(),
295 kTargetSendingRate.bps() + 2 * kInitialConversionFactor * gradient);
296}
297
298} // namespace test
299} // namespace pcc
300} // namespace webrtc