| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/quic/congestion_control/inter_arrival_sender.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/stl_util.h" |
| #include "net/quic/test_tools/mock_clock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using std::pair; |
| |
| namespace net { |
| namespace test { |
| |
| class InterArrivalSenderTest : public ::testing::Test { |
| protected: |
| InterArrivalSenderTest() |
| : rtt_(QuicTime::Delta::FromMilliseconds(60)), |
| one_ms_(QuicTime::Delta::FromMilliseconds(1)), |
| one_s_(QuicTime::Delta::FromMilliseconds(1000)), |
| nine_ms_(QuicTime::Delta::FromMilliseconds(9)), |
| send_start_time_(send_clock_.Now()), |
| sender_(&send_clock_), |
| sequence_number_(1), |
| acked_sequence_number_(1), |
| feedback_sequence_number_(1) { |
| send_clock_.AdvanceTime(one_ms_); |
| receive_clock_.AdvanceTime(one_ms_); |
| } |
| |
| virtual ~InterArrivalSenderTest() { |
| STLDeleteValues(&sent_packets_); |
| } |
| |
| void SendAvailableCongestionWindow() { |
| while (sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()) { |
| QuicByteCount bytes_in_packet = kDefaultMaxPacketSize; |
| sent_packets_[sequence_number_] = |
| new class SendAlgorithmInterface::SentPacket( |
| bytes_in_packet, send_clock_.Now(), HAS_RETRANSMITTABLE_DATA); |
| |
| sender_.OnPacketSent(send_clock_.Now(), sequence_number_, bytes_in_packet, |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA); |
| sequence_number_++; |
| } |
| EXPECT_FALSE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| } |
| |
| void AckNPackets(int n) { |
| for (int i = 0; i < n; ++i) { |
| sender_.OnPacketAcked( |
| acked_sequence_number_++, kDefaultMaxPacketSize, rtt_); |
| } |
| } |
| |
| void SendDelaySpikeFeedbackMessage(QuicTime::Delta spike_time) { |
| QuicCongestionFeedbackFrame feedback; |
| feedback.type = kInterArrival; |
| feedback.inter_arrival.accumulated_number_of_lost_packets = 0; |
| receive_clock_.AdvanceTime(spike_time); |
| QuicTime receive_time = receive_clock_.ApproximateNow(); |
| feedback.inter_arrival.received_packet_times.insert( |
| pair<QuicPacketSequenceNumber, QuicTime>( |
| feedback_sequence_number_, receive_time)); |
| feedback_sequence_number_++; |
| |
| // We need to send feedback for 2 packets since they where sent at the |
| // same time. |
| feedback.inter_arrival.received_packet_times.insert( |
| pair<QuicPacketSequenceNumber, QuicTime>( |
| feedback_sequence_number_, receive_time)); |
| feedback_sequence_number_++; |
| |
| sender_.OnIncomingQuicCongestionFeedbackFrame(feedback, send_clock_.Now(), |
| sent_packets_); |
| } |
| |
| void SendFeedbackMessageNPackets(int n, |
| QuicTime::Delta delta_odd, |
| QuicTime::Delta delta_even) { |
| QuicCongestionFeedbackFrame feedback; |
| feedback.type = kInterArrival; |
| feedback.inter_arrival.accumulated_number_of_lost_packets = 0; |
| for (int i = 0; i < n; ++i) { |
| if (feedback_sequence_number_ % 2) { |
| receive_clock_.AdvanceTime(delta_even); |
| } else { |
| receive_clock_.AdvanceTime(delta_odd); |
| } |
| QuicTime receive_time = receive_clock_.ApproximateNow(); |
| feedback.inter_arrival.received_packet_times.insert( |
| pair<QuicPacketSequenceNumber, QuicTime>( |
| feedback_sequence_number_, receive_time)); |
| feedback_sequence_number_++; |
| } |
| sender_.OnIncomingQuicCongestionFeedbackFrame(feedback, send_clock_.Now(), |
| sent_packets_); |
| } |
| |
| QuicTime::Delta SenderDeltaSinceStart() { |
| return send_clock_.ApproximateNow().Subtract(send_start_time_); |
| } |
| |
| const QuicTime::Delta rtt_; |
| const QuicTime::Delta one_ms_; |
| const QuicTime::Delta one_s_; |
| const QuicTime::Delta nine_ms_; |
| MockClock send_clock_; |
| MockClock receive_clock_; |
| const QuicTime send_start_time_; |
| InterArrivalSender sender_; |
| QuicPacketSequenceNumber sequence_number_; |
| QuicPacketSequenceNumber acked_sequence_number_; |
| QuicPacketSequenceNumber feedback_sequence_number_; |
| SendAlgorithmInterface::SentPacketsMap sent_packets_; |
| }; |
| |
| TEST_F(InterArrivalSenderTest, ProbeFollowedByFullRampUpCycle) { |
| QuicCongestionFeedbackFrame feedback; |
| // At startup make sure we can send. |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| // Send 5 bursts. |
| for (int i = 0; i < 4; ++i) { |
| SendAvailableCongestionWindow(); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| } |
| SendAvailableCongestionWindow(); |
| |
| // We have now sent our probe. |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION, |
| HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsInfinite()); |
| |
| AckNPackets(10); |
| SendFeedbackMessageNPackets(10, one_ms_, nine_ms_); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| // We should now have our probe rate. |
| QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41); |
| int64 probe_rate = kDefaultMaxPacketSize * 9 * kNumMicrosPerSecond / |
| acc_arrival_time.ToMicroseconds(); |
| EXPECT_NEAR(0.7f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| DLOG(INFO) << "After probe"; |
| // Send 50 bursts, make sure that we move fast in the beginning. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(0.875f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 600, 10); |
| |
| // Send 50 bursts, make sure that we slow down towards the probe rate. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(0.95f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 1100, 10); |
| |
| // Send 50 bursts, make sure that we move very slow close to the probe rate. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(0.99f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 1560, 10); |
| DLOG(INFO) << "Near available channel estimate"; |
| |
| // Send 50 bursts, make sure that we move very slow close to the probe rate. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(1.00f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 2000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 2000, 100); |
| DLOG(INFO) << "At available channel estimate"; |
| |
| // Send 50 bursts, make sure that we move very slow close to the probe rate. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(1.01f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 2000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 2500, 100); |
| |
| // Send 50 bursts, make sure that we accelerate after the probe rate. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(1.01f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 2000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 2900, 100); |
| |
| // Send 50 bursts, make sure that we accelerate after the probe rate. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(1.03f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 2000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 3400, 100); |
| |
| int64 max_rate = kDefaultMaxPacketSize * kNumMicrosPerSecond / |
| one_ms_.ToMicroseconds(); |
| |
| int64 halfway_rate = probe_rate + (max_rate - probe_rate) / 2; |
| |
| // Send until we reach halfway point. |
| for (int i = 0; i < 570; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(halfway_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 5000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 6600, 100); |
| DLOG(INFO) << "Near halfway point"; |
| |
| // Send until we reach max channel capacity. |
| for (int i = 0; i < 1500; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(max_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 5000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 10000, 200); |
| } |
| |
| TEST_F(InterArrivalSenderTest, DelaySpikeFollowedBySlowDrain) { |
| QuicCongestionFeedbackFrame feedback; |
| // At startup make sure we can send. |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| // Send 5 bursts. |
| for (int i = 0; i < 4; ++i) { |
| SendAvailableCongestionWindow(); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| } |
| SendAvailableCongestionWindow(); |
| |
| // We have now sent our probe. |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION, |
| HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsInfinite()); |
| |
| AckNPackets(10); |
| SendFeedbackMessageNPackets(10, one_ms_, nine_ms_); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| // We should now have our probe rate. |
| QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41); |
| int64 probe_rate = kDefaultMaxPacketSize * 9 * kNumMicrosPerSecond / |
| acc_arrival_time.ToMicroseconds(); |
| EXPECT_NEAR(0.7f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| |
| // Send 50 bursts, make sure that we move fast in the beginning. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(0.875f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 600, 10); |
| |
| SendAvailableCongestionWindow(); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| |
| int64 rate_at_introduced_delay_spike = 0.875f * probe_rate; |
| QuicTime::Delta spike_time = QuicTime::Delta::FromMilliseconds(100); |
| SendDelaySpikeFeedbackMessage(spike_time); |
| |
| // Backing as much as we can, currently 90%. |
| EXPECT_NEAR(0.1f * rate_at_introduced_delay_spike, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 610, 10); |
| |
| // Run until we are catched up after our introduced delay spike. |
| while (send_clock_.Now() < receive_clock_.Now()) { |
| SendAvailableCongestionWindow(); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, one_ms_); |
| } |
| // Expect that we go back to 67% of the rate before the spike. |
| EXPECT_NEAR(0.67f * rate_at_introduced_delay_spike, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 820, 10); |
| |
| // Send 100 bursts, make sure that we slow down towards the rate we had |
| // before the spike. |
| for (int i = 0; i < 100; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(0.97f * rate_at_introduced_delay_spike, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 2100, 10); |
| } |
| |
| TEST_F(InterArrivalSenderTest, DelaySpikeFollowedByImmediateDrain) { |
| QuicCongestionFeedbackFrame feedback; |
| // At startup make sure we can send. |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| // Send 5 bursts. |
| for (int i = 0; i < 4; ++i) { |
| SendAvailableCongestionWindow(); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| } |
| SendAvailableCongestionWindow(); |
| |
| // We have now sent our probe. |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), NOT_RETRANSMISSION, |
| HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsInfinite()); |
| |
| AckNPackets(10); |
| SendFeedbackMessageNPackets(10, one_ms_, nine_ms_); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| // We should now have our probe rate. |
| QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(41); |
| int64 probe_rate = kDefaultMaxPacketSize * 9 * kNumMicrosPerSecond / |
| acc_arrival_time.ToMicroseconds(); |
| EXPECT_NEAR(0.7f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| |
| // Send 50 bursts, make sure that we move fast in the beginning. |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, time_until_send.Subtract(one_ms_)); |
| } |
| EXPECT_NEAR(0.875f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 600, 10); |
| |
| SendAvailableCongestionWindow(); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| AckNPackets(2); |
| |
| int64 rate_at_introduced_delay_spike = 0.875f * probe_rate; |
| QuicTime::Delta spike_time = QuicTime::Delta::FromMilliseconds(100); |
| SendDelaySpikeFeedbackMessage(spike_time); |
| |
| // Backing as much as we can, currently 90%. |
| EXPECT_NEAR(0.1f * rate_at_introduced_delay_spike, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 610, 10); |
| |
| // Move send time forward. |
| send_clock_.AdvanceTime(spike_time); |
| // Make sure our clocks are aligned again. |
| receive_clock_.AdvanceTime(send_clock_.Now().Subtract(receive_clock_.Now())); |
| |
| SendAvailableCongestionWindow(); |
| AckNPackets(2); |
| SendFeedbackMessageNPackets(2, one_ms_, one_ms_); |
| // We should now be back where we introduced the delay spike. |
| EXPECT_NEAR(rate_at_introduced_delay_spike, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| EXPECT_NEAR(SenderDeltaSinceStart().ToMilliseconds(), 710, 10); |
| } |
| |
| TEST_F(InterArrivalSenderTest, MinBitrateDueToDelay) { |
| QuicBandwidth expected_min_bitrate = QuicBandwidth::FromKBitsPerSecond(10); |
| QuicCongestionFeedbackFrame feedback; |
| // At startup make sure we can send. |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| // Send 5 bursts. |
| for (int i = 0; i < 4; ++i) { |
| SendAvailableCongestionWindow(); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| } |
| SendAvailableCongestionWindow(); |
| |
| AckNPackets(10); |
| |
| // One second spread per packet is expected to result in an estimate at |
| // our minimum bitrate. |
| SendFeedbackMessageNPackets(10, one_s_, one_s_); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| EXPECT_EQ(expected_min_bitrate, sender_.BandwidthEstimate()); |
| } |
| |
| TEST_F(InterArrivalSenderTest, MinBitrateDueToLoss) { |
| QuicBandwidth expected_min_bitrate = QuicBandwidth::FromKBitsPerSecond(10); |
| QuicCongestionFeedbackFrame feedback; |
| // At startup make sure we can send. |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| // Send 5 bursts. |
| for (int i = 0; i < 4; ++i) { |
| SendAvailableCongestionWindow(); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| } |
| SendAvailableCongestionWindow(); |
| |
| AckNPackets(10); |
| SendFeedbackMessageNPackets(10, nine_ms_, nine_ms_); |
| send_clock_.AdvanceTime(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE)); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| |
| QuicTime::Delta acc_arrival_time = QuicTime::Delta::FromMilliseconds(81); |
| int64 probe_rate = kDefaultMaxPacketSize * 9 * kNumMicrosPerSecond / |
| acc_arrival_time.ToMicroseconds(); |
| EXPECT_NEAR(0.7f * probe_rate, |
| sender_.BandwidthEstimate().ToBytesPerSecond(), 1000); |
| |
| for (int i = 0; i < 15; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| sender_.OnPacketLost(acked_sequence_number_ - 1, send_clock_.Now()); |
| sender_.OnPacketAcked(acked_sequence_number_, kDefaultMaxPacketSize, rtt_); |
| acked_sequence_number_ += 2; // Create a loss by not acking both packets. |
| SendFeedbackMessageNPackets(2, nine_ms_, nine_ms_); |
| } |
| // Test that our exponentail back off stop at expected_min_bitrate. |
| EXPECT_EQ(expected_min_bitrate, sender_.BandwidthEstimate()); |
| |
| for (int i = 0; i < 50; ++i) { |
| SendAvailableCongestionWindow(); |
| QuicTime::Delta time_until_send = sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE); |
| send_clock_.AdvanceTime(time_until_send); |
| EXPECT_TRUE(sender_.TimeUntilSend(send_clock_.Now(), |
| NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA, NOT_HANDSHAKE).IsZero()); |
| sender_.OnPacketLost(acked_sequence_number_ - 1, send_clock_.Now()); |
| sender_.OnPacketAcked(acked_sequence_number_, kDefaultMaxPacketSize, rtt_); |
| acked_sequence_number_ += 2; // Create a loss by not acking both packets. |
| SendFeedbackMessageNPackets(2, nine_ms_, nine_ms_); |
| |
| // Make sure our bitrate is fixed at the expected_min_bitrate. |
| EXPECT_EQ(expected_min_bitrate, sender_.BandwidthEstimate()); |
| } |
| } |
| |
| } // namespace test |
| } // namespace net |