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 |