diff --git a/transport/tuic/congestion_v2/bbr_sender.go b/transport/tuic/congestion_v2/bbr_sender.go index 99e85e90..c5bca210 100644 --- a/transport/tuic/congestion_v2/bbr_sender.go +++ b/transport/tuic/congestion_v2/bbr_sender.go @@ -27,16 +27,13 @@ const ( invalidPacketNumber = -1 initialCongestionWindowPackets = 32 + minCongestionWindowPackets = 4 // Constants based on TCP defaults. // The minimum CWND to ensure delayed acks don't reduce bandwidth measurements. // Does not inflate the pacing rate. - defaultMinimumCongestionWindow = 4 * congestion.ByteCount(congestion.InitialPacketSize) - // The gain used for the STARTUP, equal to 2/ln(2). defaultHighGain = 2.885 - // The newly derived gain for STARTUP, equal to 4 * ln(2) - derivedHighGain = 2.773 // The newly derived CWND gain for STARTUP, 2. derivedHighCWNDGain = 2.0 ) @@ -63,7 +60,6 @@ const ( // Flag. defaultStartupFullLossCount = 8 quicBbr2DefaultLossThreshold = 0.02 - maxBbrBurstPackets = 10 ) type bbrMode int @@ -267,7 +263,7 @@ func newBbrSender( congestionWindow: initialCongestionWindow, initialCongestionWindow: initialCongestionWindow, maxCongestionWindow: initialMaxCongestionWindow, - minCongestionWindow: defaultMinimumCongestionWindow, + minCongestionWindow: minCongestionWindowForMaxDatagramSize(initialMaxDatagramSize), highGain: defaultHighGain, highCwndGain: defaultHighGain, drainGain: 1.0 / defaultHighGain, @@ -285,19 +281,37 @@ func newBbrSender( } b.pacer = NewPacer(b.bandwidthForPacer) - /* - if b.tracer != nil { - b.lastState = logging.CongestionStateStartup - b.tracer.UpdatedCongestionState(logging.CongestionStateStartup) - } - */ - b.enterStartupMode() b.setHighCwndGain(derivedHighCWNDGain) return b } +func minCongestionWindowForMaxDatagramSize(maxDatagramSize congestion.ByteCount) congestion.ByteCount { + return minCongestionWindowPackets * maxDatagramSize +} + +func scaleByteWindowForDatagramSize(window, oldMaxDatagramSize, newMaxDatagramSize congestion.ByteCount) congestion.ByteCount { + if oldMaxDatagramSize == newMaxDatagramSize { + return window + } + return congestion.ByteCount(uint64(window) * uint64(newMaxDatagramSize) / uint64(oldMaxDatagramSize)) +} + +func (b *bbrSender) rescalePacketSizedWindows(maxDatagramSize congestion.ByteCount) { + oldMaxDatagramSize := b.maxDatagramSize + b.maxDatagramSize = maxDatagramSize + b.initialCongestionWindow = scaleByteWindowForDatagramSize(b.initialCongestionWindow, oldMaxDatagramSize, maxDatagramSize) + b.maxCongestionWindow = scaleByteWindowForDatagramSize(b.maxCongestionWindow, oldMaxDatagramSize, maxDatagramSize) + b.minCongestionWindow = minCongestionWindowForMaxDatagramSize(maxDatagramSize) + b.cwndToCalculateMinPacingRate = scaleByteWindowForDatagramSize(b.cwndToCalculateMinPacingRate, oldMaxDatagramSize, maxDatagramSize) + b.maxCongestionWindowWithNetworkParametersAdjusted = scaleByteWindowForDatagramSize( + b.maxCongestionWindowWithNetworkParametersAdjusted, + oldMaxDatagramSize, + maxDatagramSize, + ) +} + func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { b.rttStats = provider } @@ -330,8 +344,6 @@ func (b *bbrSender) OnPacketSent( } b.sampler.OnPacketSent(sentTime, packetNumber, bytes, bytesInFlight, isRetransmittable) - - b.maybeAppLimited(bytesInFlight) } // CanSend implements the SendAlgorithm interface. @@ -364,11 +376,18 @@ func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) { if s < b.maxDatagramSize { panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", b.maxDatagramSize, s)) } - cwndIsMinCwnd := b.congestionWindow == b.minCongestionWindow - b.maxDatagramSize = s - if cwndIsMinCwnd { + oldMinCongestionWindow := b.minCongestionWindow + oldInitialCongestionWindow := b.initialCongestionWindow + b.rescalePacketSizedWindows(s) + switch b.congestionWindow { + case oldMinCongestionWindow: b.congestionWindow = b.minCongestionWindow + case oldInitialCongestionWindow: + b.congestionWindow = b.initialCongestionWindow + default: + b.congestionWindow = Min(b.maxCongestionWindow, Max(b.congestionWindow, b.minCongestionWindow)) } + b.recoveryWindow = Min(b.maxCongestionWindow, Max(b.recoveryWindow, b.minCongestionWindow)) b.pacer.SetMaxDatagramSize(s) } @@ -411,6 +430,8 @@ 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 { @@ -508,22 +529,6 @@ func (b *bbrSender) PacingRate() Bandwidth { return b.pacingRate } -func (b *bbrSender) hasGoodBandwidthEstimateForResumption() bool { - return b.hasNonAppLimitedSample() -} - -func (b *bbrSender) hasNonAppLimitedSample() bool { - return b.hasNoAppLimitedSample -} - -// Sets the pacing gain used in STARTUP. Must be greater than 1. -func (b *bbrSender) setHighGain(highGain float64) { - b.highGain = highGain - if b.mode == bbrModeStartup { - b.pacingGain = highGain - } -} - // Sets the CWND gain used in STARTUP. Must be greater than 1. func (b *bbrSender) setHighCwndGain(highCwndGain float64) { b.highCwndGain = highCwndGain @@ -532,11 +537,6 @@ func (b *bbrSender) setHighCwndGain(highCwndGain float64) { } } -// Sets the gain used in DRAIN. Must be less than 1. -func (b *bbrSender) setDrainGain(drainGain float64) { - b.drainGain = drainGain -} - // Get the current bandwidth estimate. Note that Bandwidth is in bits per second. func (b *bbrSender) bandwidthEstimate() Bandwidth { return b.maxBandwidth.GetBest() @@ -697,12 +697,7 @@ func (b *bbrSender) checkIfFullBandwidthReached(lastPacketSendState *sendTimeSta } func (b *bbrSender) maybeAppLimited(bytesInFlight congestion.ByteCount) { - congestionWindow := b.GetCongestionWindow() - if bytesInFlight >= congestionWindow { - return - } - availableBytes := congestionWindow - bytesInFlight - if availableBytes > maxBbrBurstPackets*b.maxDatagramSize { + if bytesInFlight < b.getTargetCongestionWindow(1) { b.sampler.OnAppLimited() } } @@ -729,7 +724,7 @@ func (b *bbrSender) maybeEnterOrExitProbeRtt(now monotime.Time, isRoundStart, mi b.pacingGain = 1.0 // Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight| // is at the target small value. - b.exitProbeRttAt = monotime.Time(0) + b.exitProbeRttAt = 0 } if b.mode == bbrModeProbeRtt {