From 6328acffd73afede64fd19bff3d1e69707e54fc6 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Wed, 22 Jul 2020 13:56:08 +0700 Subject: [PATCH] remove the N connection simulation from the Reno code --- internal/congestion/cubic_sender.go | 36 +++----------- internal/congestion/cubic_sender_test.go | 62 ------------------------ 2 files changed, 8 insertions(+), 90 deletions(-) diff --git a/internal/congestion/cubic_sender.go b/internal/congestion/cubic_sender.go index 7afa0531e..d2a3e49a2 100644 --- a/internal/congestion/cubic_sender.go +++ b/internal/congestion/cubic_sender.go @@ -10,12 +10,12 @@ import ( const ( // maxDatagramSize is the default maximum packet size used in the Linux TCP implementation. // Used in QUIC for congestion window computations in bytes. - maxDatagramSize = protocol.ByteCount(protocol.MaxPacketSizeIPv4) - maxBurstBytes = 3 * maxDatagramSize - renoBeta float32 = 0.7 // Reno backoff factor. - maxCongestionWindow = protocol.MaxCongestionWindowPackets * maxDatagramSize - minCongestionWindow = 2 * maxDatagramSize - initialCongestionWindow = 32 * maxDatagramSize + maxDatagramSize = protocol.ByteCount(protocol.MaxPacketSizeIPv4) + maxBurstBytes = 3 * maxDatagramSize + renoBeta = 0.7 // Reno backoff factor. + maxCongestionWindow = protocol.MaxCongestionWindowPackets * maxDatagramSize + minCongestionWindow = 2 * maxDatagramSize + initialCongestionWindow = 32 * maxDatagramSize ) type cubicSender struct { @@ -52,9 +52,6 @@ type cubicSender struct { // Slow start congestion window in bytes, aka ssthresh. slowStartThreshold protocol.ByteCount - // Number of connections to simulate. - numConnections int - // ACK counter for the Reno implementation. numAckedPackets uint64 @@ -82,7 +79,6 @@ func newCubicSender(clock Clock, rttStats *RTTStats, reno bool, initialCongestio minCongestionWindow: minCongestionWindow, slowStartThreshold: initialMaxCongestionWindow, maxCongestionWindow: initialMaxCongestionWindow, - numConnections: defaultNumConnections, cubic: NewCubic(clock), clock: clock, reno: reno, @@ -167,7 +163,7 @@ func (c *cubicSender) OnPacketLost( c.lastCutbackExitedSlowstart = c.InSlowStart() if c.reno { - c.congestionWindow = protocol.ByteCount(float32(c.congestionWindow) * c.renoBeta()) + c.congestionWindow = protocol.ByteCount(float64(c.congestionWindow) * renoBeta) } else { c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow) } @@ -181,14 +177,6 @@ func (c *cubicSender) OnPacketLost( c.numAckedPackets = 0 } -func (c *cubicSender) renoBeta() float32 { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (float32(c.numConnections) - 1. + renoBeta) / float32(c.numConnections) -} - // Called when we receive an ack. Normal TCP tracks how many packets one ack // represents, but quic has a separate ack for each packet. func (c *cubicSender) maybeIncreaseCwnd( @@ -215,9 +203,7 @@ func (c *cubicSender) maybeIncreaseCwnd( if c.reno { // Classic Reno congestion avoidance. c.numAckedPackets++ - // Divide by num_connections to smoothly increase the CWND at a faster - // rate than conventional Reno. - if c.numAckedPackets*uint64(c.numConnections) >= uint64(c.congestionWindow)/uint64(maxDatagramSize) { + if c.numAckedPackets >= uint64(c.congestionWindow/maxDatagramSize) { c.congestionWindow += maxDatagramSize c.numAckedPackets = 0 } @@ -246,12 +232,6 @@ func (c *cubicSender) BandwidthEstimate() Bandwidth { return BandwidthFromDelta(c.GetCongestionWindow(), srtt) } -// SetNumEmulatedConnections sets the number of emulated connections -func (c *cubicSender) SetNumEmulatedConnections(n int) { - c.numConnections = utils.Max(n, 1) - c.cubic.SetNumConnections(c.numConnections) -} - // OnRetransmissionTimeout is called on an retransmission timeout func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) { c.largestSentAtLastCutback = protocol.InvalidPacketNumber diff --git a/internal/congestion/cubic_sender_test.go b/internal/congestion/cubic_sender_test.go index 6b1acbe4f..088dd158e 100644 --- a/internal/congestion/cubic_sender_test.go +++ b/internal/congestion/cubic_sender_test.go @@ -145,7 +145,6 @@ var _ = Describe("Cubic Sender", func() { }) It("slow start packet loss", func() { - sender.SetNumEmulatedConnections(1) const numberOfAcks = 10 for i := 0; i < numberOfAcks; i++ { // Send our full send window. @@ -188,7 +187,6 @@ var _ = Describe("Cubic Sender", func() { }) It("slow start packet loss PRR", func() { - sender.SetNumEmulatedConnections(1) // Test based on the first example in RFC6937. // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example. const numberOfAcks = 5 @@ -235,7 +233,6 @@ var _ = Describe("Cubic Sender", func() { }) It("slow start burst packet loss PRR", func() { - sender.SetNumEmulatedConnections(1) // Test based on the second example in RFC6937, though we also implement // forward acknowledgements, so the first two incoming acks will trigger // PRR immediately. @@ -364,63 +361,7 @@ var _ = Describe("Cubic Sender", func() { Expect(postLossWindow).To(BeNumerically(">", sender.GetCongestionWindow())) }) - It("2 connection congestion avoidance at end of recovery", func() { - sender.SetNumEmulatedConnections(2) - // Ack 10 packets in 5 acks to raise the CWND to 20. - const numberOfAcks = 5 - for i := 0; i < numberOfAcks; i++ { - // Send our full send window. - SendAvailableSendWindow() - AckNPackets(2) - } - SendAvailableSendWindow() - expectedSendWindow := defaultWindowTCP + (maxDatagramSize * 2 * numberOfAcks) - Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) - - LoseNPackets(1) - - // We should now have fallen out of slow start with a reduced window. - expectedSendWindow = protocol.ByteCount(float32(expectedSendWindow) * sender.renoBeta()) - Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) - - // No congestion window growth should occur in recovery phase, i.e., until the - // currently outstanding 20 packets are acked. - for i := 0; i < 10; i++ { - // Send our full send window. - SendAvailableSendWindow() - Expect(sender.InRecovery()).To(BeTrue()) - AckNPackets(2) - Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) - } - Expect(sender.InRecovery()).To(BeFalse()) - - // Out of recovery now. Congestion window should not grow for half an RTT. - packetsInSendWindow := expectedSendWindow / maxDatagramSize - SendAvailableSendWindow() - AckNPackets(int(packetsInSendWindow/2 - 2)) - Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) - - // Next ack should increase congestion window by 1MSS. - SendAvailableSendWindow() - AckNPackets(2) - expectedSendWindow += maxDatagramSize - packetsInSendWindow++ - Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) - - // Congestion window should remain steady again for half an RTT. - SendAvailableSendWindow() - AckNPackets(int(packetsInSendWindow/2 - 1)) - Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) - - // Next ack should cause congestion window to grow by 1MSS. - SendAvailableSendWindow() - AckNPackets(2) - expectedSendWindow += maxDatagramSize - Expect(sender.GetCongestionWindow()).To(Equal(expectedSendWindow)) - }) - It("1 connection congestion avoidance at end of recovery", func() { - sender.SetNumEmulatedConnections(1) // Ack 10 packets in 5 acks to raise the CWND to 20. const numberOfAcks = 5 for i := 0; i < numberOfAcks; i++ { @@ -465,8 +406,6 @@ var _ = Describe("Cubic Sender", func() { }) It("no PRR", func() { - sender.SetNumEmulatedConnections(1) - SendAvailableSendWindow() LoseNPackets(9) AckNPackets(1) @@ -482,7 +421,6 @@ var _ = Describe("Cubic Sender", func() { Expect(sender.slowStartThreshold).To(Equal(MaxCongestionWindow)) // Starts with slow start. - sender.SetNumEmulatedConnections(1) const numberOfAcks = 10 for i := 0; i < numberOfAcks; i++ { // Send our full send window.