| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/quic/congestion_control/general_loss_algorithm.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 #include "base/logging.h" | |
| 10 #include "net/quic/congestion_control/rtt_stats.h" | |
| 11 #include "net/quic/quic_flags.h" | |
| 12 #include "net/quic/quic_unacked_packet_map.h" | |
| 13 #include "net/quic/test_tools/mock_clock.h" | |
| 14 #include "testing/gtest/include/gtest/gtest.h" | |
| 15 | |
| 16 using std::vector; | |
| 17 | |
| 18 namespace net { | |
| 19 namespace test { | |
| 20 namespace { | |
| 21 | |
| 22 // Default packet length. | |
| 23 const uint32_t kDefaultLength = 1000; | |
| 24 | |
| 25 class GeneralLossAlgorithmTest : public ::testing::Test { | |
| 26 protected: | |
| 27 GeneralLossAlgorithmTest() { | |
| 28 rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(100), | |
| 29 QuicTime::Delta::Zero(), clock_.Now()); | |
| 30 EXPECT_LT(0, rtt_stats_.smoothed_rtt().ToMicroseconds()); | |
| 31 } | |
| 32 | |
| 33 ~GeneralLossAlgorithmTest() override {} | |
| 34 | |
| 35 void SendDataPacket(QuicPacketNumber packet_number) { | |
| 36 QuicStreamFrame* frame = new QuicStreamFrame(); | |
| 37 frame->stream_id = kHeadersStreamId; | |
| 38 SerializedPacket packet(kDefaultPathId, packet_number, | |
| 39 PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength, | |
| 40 0, false, false); | |
| 41 packet.retransmittable_frames.push_back(QuicFrame(frame)); | |
| 42 unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(), | |
| 43 true); | |
| 44 } | |
| 45 | |
| 46 void VerifyLosses(QuicPacketNumber largest_newly_acked, | |
| 47 QuicPacketNumber* losses_expected, | |
| 48 size_t num_losses) { | |
| 49 if (largest_newly_acked > unacked_packets_.largest_observed()) { | |
| 50 unacked_packets_.IncreaseLargestObserved(largest_newly_acked); | |
| 51 } | |
| 52 SendAlgorithmInterface::CongestionVector lost_packets; | |
| 53 loss_algorithm_.DetectLosses(unacked_packets_, clock_.Now(), rtt_stats_, | |
| 54 largest_newly_acked, &lost_packets); | |
| 55 EXPECT_EQ(num_losses, lost_packets.size()); | |
| 56 for (size_t i = 0; i < num_losses; ++i) { | |
| 57 EXPECT_EQ(lost_packets[i].first, losses_expected[i]); | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 QuicUnackedPacketMap unacked_packets_; | |
| 62 GeneralLossAlgorithm loss_algorithm_; | |
| 63 RttStats rtt_stats_; | |
| 64 MockClock clock_; | |
| 65 }; | |
| 66 | |
| 67 TEST_F(GeneralLossAlgorithmTest, NackRetransmit1Packet) { | |
| 68 const size_t kNumSentPackets = 5; | |
| 69 // Transmit 5 packets. | |
| 70 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 71 SendDataPacket(i); | |
| 72 } | |
| 73 // No loss on one ack. | |
| 74 unacked_packets_.RemoveFromInFlight(2); | |
| 75 VerifyLosses(2, nullptr, 0); | |
| 76 // No loss on two acks. | |
| 77 unacked_packets_.RemoveFromInFlight(3); | |
| 78 VerifyLosses(3, nullptr, 0); | |
| 79 // Loss on three acks. | |
| 80 unacked_packets_.RemoveFromInFlight(4); | |
| 81 QuicPacketNumber lost[] = {1}; | |
| 82 VerifyLosses(4, lost, arraysize(lost)); | |
| 83 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 84 } | |
| 85 | |
| 86 // A stretch ack is an ack that covers more than 1 packet of previously | |
| 87 // unacknowledged data. | |
| 88 TEST_F(GeneralLossAlgorithmTest, NackRetransmit1PacketWith1StretchAck) { | |
| 89 const size_t kNumSentPackets = 10; | |
| 90 // Transmit 10 packets. | |
| 91 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 92 SendDataPacket(i); | |
| 93 } | |
| 94 | |
| 95 // Nack the first packet 3 times in a single StretchAck. | |
| 96 unacked_packets_.RemoveFromInFlight(2); | |
| 97 unacked_packets_.RemoveFromInFlight(3); | |
| 98 unacked_packets_.RemoveFromInFlight(4); | |
| 99 QuicPacketNumber lost[] = {1}; | |
| 100 VerifyLosses(4, lost, arraysize(lost)); | |
| 101 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 102 } | |
| 103 | |
| 104 // Ack a packet 3 packets ahead, causing a retransmit. | |
| 105 TEST_F(GeneralLossAlgorithmTest, NackRetransmit1PacketSingleAck) { | |
| 106 const size_t kNumSentPackets = 10; | |
| 107 // Transmit 10 packets. | |
| 108 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 109 SendDataPacket(i); | |
| 110 } | |
| 111 | |
| 112 // Nack the first packet 3 times in an AckFrame with three missing packets. | |
| 113 unacked_packets_.RemoveFromInFlight(4); | |
| 114 QuicPacketNumber lost[] = {1}; | |
| 115 VerifyLosses(4, lost, arraysize(lost)); | |
| 116 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 117 } | |
| 118 | |
| 119 TEST_F(GeneralLossAlgorithmTest, EarlyRetransmit1Packet) { | |
| 120 const size_t kNumSentPackets = 2; | |
| 121 // Transmit 2 packets. | |
| 122 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 123 SendDataPacket(i); | |
| 124 } | |
| 125 // Early retransmit when the final packet gets acked and the first is nacked. | |
| 126 unacked_packets_.RemoveFromInFlight(2); | |
| 127 VerifyLosses(2, nullptr, 0); | |
| 128 EXPECT_EQ(clock_.Now() + 1.25 * rtt_stats_.smoothed_rtt(), | |
| 129 loss_algorithm_.GetLossTimeout()); | |
| 130 | |
| 131 clock_.AdvanceTime(1.25 * rtt_stats_.latest_rtt()); | |
| 132 QuicPacketNumber lost[] = {1}; | |
| 133 VerifyLosses(2, lost, arraysize(lost)); | |
| 134 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 135 } | |
| 136 | |
| 137 TEST_F(GeneralLossAlgorithmTest, EarlyRetransmitAllPackets) { | |
| 138 const size_t kNumSentPackets = 5; | |
| 139 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 140 SendDataPacket(i); | |
| 141 // Advance the time 1/4 RTT between 3 and 4. | |
| 142 if (i == 3) { | |
| 143 clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); | |
| 144 } | |
| 145 } | |
| 146 | |
| 147 // Early retransmit when the final packet gets acked and 1.25 RTTs have | |
| 148 // elapsed since the packets were sent. | |
| 149 unacked_packets_.RemoveFromInFlight(kNumSentPackets); | |
| 150 // This simulates a single ack following multiple missing packets with FACK. | |
| 151 QuicPacketNumber lost[] = {1, 2}; | |
| 152 VerifyLosses(kNumSentPackets, lost, arraysize(lost)); | |
| 153 // The time has already advanced 1/4 an RTT, so ensure the timeout is set | |
| 154 // 1.25 RTTs after the earliest pending packet(3), not the last(4). | |
| 155 EXPECT_EQ(clock_.Now() + rtt_stats_.smoothed_rtt(), | |
| 156 loss_algorithm_.GetLossTimeout()); | |
| 157 | |
| 158 clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); | |
| 159 QuicPacketNumber lost2[] = {1, 2, 3}; | |
| 160 VerifyLosses(kNumSentPackets, lost2, arraysize(lost2)); | |
| 161 EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(), | |
| 162 loss_algorithm_.GetLossTimeout()); | |
| 163 clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); | |
| 164 QuicPacketNumber lost3[] = {1, 2, 3, 4}; | |
| 165 VerifyLosses(kNumSentPackets, lost3, arraysize(lost3)); | |
| 166 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 167 } | |
| 168 | |
| 169 TEST_F(GeneralLossAlgorithmTest, DontEarlyRetransmitNeuteredPacket) { | |
| 170 const size_t kNumSentPackets = 2; | |
| 171 // Transmit 2 packets. | |
| 172 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 173 SendDataPacket(i); | |
| 174 } | |
| 175 // Neuter packet 1. | |
| 176 unacked_packets_.RemoveRetransmittability(1); | |
| 177 | |
| 178 // Early retransmit when the final packet gets acked and the first is nacked. | |
| 179 unacked_packets_.IncreaseLargestObserved(2); | |
| 180 unacked_packets_.RemoveFromInFlight(2); | |
| 181 VerifyLosses(2, nullptr, 0); | |
| 182 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 183 } | |
| 184 | |
| 185 TEST_F(GeneralLossAlgorithmTest, AlwaysLosePacketSent1RTTEarlier) { | |
| 186 // Transmit 1 packet and then wait an rtt plus 1ms. | |
| 187 SendDataPacket(1); | |
| 188 clock_.AdvanceTime(rtt_stats_.smoothed_rtt() + | |
| 189 QuicTime::Delta::FromMilliseconds(1)); | |
| 190 | |
| 191 // Transmit 2 packets. | |
| 192 SendDataPacket(2); | |
| 193 SendDataPacket(3); | |
| 194 | |
| 195 // Wait another RTT and ack 2. | |
| 196 clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); | |
| 197 unacked_packets_.IncreaseLargestObserved(2); | |
| 198 unacked_packets_.RemoveFromInFlight(2); | |
| 199 QuicPacketNumber lost[] = {1}; | |
| 200 VerifyLosses(2, lost, arraysize(lost)); | |
| 201 } | |
| 202 | |
| 203 // Time-based loss detection tests. | |
| 204 TEST_F(GeneralLossAlgorithmTest, NoLossFor500Nacks) { | |
| 205 loss_algorithm_.SetLossDetectionType(kTime); | |
| 206 const size_t kNumSentPackets = 5; | |
| 207 // Transmit 5 packets. | |
| 208 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 209 SendDataPacket(i); | |
| 210 } | |
| 211 unacked_packets_.RemoveFromInFlight(2); | |
| 212 for (size_t i = 1; i < 500; ++i) { | |
| 213 VerifyLosses(2, nullptr, 0); | |
| 214 } | |
| 215 EXPECT_EQ(1.25 * rtt_stats_.smoothed_rtt(), | |
| 216 loss_algorithm_.GetLossTimeout() - clock_.Now()); | |
| 217 } | |
| 218 | |
| 219 TEST_F(GeneralLossAlgorithmTest, NoLossUntilTimeout) { | |
| 220 loss_algorithm_.SetLossDetectionType(kTime); | |
| 221 const size_t kNumSentPackets = 10; | |
| 222 // Transmit 10 packets at 1/10th an RTT interval. | |
| 223 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 224 SendDataPacket(i); | |
| 225 clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt()); | |
| 226 } | |
| 227 // Expect the timer to not be set. | |
| 228 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 229 // The packet should not be lost until 1.25 RTTs pass. | |
| 230 unacked_packets_.RemoveFromInFlight(2); | |
| 231 VerifyLosses(2, nullptr, 0); | |
| 232 // Expect the timer to be set to 0.25 RTT's in the future. | |
| 233 EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(), | |
| 234 loss_algorithm_.GetLossTimeout() - clock_.Now()); | |
| 235 VerifyLosses(2, nullptr, 0); | |
| 236 clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); | |
| 237 QuicPacketNumber lost[] = {1}; | |
| 238 VerifyLosses(2, lost, arraysize(lost)); | |
| 239 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 240 } | |
| 241 | |
| 242 TEST_F(GeneralLossAlgorithmTest, NoLossWithoutNack) { | |
| 243 loss_algorithm_.SetLossDetectionType(kTime); | |
| 244 const size_t kNumSentPackets = 10; | |
| 245 // Transmit 10 packets at 1/10th an RTT interval. | |
| 246 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 247 SendDataPacket(i); | |
| 248 clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt()); | |
| 249 } | |
| 250 // Expect the timer to not be set. | |
| 251 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 252 // The packet should not be lost without a nack. | |
| 253 unacked_packets_.RemoveFromInFlight(1); | |
| 254 VerifyLosses(1, nullptr, 0); | |
| 255 // The timer should still not be set. | |
| 256 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 257 clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); | |
| 258 VerifyLosses(1, nullptr, 0); | |
| 259 clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); | |
| 260 VerifyLosses(1, nullptr, 0); | |
| 261 | |
| 262 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 263 } | |
| 264 | |
| 265 TEST_F(GeneralLossAlgorithmTest, MultipleLossesAtOnce) { | |
| 266 loss_algorithm_.SetLossDetectionType(kTime); | |
| 267 const size_t kNumSentPackets = 10; | |
| 268 // Transmit 10 packets at once and then go forward an RTT. | |
| 269 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 270 SendDataPacket(i); | |
| 271 } | |
| 272 clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); | |
| 273 // Expect the timer to not be set. | |
| 274 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 275 // The packet should not be lost until 1.25 RTTs pass. | |
| 276 unacked_packets_.RemoveFromInFlight(10); | |
| 277 VerifyLosses(10, nullptr, 0); | |
| 278 // Expect the timer to be set to 0.25 RTT's in the future. | |
| 279 EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(), | |
| 280 loss_algorithm_.GetLossTimeout() - clock_.Now()); | |
| 281 clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); | |
| 282 QuicPacketNumber lost[] = {1, 2, 3, 4, 5, 6, 7, 8, 9}; | |
| 283 VerifyLosses(10, lost, arraysize(lost)); | |
| 284 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 285 } | |
| 286 | |
| 287 TEST_F(GeneralLossAlgorithmTest, NoSpuriousLossesFromLargeReordering) { | |
| 288 FLAGS_quic_loss_recovery_use_largest_acked = true; | |
| 289 loss_algorithm_.SetLossDetectionType(kTime); | |
| 290 const size_t kNumSentPackets = 10; | |
| 291 // Transmit 10 packets at once and then go forward an RTT. | |
| 292 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 293 SendDataPacket(i); | |
| 294 } | |
| 295 clock_.AdvanceTime(rtt_stats_.smoothed_rtt()); | |
| 296 // Expect the timer to not be set. | |
| 297 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 298 // The packet should not be lost until 1.25 RTTs pass. | |
| 299 | |
| 300 unacked_packets_.RemoveFromInFlight(10); | |
| 301 VerifyLosses(10, nullptr, 0); | |
| 302 // Expect the timer to be set to 0.25 RTT's in the future. | |
| 303 EXPECT_EQ(0.25 * rtt_stats_.smoothed_rtt(), | |
| 304 loss_algorithm_.GetLossTimeout() - clock_.Now()); | |
| 305 clock_.AdvanceTime(0.25 * rtt_stats_.smoothed_rtt()); | |
| 306 // Now ack packets 1 to 9 and ensure the timer is no longer set and no packets | |
| 307 // are lost. | |
| 308 for (QuicPacketNumber i = 1; i <= 9; ++i) { | |
| 309 unacked_packets_.RemoveFromInFlight(i); | |
| 310 VerifyLosses(i, nullptr, 0); | |
| 311 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 312 } | |
| 313 } | |
| 314 | |
| 315 TEST_F(GeneralLossAlgorithmTest, IncreaseThresholdUponSpuriousLoss) { | |
| 316 loss_algorithm_.SetLossDetectionType(kAdaptiveTime); | |
| 317 EXPECT_EQ(4, loss_algorithm_.reordering_shift()); | |
| 318 const size_t kNumSentPackets = 10; | |
| 319 // Transmit 2 packets at 1/10th an RTT interval. | |
| 320 for (size_t i = 1; i <= kNumSentPackets; ++i) { | |
| 321 SendDataPacket(i); | |
| 322 clock_.AdvanceTime(0.1 * rtt_stats_.smoothed_rtt()); | |
| 323 } | |
| 324 EXPECT_EQ(QuicTime::Zero() + rtt_stats_.smoothed_rtt(), clock_.Now()); | |
| 325 | |
| 326 // Expect the timer to not be set. | |
| 327 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 328 // Packet 1 should not be lost until 1/16 RTTs pass. | |
| 329 unacked_packets_.RemoveFromInFlight(2); | |
| 330 VerifyLosses(2, nullptr, 0); | |
| 331 // Expect the timer to be set to 1/16 RTT's in the future. | |
| 332 EXPECT_EQ(rtt_stats_.smoothed_rtt() * (1.0f / 16), | |
| 333 loss_algorithm_.GetLossTimeout() - clock_.Now()); | |
| 334 VerifyLosses(2, nullptr, 0); | |
| 335 clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 16)); | |
| 336 QuicPacketNumber lost[] = {1}; | |
| 337 VerifyLosses(2, lost, arraysize(lost)); | |
| 338 EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout()); | |
| 339 // Retransmit packet 1 as 11 and 2 as 12. | |
| 340 SendDataPacket(11); | |
| 341 SendDataPacket(12); | |
| 342 | |
| 343 // Advance the time 1/4 RTT and indicate the loss was spurious. | |
| 344 // The new threshold should be 1/2 RTT. | |
| 345 clock_.AdvanceTime(rtt_stats_.smoothed_rtt() * (1.0f / 4)); | |
| 346 loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(), | |
| 347 rtt_stats_, 11); | |
| 348 EXPECT_EQ(1, loss_algorithm_.reordering_shift()); | |
| 349 | |
| 350 // Detect another spurious retransmit and ensure the threshold doesn't | |
| 351 // increase again. | |
| 352 loss_algorithm_.SpuriousRetransmitDetected(unacked_packets_, clock_.Now(), | |
| 353 rtt_stats_, 12); | |
| 354 EXPECT_EQ(1, loss_algorithm_.reordering_shift()); | |
| 355 } | |
| 356 | |
| 357 } // namespace | |
| 358 } // namespace test | |
| 359 } // namespace net | |
| OLD | NEW |