diff --git a/internal/congestion/cubic_sender.go b/internal/congestion/cubic_sender.go index 074ed667..a2b3f940 100644 --- a/internal/congestion/cubic_sender.go +++ b/internal/congestion/cubic_sender.go @@ -20,13 +20,11 @@ const ( type cubicSender struct { hybridSlowStart HybridSlowStart - prr PrrSender rttStats *RTTStats stats connectionStats cubic *Cubic - noPRR bool - reno bool + reno bool // Track the largest packet that has been sent. largestSentPacketNumber protocol.PacketNumber @@ -96,12 +94,6 @@ func newCubicSender(clock Clock, rttStats *RTTStats, reno bool, initialCongestio // TimeUntilSend returns when the next packet should be sent. func (c *cubicSender) TimeUntilSend(bytesInFlight protocol.ByteCount) time.Duration { - if !c.noPRR && c.InRecovery() { - // PRR is used when in recovery. - if c.prr.CanSend(c.GetCongestionWindow(), bytesInFlight, c.GetSlowStartThreshold()) { - return 0 - } - } return c.rttStats.SmoothedRTT() * time.Duration(maxDatagramSize) / time.Duration(2*c.GetCongestionWindow()) } @@ -115,18 +107,11 @@ func (c *cubicSender) OnPacketSent( if !isRetransmittable { return } - if c.InRecovery() { - // PRR is used when in recovery. - c.prr.OnPacketSent(bytes) - } c.largestSentPacketNumber = packetNumber c.hybridSlowStart.OnPacketSent(packetNumber) } func (c *cubicSender) CanSend(bytesInFlight protocol.ByteCount) bool { - if !c.noPRR && c.InRecovery() { - return c.prr.CanSend(c.GetCongestionWindow(), bytesInFlight, c.GetSlowStartThreshold()) - } return bytesInFlight < c.GetCongestionWindow() } @@ -168,10 +153,6 @@ func (c *cubicSender) OnPacketAcked( ) { c.largestAckedPacketNumber = utils.MaxPacketNumber(ackedPacketNumber, c.largestAckedPacketNumber) if c.InRecovery() { - // PRR is used when in recovery. - if !c.noPRR { - c.prr.OnPacketAcked(ackedBytes) - } return } c.maybeIncreaseCwnd(ackedPacketNumber, ackedBytes, priorInFlight, eventTime) @@ -204,10 +185,6 @@ func (c *cubicSender) OnPacketLost( c.stats.slowstartPacketsLost++ } - if !c.noPRR { - c.prr.OnPacketLost(priorInFlight) - } - // TODO(chromium): Separate out all of slow start into a separate class. if c.slowStartLargeReduction && c.InSlowStart() { if c.congestionWindow >= 2*c.initialCongestionWindow { @@ -320,7 +297,6 @@ func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) { // OnConnectionMigration is called when the connection is migrated (?) func (c *cubicSender) OnConnectionMigration() { c.hybridSlowStart.Restart() - c.prr = PrrSender{} c.largestSentPacketNumber = protocol.InvalidPacketNumber c.largestAckedPacketNumber = protocol.InvalidPacketNumber c.largestSentAtLastCutback = protocol.InvalidPacketNumber diff --git a/internal/congestion/cubic_sender_test.go b/internal/congestion/cubic_sender_test.go index 1cd46649..21d189cc 100644 --- a/internal/congestion/cubic_sender_test.go +++ b/internal/congestion/cubic_sender_test.go @@ -264,18 +264,6 @@ var _ = Describe("Cubic Sender", func() { Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) }) - It("no PRR when less than one packet in flight", func() { - SendAvailableSendWindow() - LoseNPackets(int(initialCongestionWindowPackets) - 1) - AckNPackets(1) - // PRR will allow 2 packets for every ack during recovery. - Expect(SendAvailableSendWindow()).To(Equal(2)) - // Simulate abandoning all packets by supplying a bytes_in_flight of 0. - // PRR should now allow a packet to be sent, even though prr's state - // variables believe it has sent enough packets. - Expect(sender.CanSend(0)).To(BeTrue()) - }) - It("slow start packet loss PRR", func() { sender.SetNumEmulatedConnections(1) // Test based on the first example in RFC6937. @@ -555,7 +543,6 @@ var _ = Describe("Cubic Sender", func() { It("no PRR", func() { sender.SetNumEmulatedConnections(1) - sender.noPRR = true SendAvailableSendWindow() LoseNPackets(9) diff --git a/internal/congestion/prr_sender.go b/internal/congestion/prr_sender.go deleted file mode 100644 index c095949f..00000000 --- a/internal/congestion/prr_sender.go +++ /dev/null @@ -1,54 +0,0 @@ -package congestion - -import ( - "github.com/lucas-clemente/quic-go/internal/protocol" -) - -// PrrSender implements the Proportional Rate Reduction (PRR) per RFC 6937 -type PrrSender struct { - bytesSentSinceLoss protocol.ByteCount - bytesDeliveredSinceLoss protocol.ByteCount - ackCountSinceLoss protocol.ByteCount - bytesInFlightBeforeLoss protocol.ByteCount -} - -// OnPacketSent should be called after a packet was sent -func (p *PrrSender) OnPacketSent(sentBytes protocol.ByteCount) { - p.bytesSentSinceLoss += sentBytes -} - -// OnPacketLost should be called on the first loss that triggers a recovery -// period and all other methods in this class should only be called when in -// recovery. -func (p *PrrSender) OnPacketLost(priorInFlight protocol.ByteCount) { - p.bytesSentSinceLoss = 0 - p.bytesInFlightBeforeLoss = priorInFlight - p.bytesDeliveredSinceLoss = 0 - p.ackCountSinceLoss = 0 -} - -// OnPacketAcked should be called after a packet was acked -func (p *PrrSender) OnPacketAcked(ackedBytes protocol.ByteCount) { - p.bytesDeliveredSinceLoss += ackedBytes - p.ackCountSinceLoss++ -} - -// CanSend returns if packets can be sent -func (p *PrrSender) CanSend(congestionWindow, bytesInFlight, slowstartThreshold protocol.ByteCount) bool { - // Return QuicTime::Zero In order to ensure limited transmit always works. - if p.bytesSentSinceLoss == 0 || bytesInFlight < maxDatagramSize { - return true - } - if congestionWindow > bytesInFlight { - // During PRR-SSRB, limit outgoing packets to 1 extra MSS per ack, instead - // of sending the entire available window. This prevents burst retransmits - // when more packets are lost than the CWND reduction. - // limit = MAX(prr_delivered - prr_out, DeliveredData) + MSS - return p.bytesDeliveredSinceLoss+p.ackCountSinceLoss*maxDatagramSize > p.bytesSentSinceLoss - } - // Implement Proportional Rate Reduction (RFC6937). - // Checks a simplified version of the PRR formula that doesn't use division: - // AvailableSendWindow = - // CEIL(prr_delivered * ssthresh / BytesInFlightAtLoss) - prr_sent - return p.bytesDeliveredSinceLoss*slowstartThreshold > p.bytesSentSinceLoss*p.bytesInFlightBeforeLoss -} diff --git a/internal/congestion/prr_sender_test.go b/internal/congestion/prr_sender_test.go deleted file mode 100644 index 4893517b..00000000 --- a/internal/congestion/prr_sender_test.go +++ /dev/null @@ -1,107 +0,0 @@ -package congestion - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "github.com/lucas-clemente/quic-go/internal/protocol" -) - -var _ = Describe("PRR sender", func() { - var ( - prr PrrSender - ) - - BeforeEach(func() { - prr = PrrSender{} - }) - - It("single loss results in send on every other ack", func() { - numPacketsInFlight := protocol.ByteCount(50) - bytesInFlight := numPacketsInFlight * maxDatagramSize - sshthreshAfterLoss := numPacketsInFlight / 2 - congestionWindow := sshthreshAfterLoss * maxDatagramSize - - prr.OnPacketLost(bytesInFlight) - // Ack a packet. PRR allows one packet to leave immediately. - prr.OnPacketAcked(maxDatagramSize) - bytesInFlight -= maxDatagramSize - Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*maxDatagramSize)).To(BeTrue()) - // Send retransmission. - prr.OnPacketSent(maxDatagramSize) - // PRR shouldn't allow sending any more packets. - Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*maxDatagramSize)).To(BeFalse()) - - // One packet is lost, and one ack was consumed above. PRR now paces - // transmissions through the remaining 48 acks. PRR will alternatively - // disallow and allow a packet to be sent in response to an ack. - for i := protocol.ByteCount(0); i < sshthreshAfterLoss-1; i++ { - // Ack a packet. PRR shouldn't allow sending a packet in response. - prr.OnPacketAcked(maxDatagramSize) - bytesInFlight -= maxDatagramSize - Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*maxDatagramSize)).To(BeFalse()) - // Ack another packet. PRR should now allow sending a packet in response. - prr.OnPacketAcked(maxDatagramSize) - bytesInFlight -= maxDatagramSize - Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*maxDatagramSize)).To(BeTrue()) - // Send a packet in response. - prr.OnPacketSent(maxDatagramSize) - bytesInFlight += maxDatagramSize - } - - // Since bytes_in_flight is now equal to congestion_window, PRR now maintains - // packet conservation, allowing one packet to be sent in response to an ack. - Expect(bytesInFlight).To(Equal(congestionWindow)) - for i := 0; i < 10; i++ { - // Ack a packet. - prr.OnPacketAcked(maxDatagramSize) - bytesInFlight -= maxDatagramSize - Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*maxDatagramSize)).To(BeTrue()) - // Send a packet in response, since PRR allows it. - prr.OnPacketSent(maxDatagramSize) - bytesInFlight += maxDatagramSize - - // Since bytes_in_flight is equal to the congestion_window, - // PRR disallows sending. - Expect(bytesInFlight).To(Equal(congestionWindow)) - Expect(prr.CanSend(congestionWindow, bytesInFlight, sshthreshAfterLoss*maxDatagramSize)).To(BeFalse()) - } - - }) - - It("burst loss results in slow start", func() { - bytesInFlight := 20 * maxDatagramSize - const numPacketsLost = 13 - const ssthreshAfterLoss = 10 - const congestionWindow = ssthreshAfterLoss * maxDatagramSize - - // Lose 13 packets. - bytesInFlight -= numPacketsLost * maxDatagramSize - prr.OnPacketLost(bytesInFlight) - - // PRR-SSRB will allow the following 3 acks to send up to 2 packets. - for i := 0; i < 3; i++ { - prr.OnPacketAcked(maxDatagramSize) - bytesInFlight -= maxDatagramSize - // PRR-SSRB should allow two packets to be sent. - for j := 0; j < 2; j++ { - Expect(prr.CanSend(congestionWindow, bytesInFlight, ssthreshAfterLoss*maxDatagramSize)).To(BeTrue()) - // Send a packet in response. - prr.OnPacketSent(maxDatagramSize) - bytesInFlight += maxDatagramSize - } - // PRR should allow no more than 2 packets in response to an ack. - Expect(prr.CanSend(congestionWindow, bytesInFlight, ssthreshAfterLoss*maxDatagramSize)).To(BeFalse()) - } - - // Out of SSRB mode, PRR allows one send in response to each ack. - for i := 0; i < 10; i++ { - prr.OnPacketAcked(maxDatagramSize) - bytesInFlight -= maxDatagramSize - Expect(prr.CanSend(congestionWindow, bytesInFlight, ssthreshAfterLoss*maxDatagramSize)).To(BeTrue()) - // Send a packet in response. - prr.OnPacketSent(maxDatagramSize) - bytesInFlight += maxDatagramSize - } - }) -})