1 // Copyright (c) 2012 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.
5 #include "base/logging.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "net/quic/congestion_control/tcp_cubic_sender.h"
8 #include "net/quic/congestion_control/tcp_receiver.h"
9 #include "net/quic/test_tools/mock_clock.h"
10 #include "testing/gtest/include/gtest/gtest.h"
15 const uint32 kDefaultWindowTCP = 10 * kDefaultTCPMSS;
17 // TODO(ianswett): Remove 10000 once b/10075719 is fixed.
18 const QuicTcpCongestionWindow kDefaultMaxCongestionWindowTCP = 10000;
20 class TcpCubicSenderPeer : public TcpCubicSender {
22 TcpCubicSenderPeer(const QuicClock* clock,
24 QuicTcpCongestionWindow max_tcp_congestion_window)
25 : TcpCubicSender(clock, reno, max_tcp_congestion_window) {
28 QuicTcpCongestionWindow congestion_window() {
29 return congestion_window_;
32 using TcpCubicSender::AvailableSendWindow;
33 using TcpCubicSender::SendWindow;
34 using TcpCubicSender::AckAccounting;
37 class TcpCubicSenderTest : public ::testing::Test {
40 : rtt_(QuicTime::Delta::FromMilliseconds(60)),
41 one_ms_(QuicTime::Delta::FromMilliseconds(1)),
42 sender_(new TcpCubicSenderPeer(&clock_, true,
43 kDefaultMaxCongestionWindowTCP)),
44 receiver_(new TcpReceiver()),
46 acked_sequence_number_(0) {
49 void SendAvailableSendWindow() {
50 QuicByteCount bytes_to_send = sender_->AvailableSendWindow();
51 while (bytes_to_send > 0) {
52 QuicByteCount bytes_in_packet = std::min(kDefaultTCPMSS, bytes_to_send);
53 sender_->OnPacketSent(clock_.Now(), sequence_number_++, bytes_in_packet,
54 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
55 bytes_to_send -= bytes_in_packet;
56 if (bytes_to_send > 0) {
57 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION,
58 HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
62 // Normal is that TCP acks every other segment.
63 void AckNPackets(int n) {
64 for (int i = 0; i < n; ++i) {
65 acked_sequence_number_++;
66 sender_->OnIncomingAck(acked_sequence_number_, kDefaultTCPMSS, rtt_);
68 clock_.AdvanceTime(one_ms_); // 1 millisecond.
71 const QuicTime::Delta rtt_;
72 const QuicTime::Delta one_ms_;
74 SendAlgorithmInterface::SentPacketsMap not_used_;
75 scoped_ptr<TcpCubicSenderPeer> sender_;
76 scoped_ptr<TcpReceiver> receiver_;
77 QuicPacketSequenceNumber sequence_number_;
78 QuicPacketSequenceNumber acked_sequence_number_;
81 TEST_F(TcpCubicSenderTest, SimpleSender) {
82 QuicCongestionFeedbackFrame feedback;
83 // At startup make sure we are at the default.
84 EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableSendWindow());
85 EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
86 // At startup make sure we can send.
87 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
88 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
89 // Get default QuicCongestionFeedbackFrame from receiver.
90 ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
91 sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
93 // Make sure we can send.
94 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
95 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
96 // And that window is un-affected.
97 EXPECT_EQ(kDefaultWindowTCP, sender_->AvailableSendWindow());
98 EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
100 // A retransmit should always return 0.
101 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
102 NACK_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
105 TEST_F(TcpCubicSenderTest, ExponentialSlowStart) {
106 const int kNumberOfAck = 20;
107 QuicCongestionFeedbackFrame feedback;
108 // At startup make sure we can send.
109 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
110 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
111 // Get default QuicCongestionFeedbackFrame from receiver.
112 ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
113 sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
115 // Make sure we can send.
116 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
117 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
119 for (int n = 0; n < kNumberOfAck; ++n) {
120 // Send our full send window.
121 SendAvailableSendWindow();
124 QuicByteCount bytes_to_send = sender_->SendWindow();
125 EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAck,
129 TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
130 // Make sure that we fall out of slow start when we send ACK train longer
131 // than half the RTT, in this test case 30ms, which is more than 30 calls to
132 // Ack2Packets in one round.
133 // Since we start at 10 packet first round will be 5 second round 10 etc
134 // Hence we should pass 30 at 65 = 5 + 10 + 20 + 30
135 const int kNumberOfAck = 65;
136 QuicCongestionFeedbackFrame feedback;
137 // At startup make sure we can send.
138 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
139 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
140 // Get default QuicCongestionFeedbackFrame from receiver.
141 ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
142 sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
144 // Make sure we can send.
145 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
146 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
148 for (int n = 0; n < kNumberOfAck; ++n) {
149 // Send our full send window.
150 SendAvailableSendWindow();
153 QuicByteCount expected_send_window =
154 kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAck);
155 EXPECT_EQ(expected_send_window, sender_->SendWindow());
156 EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow());
157 // We should now have fallen out of slow start.
158 SendAvailableSendWindow();
160 expected_send_window += kDefaultTCPMSS;
161 EXPECT_EQ(expected_send_window, sender_->SendWindow());
163 // Testing Reno phase.
164 // We should need 141(65*2+1+10) ACK:ed packets before increasing window by
166 for (int m = 0; m < 70; ++m) {
167 SendAvailableSendWindow();
169 EXPECT_EQ(expected_send_window, sender_->SendWindow());
171 SendAvailableSendWindow();
173 expected_send_window += kDefaultTCPMSS;
174 EXPECT_EQ(expected_send_window, sender_->SendWindow());
177 TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) {
178 // Make sure that we fall out of slow start when we encounter a packet loss.
179 const int kNumberOfAck = 10;
180 QuicCongestionFeedbackFrame feedback;
181 // At startup make sure we can send.
182 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
183 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
184 // Get default QuicCongestionFeedbackFrame from receiver.
185 ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
186 sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
188 // Make sure we can send.
189 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
190 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
192 for (int i = 0; i < kNumberOfAck; ++i) {
193 // Send our full send window.
194 SendAvailableSendWindow();
197 SendAvailableSendWindow();
198 QuicByteCount expected_send_window = kDefaultWindowTCP +
199 (kDefaultTCPMSS * 2 * kNumberOfAck);
200 EXPECT_EQ(expected_send_window, sender_->SendWindow());
202 sender_->OnIncomingLoss(clock_.Now());
204 // Make sure that we should not send right now.
205 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), NOT_RETRANSMISSION,
206 HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsInfinite());
208 // We should now have fallen out of slow start.
209 // We expect window to be cut in half.
210 expected_send_window /= 2;
211 EXPECT_EQ(expected_send_window, sender_->SendWindow());
213 // Testing Reno phase.
214 // We need to ack half of the pending packet before we can send again.
215 int number_of_packets_in_window = expected_send_window / kDefaultTCPMSS;
216 AckNPackets(number_of_packets_in_window);
217 EXPECT_EQ(expected_send_window, sender_->SendWindow());
218 EXPECT_EQ(0u, sender_->AvailableSendWindow());
221 expected_send_window += kDefaultTCPMSS;
222 number_of_packets_in_window++;
223 EXPECT_EQ(expected_send_window, sender_->SendWindow());
225 // We should need number_of_packets_in_window ACK:ed packets before
226 // increasing window by one.
227 for (int k = 0; k < number_of_packets_in_window; ++k) {
228 SendAvailableSendWindow();
230 EXPECT_EQ(expected_send_window, sender_->SendWindow());
232 SendAvailableSendWindow();
234 expected_send_window += kDefaultTCPMSS;
235 EXPECT_EQ(expected_send_window, sender_->SendWindow());
238 TEST_F(TcpCubicSenderTest, RetransmissionDelay) {
239 const int64 kRttMs = 10;
240 const int64 kDeviationMs = 3;
241 EXPECT_EQ(QuicTime::Delta::Zero(), sender_->RetransmissionDelay());
243 sender_->AckAccounting(QuicTime::Delta::FromMilliseconds(kRttMs));
245 // Initial value is to set the median deviation to half of the initial
246 // rtt, the median in then multiplied by a factor of 4 and finally the
247 // smoothed rtt is added which is the initial rtt.
248 QuicTime::Delta expected_delay =
249 QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4);
250 EXPECT_EQ(expected_delay, sender_->RetransmissionDelay());
252 for (int i = 0; i < 100; ++i) {
253 // Run to make sure that we converge.
254 sender_->AckAccounting(
255 QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs));
256 sender_->AckAccounting(
257 QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs));
259 expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4);
261 EXPECT_NEAR(kRttMs, sender_->SmoothedRtt().ToMilliseconds(), 1);
262 EXPECT_NEAR(expected_delay.ToMilliseconds(),
263 sender_->RetransmissionDelay().ToMilliseconds(),
267 TEST_F(TcpCubicSenderTest, SlowStartMaxSendWindow) {
268 const QuicTcpCongestionWindow kMaxCongestionWindowTCP = 50;
269 const int kNumberOfAck = 100;
271 new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP));
273 QuicCongestionFeedbackFrame feedback;
274 // At startup make sure we can send.
275 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
276 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
277 // Get default QuicCongestionFeedbackFrame from receiver.
278 ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
279 sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
281 // Make sure we can send.
282 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
283 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
285 for (int i = 0; i < kNumberOfAck; ++i) {
286 // Send our full send window.
287 SendAvailableSendWindow();
290 QuicByteCount expected_send_window =
291 kMaxCongestionWindowTCP * kDefaultTCPMSS;
292 EXPECT_EQ(expected_send_window, sender_->SendWindow());
295 TEST_F(TcpCubicSenderTest, TcpRenoMaxCongestionWindow) {
296 const QuicTcpCongestionWindow kMaxCongestionWindowTCP = 50;
297 const int kNumberOfAck = 1000;
299 new TcpCubicSenderPeer(&clock_, true, kMaxCongestionWindowTCP));
301 QuicCongestionFeedbackFrame feedback;
302 // At startup make sure we can send.
303 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
304 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
305 // Get default QuicCongestionFeedbackFrame from receiver.
306 ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
307 sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
309 // Make sure we can send.
310 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
311 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
313 SendAvailableSendWindow();
315 // Make sure we fall out of slow start.
316 sender_->OnIncomingLoss(clock_.Now());
318 for (int i = 0; i < kNumberOfAck; ++i) {
319 // Send our full send window.
320 SendAvailableSendWindow();
324 QuicByteCount expected_send_window =
325 kMaxCongestionWindowTCP * kDefaultTCPMSS;
326 EXPECT_EQ(expected_send_window, sender_->SendWindow());
329 TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) {
330 const QuicTcpCongestionWindow kMaxCongestionWindowTCP = 50;
331 const int kNumberOfAck = 1000;
333 new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP));
335 QuicCongestionFeedbackFrame feedback;
336 // At startup make sure we can send.
337 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
338 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
339 // Get default QuicCongestionFeedbackFrame from receiver.
340 ASSERT_TRUE(receiver_->GenerateCongestionFeedback(&feedback));
341 sender_->OnIncomingQuicCongestionFeedbackFrame(feedback, clock_.Now(),
343 // Make sure we can send.
344 EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(),
345 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero());
347 SendAvailableSendWindow();
349 // Make sure we fall out of slow start.
350 sender_->OnIncomingLoss(clock_.Now());
352 for (int i = 0; i < kNumberOfAck; ++i) {
353 // Send our full send window.
354 SendAvailableSendWindow();
358 QuicByteCount expected_send_window =
359 kMaxCongestionWindowTCP * kDefaultTCPMSS;
360 EXPECT_EQ(expected_send_window, sender_->SendWindow());
363 TEST_F(TcpCubicSenderTest, SendWindowNotAffectedByAcks) {
364 QuicByteCount send_window = sender_->AvailableSendWindow();
366 // Send a packet with no retransmittable data, and ensure that the congestion
367 // window doesn't change.
368 QuicByteCount bytes_in_packet = std::min(kDefaultTCPMSS, send_window);
369 sender_->OnPacketSent(clock_.Now(), sequence_number_++, bytes_in_packet,
370 NOT_RETRANSMISSION, NO_RETRANSMITTABLE_DATA);
371 EXPECT_EQ(send_window, sender_->AvailableSendWindow());
373 // Send a data packet with retransmittable data, and ensure that the
374 // congestion window has shrunk.
375 sender_->OnPacketSent(clock_.Now(), sequence_number_++, bytes_in_packet,
376 NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
377 EXPECT_GT(send_window, sender_->AvailableSendWindow());
380 TEST_F(TcpCubicSenderTest, ConfigureMaxInitialWindow) {
381 QuicTcpCongestionWindow congestion_window = sender_->congestion_window();
383 config.set_server_initial_congestion_window(2 * congestion_window,
384 2 * congestion_window);
385 EXPECT_EQ(2 * congestion_window, config.server_initial_congestion_window());
387 sender_->SetFromConfig(config, true);
388 EXPECT_EQ(2 * congestion_window, sender_->congestion_window());