forked from quic-go/quic-go
Merge pull request #2682 from lucas-clemente/remove-reno-n-connection-simulation
remove the N connection simulation from the Reno code
This commit is contained in:
@@ -10,12 +10,12 @@ import (
|
|||||||
const (
|
const (
|
||||||
// maxDatagramSize is the default maximum packet size used in the Linux TCP implementation.
|
// maxDatagramSize is the default maximum packet size used in the Linux TCP implementation.
|
||||||
// Used in QUIC for congestion window computations in bytes.
|
// Used in QUIC for congestion window computations in bytes.
|
||||||
maxDatagramSize = protocol.ByteCount(protocol.MaxPacketSizeIPv4)
|
maxDatagramSize = protocol.ByteCount(protocol.MaxPacketSizeIPv4)
|
||||||
maxBurstBytes = 3 * maxDatagramSize
|
maxBurstBytes = 3 * maxDatagramSize
|
||||||
renoBeta float32 = 0.7 // Reno backoff factor.
|
renoBeta = 0.7 // Reno backoff factor.
|
||||||
maxCongestionWindow = protocol.MaxCongestionWindowPackets * maxDatagramSize
|
maxCongestionWindow = protocol.MaxCongestionWindowPackets * maxDatagramSize
|
||||||
minCongestionWindow = 2 * maxDatagramSize
|
minCongestionWindow = 2 * maxDatagramSize
|
||||||
initialCongestionWindow = 32 * maxDatagramSize
|
initialCongestionWindow = 32 * maxDatagramSize
|
||||||
)
|
)
|
||||||
|
|
||||||
type cubicSender struct {
|
type cubicSender struct {
|
||||||
@@ -52,9 +52,6 @@ type cubicSender struct {
|
|||||||
// Slow start congestion window in bytes, aka ssthresh.
|
// Slow start congestion window in bytes, aka ssthresh.
|
||||||
slowStartThreshold protocol.ByteCount
|
slowStartThreshold protocol.ByteCount
|
||||||
|
|
||||||
// Number of connections to simulate.
|
|
||||||
numConnections int
|
|
||||||
|
|
||||||
// ACK counter for the Reno implementation.
|
// ACK counter for the Reno implementation.
|
||||||
numAckedPackets uint64
|
numAckedPackets uint64
|
||||||
|
|
||||||
@@ -82,7 +79,6 @@ func newCubicSender(clock Clock, rttStats *RTTStats, reno bool, initialCongestio
|
|||||||
minCongestionWindow: minCongestionWindow,
|
minCongestionWindow: minCongestionWindow,
|
||||||
slowStartThreshold: initialMaxCongestionWindow,
|
slowStartThreshold: initialMaxCongestionWindow,
|
||||||
maxCongestionWindow: initialMaxCongestionWindow,
|
maxCongestionWindow: initialMaxCongestionWindow,
|
||||||
numConnections: defaultNumConnections,
|
|
||||||
cubic: NewCubic(clock),
|
cubic: NewCubic(clock),
|
||||||
clock: clock,
|
clock: clock,
|
||||||
reno: reno,
|
reno: reno,
|
||||||
@@ -167,7 +163,7 @@ func (c *cubicSender) OnPacketLost(
|
|||||||
c.lastCutbackExitedSlowstart = c.InSlowStart()
|
c.lastCutbackExitedSlowstart = c.InSlowStart()
|
||||||
|
|
||||||
if c.reno {
|
if c.reno {
|
||||||
c.congestionWindow = protocol.ByteCount(float32(c.congestionWindow) * c.renoBeta())
|
c.congestionWindow = protocol.ByteCount(float64(c.congestionWindow) * renoBeta)
|
||||||
} else {
|
} else {
|
||||||
c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow)
|
c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow)
|
||||||
}
|
}
|
||||||
@@ -181,14 +177,6 @@ func (c *cubicSender) OnPacketLost(
|
|||||||
c.numAckedPackets = 0
|
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
|
// Called when we receive an ack. Normal TCP tracks how many packets one ack
|
||||||
// represents, but quic has a separate ack for each packet.
|
// represents, but quic has a separate ack for each packet.
|
||||||
func (c *cubicSender) maybeIncreaseCwnd(
|
func (c *cubicSender) maybeIncreaseCwnd(
|
||||||
@@ -215,9 +203,7 @@ func (c *cubicSender) maybeIncreaseCwnd(
|
|||||||
if c.reno {
|
if c.reno {
|
||||||
// Classic Reno congestion avoidance.
|
// Classic Reno congestion avoidance.
|
||||||
c.numAckedPackets++
|
c.numAckedPackets++
|
||||||
// Divide by num_connections to smoothly increase the CWND at a faster
|
if c.numAckedPackets >= uint64(c.congestionWindow/maxDatagramSize) {
|
||||||
// rate than conventional Reno.
|
|
||||||
if c.numAckedPackets*uint64(c.numConnections) >= uint64(c.congestionWindow)/uint64(maxDatagramSize) {
|
|
||||||
c.congestionWindow += maxDatagramSize
|
c.congestionWindow += maxDatagramSize
|
||||||
c.numAckedPackets = 0
|
c.numAckedPackets = 0
|
||||||
}
|
}
|
||||||
@@ -246,12 +232,6 @@ func (c *cubicSender) BandwidthEstimate() Bandwidth {
|
|||||||
return BandwidthFromDelta(c.GetCongestionWindow(), srtt)
|
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
|
// OnRetransmissionTimeout is called on an retransmission timeout
|
||||||
func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) {
|
func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) {
|
||||||
c.largestSentAtLastCutback = protocol.InvalidPacketNumber
|
c.largestSentAtLastCutback = protocol.InvalidPacketNumber
|
||||||
|
|||||||
@@ -145,7 +145,6 @@ var _ = Describe("Cubic Sender", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("slow start packet loss", func() {
|
It("slow start packet loss", func() {
|
||||||
sender.SetNumEmulatedConnections(1)
|
|
||||||
const numberOfAcks = 10
|
const numberOfAcks = 10
|
||||||
for i := 0; i < numberOfAcks; i++ {
|
for i := 0; i < numberOfAcks; i++ {
|
||||||
// Send our full send window.
|
// Send our full send window.
|
||||||
@@ -188,7 +187,6 @@ var _ = Describe("Cubic Sender", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("slow start packet loss PRR", func() {
|
It("slow start packet loss PRR", func() {
|
||||||
sender.SetNumEmulatedConnections(1)
|
|
||||||
// Test based on the first example in RFC6937.
|
// Test based on the first example in RFC6937.
|
||||||
// Ack 10 packets in 5 acks to raise the CWND to 20, as in the example.
|
// Ack 10 packets in 5 acks to raise the CWND to 20, as in the example.
|
||||||
const numberOfAcks = 5
|
const numberOfAcks = 5
|
||||||
@@ -235,7 +233,6 @@ var _ = Describe("Cubic Sender", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("slow start burst packet loss PRR", func() {
|
It("slow start burst packet loss PRR", func() {
|
||||||
sender.SetNumEmulatedConnections(1)
|
|
||||||
// Test based on the second example in RFC6937, though we also implement
|
// Test based on the second example in RFC6937, though we also implement
|
||||||
// forward acknowledgements, so the first two incoming acks will trigger
|
// forward acknowledgements, so the first two incoming acks will trigger
|
||||||
// PRR immediately.
|
// PRR immediately.
|
||||||
@@ -364,63 +361,7 @@ var _ = Describe("Cubic Sender", func() {
|
|||||||
Expect(postLossWindow).To(BeNumerically(">", sender.GetCongestionWindow()))
|
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() {
|
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.
|
// Ack 10 packets in 5 acks to raise the CWND to 20.
|
||||||
const numberOfAcks = 5
|
const numberOfAcks = 5
|
||||||
for i := 0; i < numberOfAcks; i++ {
|
for i := 0; i < numberOfAcks; i++ {
|
||||||
@@ -465,8 +406,6 @@ var _ = Describe("Cubic Sender", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("no PRR", func() {
|
It("no PRR", func() {
|
||||||
sender.SetNumEmulatedConnections(1)
|
|
||||||
|
|
||||||
SendAvailableSendWindow()
|
SendAvailableSendWindow()
|
||||||
LoseNPackets(9)
|
LoseNPackets(9)
|
||||||
AckNPackets(1)
|
AckNPackets(1)
|
||||||
@@ -482,7 +421,6 @@ var _ = Describe("Cubic Sender", func() {
|
|||||||
Expect(sender.slowStartThreshold).To(Equal(MaxCongestionWindow))
|
Expect(sender.slowStartThreshold).To(Equal(MaxCongestionWindow))
|
||||||
|
|
||||||
// Starts with slow start.
|
// Starts with slow start.
|
||||||
sender.SetNumEmulatedConnections(1)
|
|
||||||
const numberOfAcks = 10
|
const numberOfAcks = 10
|
||||||
for i := 0; i < numberOfAcks; i++ {
|
for i := 0; i < numberOfAcks; i++ {
|
||||||
// Send our full send window.
|
// Send our full send window.
|
||||||
|
|||||||
Reference in New Issue
Block a user