Skip to content

Commit

Permalink
wip: BBR experimental changes
Browse files Browse the repository at this point in the history
  • Loading branch information
tobyxdd committed May 18, 2024
1 parent 15e5846 commit e0e75c4
Showing 1 changed file with 52 additions and 7 deletions.
59 changes: 52 additions & 7 deletions core/internal/congestion/bbr/bbr_sender.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"fmt"
"math/rand"
"net"
"os"
"strconv"
"time"

"github.com/apernet/quic-go/congestion"
Expand Down Expand Up @@ -37,6 +39,8 @@ const (
derivedHighGain = 2.773
// The newly derived CWND gain for STARTUP, 2.
derivedHighCWNDGain = 2.0

debugEnv = "HYSTERIA_BBR_DEBUG"
)

// The cycle of gains used during the PROBE_BW stage.
Expand All @@ -61,7 +65,7 @@ const (
// Flag.
defaultStartupFullLossCount = 8
quicBbr2DefaultLossThreshold = 0.02
maxBbrBurstPackets = 3
maxBbrBurstPackets = 10
)

type bbrMode int
Expand Down Expand Up @@ -237,6 +241,8 @@ type bbrSender struct {
maxDatagramSize congestion.ByteCount
// Recorded on packet sent. equivalent |unacked_packets_->bytes_in_flight()|
bytesInFlight congestion.ByteCount

debug bool
}

var _ congestion.CongestionControl = &bbrSender{}
Expand All @@ -259,6 +265,7 @@ func newBbrSender(
initialCongestionWindow,
initialMaxCongestionWindow congestion.ByteCount,
) *bbrSender {
debug, _ := strconv.ParseBool(os.Getenv(debugEnv))
b := &bbrSender{
clock: clock,
mode: bbrModeStartup,
Expand All @@ -284,6 +291,7 @@ func newBbrSender(
cwndToCalculateMinPacingRate: initialCongestionWindow,
maxCongestionWindowWithNetworkParametersAdjusted: initialMaxCongestionWindow,
maxDatagramSize: initialMaxDatagramSize,
debug: debug,
}
b.pacer = common.NewPacer(b.bandwidthForPacer)

Expand Down Expand Up @@ -332,6 +340,8 @@ func (b *bbrSender) OnPacketSent(
}

b.sampler.OnPacketSent(sentTime, packetNumber, bytes, bytesInFlight, isRetransmittable)

b.maybeAppLimited(bytesInFlight)
}

// CanSend implements the SendAlgorithm interface.
Expand Down Expand Up @@ -411,8 +421,6 @@ func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, even
// packet in lost_packets.
var lastPacketSendState sendTimeState

b.maybeApplimited(priorInFlight)

// Update bytesInFlight
b.bytesInFlight = priorInFlight
for _, p := range ackedPackets {
Expand Down Expand Up @@ -539,7 +547,7 @@ func (b *bbrSender) setDrainGain(drainGain float64) {
b.drainGain = drainGain
}

// What's the current estimated bandwidth in bytes per second.
// Get the current bandwidth estimate. Note that Bandwidth is in bits per second.
func (b *bbrSender) bandwidthEstimate() Bandwidth {
return b.maxBandwidth.GetBest()
}
Expand Down Expand Up @@ -607,6 +615,10 @@ func (b *bbrSender) enterStartupMode(now time.Time) {
// b.maybeTraceStateChange(logging.CongestionStateStartup)
b.pacingGain = b.highGain
b.congestionWindowGain = b.highCwndGain

if b.debug {
b.debugPrint("Phase: STARTUP")
}
}

// Enters the PROBE_BW mode.
Expand All @@ -625,6 +637,10 @@ func (b *bbrSender) enterProbeBandwidthMode(now time.Time) {

b.lastCycleStart = now
b.pacingGain = pacingGain[b.cycleCurrentOffset]

if b.debug {
b.debugPrint("Phase: PROBE_BW")
}
}

// Updates the round-trip counter if a round-trip has passed. Returns true if
Expand Down Expand Up @@ -698,15 +714,17 @@ func (b *bbrSender) checkIfFullBandwidthReached(lastPacketSendState *sendTimeSta
}
}

func (b *bbrSender) maybeApplimited(bytesInFlight congestion.ByteCount) {
func (b *bbrSender) maybeAppLimited(bytesInFlight congestion.ByteCount) {
congestionWindow := b.GetCongestionWindow()
if bytesInFlight >= congestionWindow {
return
}
availableBytes := congestionWindow - bytesInFlight
drainLimited := b.mode == bbrModeDrain && bytesInFlight > congestionWindow/2
if !drainLimited || availableBytes > maxBbrBurstPackets*b.maxDatagramSize {
if availableBytes > maxBbrBurstPackets*b.maxDatagramSize {
b.sampler.OnAppLimited()
if b.debug {
b.debugPrint("AppLimited, AvailableBytes: %d", availableBytes)
}
}
}

Expand All @@ -718,6 +736,10 @@ func (b *bbrSender) maybeExitStartupOrDrain(now time.Time) {
// b.maybeTraceStateChange(logging.CongestionStateDrain)
b.pacingGain = b.drainGain
b.congestionWindowGain = b.highCwndGain

if b.debug {
b.debugPrint("Phase: DRAIN")
}
}
if b.mode == bbrModeDrain && b.bytesInFlight <= b.getTargetCongestionWindow(1) {
b.enterProbeBandwidthMode(now)
Expand All @@ -733,6 +755,12 @@ func (b *bbrSender) maybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRtt
// Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight|
// is at the target small value.
b.exitProbeRttAt = time.Time{}

if b.debug {
b.debugPrint("BandwidthEstimate: %s, CongestionWindowGain: %.2f, PacingGain: %.2f, PacingRate: %s",
formatSpeed(b.bandwidthEstimate()), b.congestionWindowGain, b.pacingGain, formatSpeed(b.PacingRate()))
b.debugPrint("Phase: PROBE_RTT")
}
}

if b.mode == bbrModeProbeRtt {
Expand Down Expand Up @@ -925,6 +953,12 @@ func (b *bbrSender) shouldExitStartupDueToLoss(lastPacketSendState *sendTimeStat
return false
}

func (b *bbrSender) debugPrint(format string, a ...any) {
fmt.Printf("[BBRSender] [%s] %s\n",
time.Now().Format("15:04:05"),
fmt.Sprintf(format, a...))
}

func bdpFromRttAndBandwidth(rtt time.Duration, bandwidth Bandwidth) congestion.ByteCount {
return congestion.ByteCount(rtt) * congestion.ByteCount(bandwidth) / congestion.ByteCount(BytesPerSecond) / congestion.ByteCount(time.Second)
}
Expand All @@ -942,3 +976,14 @@ func GetInitialPacketSize(addr net.Addr) congestion.ByteCount {
return congestion.MinInitialPacketSize
}
}

func formatSpeed(bw Bandwidth) string {
bwf := float64(bw)
units := []string{"bps", "Kbps", "Mbps", "Gbps"}
unitIndex := 0
for bwf > 1024 && unitIndex < len(units)-1 {
bwf /= 1024
unitIndex++
}
return fmt.Sprintf("%.2f %s", bwf, units[unitIndex])
}

0 comments on commit e0e75c4

Please sign in to comment.