mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-04 12:47:36 +03:00
uTLS is not yet bumped to the new version, so this commit breaks the dependencies relationship by getting rid of the local replace.
141 lines
4.5 KiB
Go
141 lines
4.5 KiB
Go
package congestion
|
|
|
|
import (
|
|
"math/rand"
|
|
"time"
|
|
|
|
"github.com/refraction-networking/uquic/internal/protocol"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Pacer", func() {
|
|
var p *pacer
|
|
|
|
const packetsPerSecond = 50
|
|
var bandwidth uint64 // in bytes/s
|
|
|
|
BeforeEach(func() {
|
|
bandwidth = uint64(packetsPerSecond * initialMaxDatagramSize) // 50 full-size packets per second
|
|
// The pacer will multiply the bandwidth with 1.25 to achieve a slightly higher pacing speed.
|
|
// For the tests, cancel out this factor, so we can do the math using the exact bandwidth.
|
|
p = newPacer(func() Bandwidth { return Bandwidth(bandwidth) * BytesPerSecond * 4 / 5 })
|
|
})
|
|
|
|
It("allows a burst at the beginning", func() {
|
|
t := time.Now()
|
|
Expect(p.TimeUntilSend()).To(BeZero())
|
|
Expect(p.Budget(t)).To(BeEquivalentTo(maxBurstSizePackets * initialMaxDatagramSize))
|
|
})
|
|
|
|
It("allows a big burst for high pacing rates", func() {
|
|
t := time.Now()
|
|
bandwidth = uint64(10000 * packetsPerSecond * initialMaxDatagramSize)
|
|
Expect(p.TimeUntilSend()).To(BeZero())
|
|
Expect(p.Budget(t)).To(BeNumerically(">", maxBurstSizePackets*initialMaxDatagramSize))
|
|
})
|
|
|
|
It("reduces the budget when sending packets", func() {
|
|
t := time.Now()
|
|
budget := p.Budget(t)
|
|
for budget > 0 {
|
|
Expect(p.TimeUntilSend()).To(BeZero())
|
|
Expect(p.Budget(t)).To(Equal(budget))
|
|
p.SentPacket(t, initialMaxDatagramSize)
|
|
budget -= initialMaxDatagramSize
|
|
}
|
|
Expect(p.Budget(t)).To(BeZero())
|
|
Expect(p.TimeUntilSend()).ToNot(BeZero())
|
|
})
|
|
|
|
sendBurst := func(t time.Time) {
|
|
for p.Budget(t) > 0 {
|
|
p.SentPacket(t, initialMaxDatagramSize)
|
|
}
|
|
}
|
|
|
|
It("paces packets after a burst", func() {
|
|
t := time.Now()
|
|
sendBurst(t)
|
|
// send 100 exactly paced packets
|
|
for i := 0; i < 100; i++ {
|
|
t2 := p.TimeUntilSend()
|
|
Expect(t2.Sub(t)).To(BeNumerically("~", time.Second/packetsPerSecond, time.Nanosecond))
|
|
Expect(p.Budget(t2)).To(BeEquivalentTo(initialMaxDatagramSize))
|
|
p.SentPacket(t2, initialMaxDatagramSize)
|
|
t = t2
|
|
}
|
|
})
|
|
|
|
It("accounts for non-full-size packets", func() {
|
|
t := time.Now()
|
|
sendBurst(t)
|
|
t2 := p.TimeUntilSend()
|
|
Expect(t2.Sub(t)).To(BeNumerically("~", time.Second/packetsPerSecond, time.Nanosecond))
|
|
// send a half-full packet
|
|
Expect(p.Budget(t2)).To(BeEquivalentTo(initialMaxDatagramSize))
|
|
size := initialMaxDatagramSize / 2
|
|
p.SentPacket(t2, size)
|
|
Expect(p.Budget(t2)).To(Equal(initialMaxDatagramSize - size))
|
|
Expect(p.TimeUntilSend()).To(BeTemporally("~", t2.Add(time.Second/packetsPerSecond/2), time.Nanosecond))
|
|
})
|
|
|
|
It("accumulates budget, if no packets are sent", func() {
|
|
t := time.Now()
|
|
sendBurst(t)
|
|
t2 := p.TimeUntilSend()
|
|
Expect(t2).To(BeTemporally(">", t))
|
|
// wait for 5 times the duration
|
|
Expect(p.Budget(t.Add(5 * t2.Sub(t)))).To(BeEquivalentTo(5 * initialMaxDatagramSize))
|
|
})
|
|
|
|
It("accumulates budget, if no packets are sent, for larger packet sizes", func() {
|
|
t := time.Now()
|
|
sendBurst(t)
|
|
const packetSize = initialMaxDatagramSize + 200
|
|
p.SetMaxDatagramSize(packetSize)
|
|
t2 := p.TimeUntilSend()
|
|
Expect(t2).To(BeTemporally(">", t))
|
|
// wait for 5 times the duration
|
|
Expect(p.Budget(t.Add(5 * t2.Sub(t)))).To(BeEquivalentTo(5 * packetSize))
|
|
})
|
|
|
|
It("never allows bursts larger than the maximum burst size", func() {
|
|
t := time.Now()
|
|
sendBurst(t)
|
|
Expect(p.Budget(t.Add(time.Hour))).To(BeEquivalentTo(maxBurstSizePackets * initialMaxDatagramSize))
|
|
})
|
|
|
|
It("never allows bursts larger than the maximum burst size, for larger packets", func() {
|
|
t := time.Now()
|
|
const packetSize = initialMaxDatagramSize + 200
|
|
p.SetMaxDatagramSize(packetSize)
|
|
sendBurst(t)
|
|
Expect(p.Budget(t.Add(time.Hour))).To(BeEquivalentTo(maxBurstSizePackets * packetSize))
|
|
})
|
|
|
|
It("changes the bandwidth", func() {
|
|
t := time.Now()
|
|
sendBurst(t)
|
|
bandwidth = uint64(5 * initialMaxDatagramSize) // reduce the bandwidth to 5 packet per second
|
|
Expect(p.TimeUntilSend()).To(Equal(t.Add(time.Second / 5)))
|
|
})
|
|
|
|
It("doesn't pace faster than the minimum pacing duration", func() {
|
|
t := time.Now()
|
|
sendBurst(t)
|
|
bandwidth = uint64(1e6 * initialMaxDatagramSize)
|
|
Expect(p.TimeUntilSend()).To(Equal(t.Add(protocol.MinPacingDelay)))
|
|
Expect(p.Budget(t.Add(protocol.MinPacingDelay))).To(Equal(protocol.ByteCount(protocol.MinPacingDelay) * initialMaxDatagramSize * 1e6 / 1e9))
|
|
})
|
|
|
|
It("protects against overflows", func() {
|
|
p = newPacer(func() Bandwidth { return infBandwidth })
|
|
t := time.Now()
|
|
p.SentPacket(t, initialMaxDatagramSize)
|
|
for i := 0; i < 1e5; i++ {
|
|
Expect(p.Budget(t.Add(time.Duration(rand.Int63())))).To(BeNumerically(">=", 0))
|
|
}
|
|
})
|
|
})
|