change cubic to use PacketNumbers

This commit is contained in:
Lucas Clemente
2016-04-27 18:09:49 +02:00
parent 23b5c6264b
commit 991834c5bf
2 changed files with 26 additions and 25 deletions

View File

@@ -4,7 +4,7 @@ import (
"math"
"time"
"github.com/lucas-clemente/quic-go/utils"
"github.com/lucas-clemente/quic-go/protocol"
)
// A Clock returns the current time
@@ -24,7 +24,7 @@ type Clock interface {
// round trip time.
const cubeScale = 40
const cubeCongestionWindowScale = 410
const cubeFactor uint64 = 1 << cubeScale / cubeCongestionWindowScale
const cubeFactor protocol.PacketNumber = 1 << cubeScale / cubeCongestionWindowScale
const defaultNumConnections = 2
@@ -54,21 +54,21 @@ type Cubic struct {
// Time when we updated last_congestion_window.
lastUpdateTime time.Time
// Last congestion window (in packets) used.
lastCongestionWindow uint64
lastCongestionWindow protocol.PacketNumber
// Max congestion window (in packets) used just before last loss event.
// Note: to improve fairness to other streams an additional back off is
// applied to this value if the new value is below our latest value.
lastMaxCongestionWindow uint64
lastMaxCongestionWindow protocol.PacketNumber
// Number of acked packets since the cycle started (epoch).
ackedPacketsCount uint64
ackedPacketsCount protocol.PacketNumber
// TCP Reno equivalent congestion window in packets.
estimatedTCPcongestionWindow uint64
estimatedTCPcongestionWindow protocol.PacketNumber
// Origin point of cubic function.
originPointCongestionWindow uint64
originPointCongestionWindow protocol.PacketNumber
// Time to origin point of cubic function in 2^10 fractions of a second.
timeToOriginPoint uint32
// Last congestion window in packets computed by cubic function.
lastTargetCongestionWindow uint64
lastTargetCongestionWindow protocol.PacketNumber
}
// NewCubic returns a new Cubic instance
@@ -131,29 +131,29 @@ func (c *Cubic) OnApplicationLimited() {
// CongestionWindowAfterPacketLoss computes a new congestion window to use after
// a loss event. Returns the new congestion window in packets. The new
// congestion window is a multiplicative decrease of our current window.
func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow uint64) uint64 {
func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow protocol.PacketNumber) protocol.PacketNumber {
if currentCongestionWindow < c.lastMaxCongestionWindow {
// We never reached the old max, so assume we are competing with another
// flow. Use our extra back off factor to allow the other flow to go up.
c.lastMaxCongestionWindow = uint64(betaLastMax * float32(currentCongestionWindow))
c.lastMaxCongestionWindow = protocol.PacketNumber(betaLastMax * float32(currentCongestionWindow))
} else {
c.lastMaxCongestionWindow = currentCongestionWindow
}
c.epoch = time.Time{} // Reset time.
return uint64(float32(currentCongestionWindow) * c.beta())
return protocol.PacketNumber(float32(currentCongestionWindow) * c.beta())
}
// CongestionWindowAfterAck computes a new congestion window to use after a received ACK.
// Returns the new congestion window in packets. The new congestion window
// follows a cubic function that depends on the time passed since last
// packet loss.
func (c *Cubic) CongestionWindowAfterAck(currentCongestionWindow uint64, delayMin time.Duration) uint64 {
func (c *Cubic) CongestionWindowAfterAck(currentCongestionWindow protocol.PacketNumber, delayMin time.Duration) protocol.PacketNumber {
c.ackedPacketsCount++ // Packets acked.
currentTime := c.clock.Now()
// Cubic is "independent" of RTT, the update is limited by the time elapsed.
if c.lastCongestionWindow == currentCongestionWindow && (currentTime.Sub(c.lastUpdateTime) <= maxCubicTimeInterval) {
return utils.MaxUint64(c.lastTargetCongestionWindow, c.estimatedTCPcongestionWindow)
return protocol.MaxPacketNumber(c.lastTargetCongestionWindow, c.estimatedTCPcongestionWindow)
}
c.lastCongestionWindow = currentCongestionWindow
c.lastUpdateTime = currentTime
@@ -188,7 +188,7 @@ func (c *Cubic) CongestionWindowAfterAck(currentCongestionWindow uint64, delayMi
elapsedTime := int64((currentTime.Add(delayMin).Sub(c.epoch)/time.Microsecond)<<10) / 1000000
offset := int64(c.timeToOriginPoint) - elapsedTime
deltaCongestionWindow := uint64((cubeCongestionWindowScale * offset * offset * offset) >> cubeScale)
deltaCongestionWindow := protocol.PacketNumber((cubeCongestionWindowScale * offset * offset * offset) >> cubeScale)
targetCongestionWindow := c.originPointCongestionWindow - deltaCongestionWindow
// With dynamic beta/alpha based on number of active streams, it is possible
@@ -196,7 +196,7 @@ func (c *Cubic) CongestionWindowAfterAck(currentCongestionWindow uint64, delayMi
// suddenly, leading to more than one iteration through the following loop.
for {
// Update estimated TCP congestion_window.
requiredAckCount := uint64(float32(c.estimatedTCPcongestionWindow) / c.alpha())
requiredAckCount := protocol.PacketNumber(float32(c.estimatedTCPcongestionWindow) / c.alpha())
if c.ackedPacketsCount < requiredAckCount {
break
}

View File

@@ -4,6 +4,7 @@ import (
"time"
"github.com/lucas-clemente/quic-go/congestion"
"github.com/lucas-clemente/quic-go/protocol"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
@@ -27,7 +28,7 @@ var _ = Describe("Cubic", func() {
It("works above origin", func() {
// Convex growth.
rtt_min := 100 * time.Millisecond
current_cwnd := uint64(10)
current_cwnd := protocol.PacketNumber(10)
expected_cwnd := current_cwnd + 1
// Initialize the state.
clock.Advance(time.Millisecond)
@@ -46,7 +47,7 @@ var _ = Describe("Cubic", func() {
}
// Cubic phase.
for i := 0; i < 52; i++ {
for n := uint64(1); n < current_cwnd; n++ {
for n := protocol.PacketNumber(1); n < current_cwnd; n++ {
// Call once per ACK.
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(Equal(current_cwnd))
}
@@ -56,14 +57,14 @@ var _ = Describe("Cubic", func() {
// Total time elapsed so far; add min_rtt (0.1s) here as well.
elapsed_time_s := 10.0 + 0.1
// |expected_cwnd| is initial value of cwnd + K * t^3, where K = 0.4.
expected_cwnd = uint64(11 + (elapsed_time_s*elapsed_time_s*elapsed_time_s*410)/1024)
expected_cwnd = protocol.PacketNumber(11 + (elapsed_time_s*elapsed_time_s*elapsed_time_s*410)/1024)
Expect(current_cwnd).To(Equal(expected_cwnd))
})
// TODO: Test copied from Chromium has no assertions
It("has increasing cwnd stats during convex region", func() {
rtt_min := 100 * time.Millisecond
current_cwnd := uint64(10)
current_cwnd := protocol.PacketNumber(10)
expected_cwnd := current_cwnd + 1
// Initialize the state.
clock.Advance(time.Millisecond)
@@ -83,7 +84,7 @@ var _ = Describe("Cubic", func() {
// Testing Cubic mode increase.
for i := 0; i < 52; i++ {
for n := uint64(1); n < current_cwnd; n++ {
for n := protocol.PacketNumber(1); n < current_cwnd; n++ {
// Call once per ACK.
cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)
}
@@ -94,26 +95,26 @@ var _ = Describe("Cubic", func() {
It("manages loss events", func() {
rtt_min := 100 * time.Millisecond
current_cwnd := uint64(422)
current_cwnd := protocol.PacketNumber(422)
expected_cwnd := current_cwnd + 1
// Initialize the state.
clock.Advance(time.Millisecond)
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(Equal(expected_cwnd))
expected_cwnd = uint64(float32(current_cwnd) * kNConnectionBeta)
expected_cwnd = protocol.PacketNumber(float32(current_cwnd) * kNConnectionBeta)
Expect(cubic.CongestionWindowAfterPacketLoss(current_cwnd)).To(Equal(expected_cwnd))
expected_cwnd = uint64(float32(current_cwnd) * kNConnectionBeta)
expected_cwnd = protocol.PacketNumber(float32(current_cwnd) * kNConnectionBeta)
Expect(cubic.CongestionWindowAfterPacketLoss(current_cwnd)).To(Equal(expected_cwnd))
})
It("works below origin", func() {
// Concave growth.
rtt_min := 100 * time.Millisecond
current_cwnd := uint64(422)
current_cwnd := protocol.PacketNumber(422)
expected_cwnd := current_cwnd + 1
// Initialize the state.
clock.Advance(time.Millisecond)
Expect(cubic.CongestionWindowAfterAck(current_cwnd, rtt_min)).To(Equal(expected_cwnd))
expected_cwnd = uint64(float32(current_cwnd) * kNConnectionBeta)
expected_cwnd = protocol.PacketNumber(float32(current_cwnd) * kNConnectionBeta)
Expect(cubic.CongestionWindowAfterPacketLoss(current_cwnd)).To(Equal(expected_cwnd))
current_cwnd = expected_cwnd
// First update after loss to initialize the epoch.