use default RTT (100ms) for 0-RTT if no prior estimate (#5388)

* utils: initialize the {Smoothed, Latest, Min}RTT to 100ms

* utils: use time.Duration.Nanoseconds instead of uint64

No functional change expected.

* congestion: better check to avoid division by zero
This commit is contained in:
Marten Seemann
2025-10-16 15:32:46 +08:00
committed by GitHub
parent 5e5100b40c
commit 42b198b8d1
14 changed files with 157 additions and 143 deletions

View File

@@ -12,10 +12,11 @@ const (
oneMinusAlpha = 1 - rttAlpha
rttBeta = 0.25
oneMinusBeta = 1 - rttBeta
// The default RTT used before an RTT sample is taken.
defaultInitialRTT = 100 * time.Millisecond
)
// The default RTT used before an RTT sample is taken
const DefaultInitialRTT = 100 * time.Millisecond
// RTTStats provides round-trip statistics
type RTTStats struct {
hasMeasurement bool
@@ -28,6 +29,14 @@ type RTTStats struct {
maxAckDelay atomic.Int64 // nanoseconds
}
func NewRTTStats() *RTTStats {
var rttStats RTTStats
rttStats.minRTT.Store(DefaultInitialRTT.Nanoseconds())
rttStats.latestRTT.Store(DefaultInitialRTT.Nanoseconds())
rttStats.smoothedRTT.Store(DefaultInitialRTT.Nanoseconds())
return &rttStats
}
// MinRTT Returns the minRTT for the entire connection.
// May return Zero if no valid updates have occurred.
func (r *RTTStats) MinRTT() time.Duration {
@@ -58,8 +67,8 @@ func (r *RTTStats) MaxAckDelay() time.Duration {
// PTO gets the probe timeout duration.
func (r *RTTStats) PTO(includeMaxAckDelay bool) time.Duration {
if r.SmoothedRTT() == 0 {
return 2 * defaultInitialRTT
if !r.hasMeasurement {
return 2 * DefaultInitialRTT
}
pto := r.SmoothedRTT() + max(4*r.MeanDeviation(), protocol.TimerGranularity)
if includeMaxAckDelay {
@@ -79,9 +88,9 @@ func (r *RTTStats) UpdateRTT(sendDelta, ackDelay time.Duration) {
// the client may cause a high ackDelay to result in underestimation of the
// r.minRTT.
minRTT := time.Duration(r.minRTT.Load())
if minRTT == 0 || minRTT > sendDelta {
if !r.hasMeasurement || minRTT > sendDelta {
minRTT = sendDelta
r.minRTT.Store(int64(sendDelta))
r.minRTT.Store(sendDelta.Nanoseconds())
}
// Correct for ackDelay if information received from the peer results in a
@@ -91,18 +100,18 @@ func (r *RTTStats) UpdateRTT(sendDelta, ackDelay time.Duration) {
if sample-minRTT >= ackDelay {
sample -= ackDelay
}
r.latestRTT.Store(int64(sample))
r.latestRTT.Store(sample.Nanoseconds())
// First time call.
if !r.hasMeasurement {
r.hasMeasurement = true
r.smoothedRTT.Store(int64(sample))
r.meanDeviation.Store(int64(sample / 2))
r.smoothedRTT.Store(sample.Nanoseconds())
r.meanDeviation.Store(sample.Nanoseconds() / 2)
} else {
smoothedRTT := r.SmoothedRTT()
meanDev := time.Duration(oneMinusBeta*float32(r.MeanDeviation()/time.Microsecond)+rttBeta*float32((smoothedRTT-sample).Abs()/time.Microsecond)) * time.Microsecond
newSmoothedRTT := time.Duration((float32(smoothedRTT/time.Microsecond)*oneMinusAlpha)+(float32(sample/time.Microsecond)*rttAlpha)) * time.Microsecond
r.meanDeviation.Store(int64(meanDev))
r.smoothedRTT.Store(int64(newSmoothedRTT))
r.meanDeviation.Store(meanDev.Nanoseconds())
r.smoothedRTT.Store(newSmoothedRTT.Nanoseconds())
}
}
@@ -127,9 +136,9 @@ func (r *RTTStats) SetInitialRTT(t time.Duration) {
func (r *RTTStats) ResetForPathMigration() {
r.hasMeasurement = false
r.minRTT.Store(0)
r.latestRTT.Store(0)
r.smoothedRTT.Store(0)
r.minRTT.Store(DefaultInitialRTT.Nanoseconds())
r.latestRTT.Store(DefaultInitialRTT.Nanoseconds())
r.smoothedRTT.Store(DefaultInitialRTT.Nanoseconds())
r.meanDeviation.Store(0)
// max_ack_delay remains valid
}