forked from quic-go/quic-go
fix integer signing bug in cubic
Fixes #402, see https://codereview.chromium.org/2550453002/
This commit is contained in:
@@ -184,9 +184,19 @@ func (c *Cubic) CongestionWindowAfterAck(currentCongestionWindow protocol.Packet
|
|||||||
elapsedTime := int64((currentTime.Add(delayMin).Sub(c.epoch)/time.Microsecond)<<10) / 1000000
|
elapsedTime := int64((currentTime.Add(delayMin).Sub(c.epoch)/time.Microsecond)<<10) / 1000000
|
||||||
|
|
||||||
offset := int64(c.timeToOriginPoint) - elapsedTime
|
offset := int64(c.timeToOriginPoint) - elapsedTime
|
||||||
|
// Right-shifts of negative, signed numbers have
|
||||||
|
// implementation-dependent behavior. Force the offset to be
|
||||||
|
// positive, similar to the kernel implementation.
|
||||||
|
if offset < 0 {
|
||||||
|
offset = -offset
|
||||||
|
}
|
||||||
deltaCongestionWindow := protocol.PacketNumber((cubeCongestionWindowScale * offset * offset * offset) >> cubeScale)
|
deltaCongestionWindow := protocol.PacketNumber((cubeCongestionWindowScale * offset * offset * offset) >> cubeScale)
|
||||||
targetCongestionWindow := c.originPointCongestionWindow - deltaCongestionWindow
|
var targetCongestionWindow protocol.PacketNumber
|
||||||
|
if elapsedTime > int64(c.timeToOriginPoint) {
|
||||||
|
targetCongestionWindow = c.originPointCongestionWindow + deltaCongestionWindow
|
||||||
|
} else {
|
||||||
|
targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow
|
||||||
|
}
|
||||||
// With dynamic beta/alpha based on number of active streams, it is possible
|
// With dynamic beta/alpha based on number of active streams, it is possible
|
||||||
// for the required_ack_count to become much lower than acked_packets_count_
|
// for the required_ack_count to become much lower than acked_packets_count_
|
||||||
// suddenly, leading to more than one iteration through the following loop.
|
// suddenly, leading to more than one iteration through the following loop.
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package congestion
|
package congestion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/lucas-clemente/quic-go/protocol"
|
"github.com/lucas-clemente/quic-go/protocol"
|
||||||
@@ -26,23 +27,37 @@ var _ = Describe("Cubic", func() {
|
|||||||
|
|
||||||
It("works above origin", func() {
|
It("works above origin", func() {
|
||||||
// Convex growth.
|
// Convex growth.
|
||||||
rtt_min := 100 * time.Millisecond
|
const rtt_min = 100 * time.Millisecond
|
||||||
|
const rtt_min_s = float32(rtt_min/time.Millisecond) / 1000.0
|
||||||
current_cwnd := protocol.PacketNumber(10)
|
current_cwnd := protocol.PacketNumber(10)
|
||||||
expected_cwnd := current_cwnd + 1
|
// Without the signed-integer, cubic-convex fix, we mistakenly
|
||||||
|
// increment cwnd after only one_ms_ and a single ack.
|
||||||
|
expected_cwnd := current_cwnd
|
||||||
// Initialize the state.
|
// Initialize the state.
|
||||||
clock.Advance(time.Millisecond)
|
clock.Advance(time.Millisecond)
|
||||||
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(Equal(expected_cwnd))
|
initial_time := clock.Now()
|
||||||
|
current_cwnd = cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)
|
||||||
|
Expect(current_cwnd).To(Equal(expected_cwnd))
|
||||||
current_cwnd = expected_cwnd
|
current_cwnd = expected_cwnd
|
||||||
|
initial_cwnd := current_cwnd
|
||||||
// Normal TCP phase.
|
// Normal TCP phase.
|
||||||
for i := 0; i < 48; i++ {
|
// The maximum number of expected reno RTTs can be calculated by
|
||||||
for n := uint64(1); n < uint64(float32(current_cwnd)/kNConnectionAlpha); n++ {
|
// finding the point where the cubic curve and the reno curve meet.
|
||||||
|
max_reno_rtts := int(math.Sqrt(float64(kNConnectionAlpha/(0.4*rtt_min_s*rtt_min_s*rtt_min_s))) - 1)
|
||||||
|
for i := 0; i < max_reno_rtts; i++ {
|
||||||
|
max_per_ack_cwnd := current_cwnd
|
||||||
|
for n := uint64(1); n < uint64(float32(max_per_ack_cwnd)/kNConnectionAlpha); n++ {
|
||||||
// Call once per ACK.
|
// Call once per ACK.
|
||||||
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(BeNumerically("~", current_cwnd, 1))
|
next_cwnd := cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)
|
||||||
|
Expect(next_cwnd).To(Equal(current_cwnd))
|
||||||
}
|
}
|
||||||
clock.Advance(100 * time.Millisecond)
|
clock.Advance(100 * time.Millisecond)
|
||||||
current_cwnd = cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)
|
current_cwnd = cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)
|
||||||
Expect(current_cwnd).To(BeNumerically("~", expected_cwnd, 1))
|
// When we fix convex mode and the uint64 arithmetic, we
|
||||||
|
// increase the expected_cwnd only after after the first 100ms,
|
||||||
|
// rather than after the initial 1ms.
|
||||||
expected_cwnd++
|
expected_cwnd++
|
||||||
|
Expect(current_cwnd).To(Equal(expected_cwnd))
|
||||||
}
|
}
|
||||||
// Cubic phase.
|
// Cubic phase.
|
||||||
for i := 0; i < 52; i++ {
|
for i := 0; i < 52; i++ {
|
||||||
@@ -54,16 +69,16 @@ var _ = Describe("Cubic", func() {
|
|||||||
current_cwnd = cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)
|
current_cwnd = cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)
|
||||||
}
|
}
|
||||||
// Total time elapsed so far; add min_rtt (0.1s) here as well.
|
// Total time elapsed so far; add min_rtt (0.1s) here as well.
|
||||||
elapsed_time_s := 10.0 + 0.1
|
elapsed_time_s := float32(clock.Now().Sub(initial_time)+rtt_min) / float32(time.Second)
|
||||||
// |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4.
|
// |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4.
|
||||||
expected_cwnd = protocol.PacketNumber(11 + (elapsed_time_s*elapsed_time_s*elapsed_time_s*410)/1024)
|
expected_cwnd = initial_cwnd + protocol.PacketNumber((elapsed_time_s*elapsed_time_s*elapsed_time_s*410)/1024)
|
||||||
Expect(current_cwnd).To(Equal(expected_cwnd))
|
Expect(current_cwnd).To(Equal(expected_cwnd))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("manages loss events", func() {
|
It("manages loss events", func() {
|
||||||
rtt_min := 100 * time.Millisecond
|
rtt_min := 100 * time.Millisecond
|
||||||
current_cwnd := protocol.PacketNumber(422)
|
current_cwnd := protocol.PacketNumber(422)
|
||||||
expected_cwnd := current_cwnd + 1
|
expected_cwnd := current_cwnd
|
||||||
// Initialize the state.
|
// Initialize the state.
|
||||||
clock.Advance(time.Millisecond)
|
clock.Advance(time.Millisecond)
|
||||||
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(Equal(expected_cwnd))
|
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(Equal(expected_cwnd))
|
||||||
@@ -77,7 +92,7 @@ var _ = Describe("Cubic", func() {
|
|||||||
// Concave growth.
|
// Concave growth.
|
||||||
rtt_min := 100 * time.Millisecond
|
rtt_min := 100 * time.Millisecond
|
||||||
current_cwnd := protocol.PacketNumber(422)
|
current_cwnd := protocol.PacketNumber(422)
|
||||||
expected_cwnd := current_cwnd + 1
|
expected_cwnd := current_cwnd
|
||||||
// Initialize the state.
|
// Initialize the state.
|
||||||
clock.Advance(time.Millisecond)
|
clock.Advance(time.Millisecond)
|
||||||
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(Equal(expected_cwnd))
|
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(Equal(expected_cwnd))
|
||||||
|
|||||||
Reference in New Issue
Block a user