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