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