"github.com/quic-go/quic-go/qlogwriter"
)
-func pointer[T any](v T) *T {
- return &v
-}
-
const (
// Maximum reordering in time space before time based loss detection considers a packet lost.
// Specified as an RTT multiplier.
panic(fmt.Sprintf("Cannot drop keys for encryption level %s", encLevel))
}
if h.qlogger != nil && h.ptoCount != 0 {
- h.qlogger.RecordEvent(qlog.MetricsUpdated{PTOCount: pointer(uint32(0))})
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
}
h.ptoCount = 0
h.numProbesToSend = 0
var metricsUpdatedEvent qlog.MetricsUpdated
var updated bool
if h.rttStats.HasMeasurement() {
- if h.lastMetrics.MinRTT == nil || *h.lastMetrics.MinRTT != h.rttStats.MinRTT() {
- metricsUpdatedEvent.MinRTT = pointer(h.rttStats.MinRTT())
- h.lastMetrics.MinRTT = pointer(h.rttStats.MinRTT())
+ if h.lastMetrics.MinRTT != h.rttStats.MinRTT() {
+ metricsUpdatedEvent.MinRTT = h.rttStats.MinRTT()
+ h.lastMetrics.MinRTT = metricsUpdatedEvent.MinRTT
updated = true
}
- if h.lastMetrics.SmoothedRTT == nil || *h.lastMetrics.SmoothedRTT != h.rttStats.SmoothedRTT() {
- metricsUpdatedEvent.SmoothedRTT = pointer(h.rttStats.SmoothedRTT())
- h.lastMetrics.SmoothedRTT = pointer(h.rttStats.SmoothedRTT())
+ if h.lastMetrics.SmoothedRTT != h.rttStats.SmoothedRTT() {
+ metricsUpdatedEvent.SmoothedRTT = h.rttStats.SmoothedRTT()
+ h.lastMetrics.SmoothedRTT = metricsUpdatedEvent.SmoothedRTT
updated = true
}
- if h.lastMetrics.LatestRTT == nil || *h.lastMetrics.LatestRTT != h.rttStats.LatestRTT() {
- metricsUpdatedEvent.LatestRTT = pointer(h.rttStats.LatestRTT())
- h.lastMetrics.LatestRTT = pointer(h.rttStats.LatestRTT())
+ if h.lastMetrics.LatestRTT != h.rttStats.LatestRTT() {
+ metricsUpdatedEvent.LatestRTT = h.rttStats.LatestRTT()
+ h.lastMetrics.LatestRTT = metricsUpdatedEvent.LatestRTT
updated = true
}
- if h.lastMetrics.RTTVariance == nil || *h.lastMetrics.RTTVariance != h.rttStats.MeanDeviation() {
- metricsUpdatedEvent.RTTVariance = pointer(h.rttStats.MeanDeviation())
- h.lastMetrics.RTTVariance = pointer(h.rttStats.MeanDeviation())
+ if h.lastMetrics.RTTVariance != h.rttStats.MeanDeviation() {
+ metricsUpdatedEvent.RTTVariance = h.rttStats.MeanDeviation()
+ h.lastMetrics.RTTVariance = metricsUpdatedEvent.RTTVariance
updated = true
}
}
- if h.lastMetrics.CongestionWindow == nil || *h.lastMetrics.CongestionWindow != int(h.congestion.GetCongestionWindow()) {
- metricsUpdatedEvent.CongestionWindow = pointer(int(h.congestion.GetCongestionWindow()))
- h.lastMetrics.CongestionWindow = pointer(int(h.congestion.GetCongestionWindow()))
+ if cwnd := h.congestion.GetCongestionWindow(); h.lastMetrics.CongestionWindow != int(cwnd) {
+ metricsUpdatedEvent.CongestionWindow = int(cwnd)
+ h.lastMetrics.CongestionWindow = metricsUpdatedEvent.CongestionWindow
updated = true
}
- if h.lastMetrics.BytesInFlight == nil || *h.lastMetrics.BytesInFlight != int(h.bytesInFlight) {
- metricsUpdatedEvent.BytesInFlight = pointer(int(h.bytesInFlight))
- h.lastMetrics.BytesInFlight = pointer(int(h.bytesInFlight))
+ if h.lastMetrics.BytesInFlight != int(h.bytesInFlight) {
+ metricsUpdatedEvent.BytesInFlight = int(h.bytesInFlight)
+ h.lastMetrics.BytesInFlight = metricsUpdatedEvent.BytesInFlight
updated = true
}
- if h.lastMetrics.PacketsInFlight == nil || *h.lastMetrics.PacketsInFlight != h.packetsInFlight() {
- metricsUpdatedEvent.PacketsInFlight = pointer(h.packetsInFlight())
- h.lastMetrics.PacketsInFlight = pointer(h.packetsInFlight())
+ if h.lastMetrics.PacketsInFlight != h.packetsInFlight() {
+ metricsUpdatedEvent.PacketsInFlight = h.packetsInFlight()
+ h.lastMetrics.PacketsInFlight = metricsUpdatedEvent.PacketsInFlight
updated = true
}
if updated {
// Reset the pto_count unless the client is unsure if the server has validated the client's address.
if h.peerCompletedAddressValidation {
if h.qlogger != nil && h.ptoCount != 0 {
- h.qlogger.RecordEvent(qlog.MetricsUpdated{PTOCount: pointer(uint32(0))})
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
}
h.ptoCount = 0
}
TimerType: qlog.TimerTypePTO,
EncLevel: encLevel,
})
- h.qlogger.RecordEvent(qlog.MetricsUpdated{PTOCount: pointer(h.ptoCount)})
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: h.ptoCount})
}
h.numProbesToSend += 2
//nolint:exhaustive // We never arm a PTO timer for 0-RTT packets.
oldAlarm := h.alarm
h.alarm = alarmTimer{}
if h.qlogger != nil {
- h.qlogger.RecordEvent(qlog.MetricsUpdated{PTOCount: pointer(uint32(0))})
+ h.qlogger.RecordEvent(qlog.PTOCountUpdated{PTOCount: 0})
if !oldAlarm.Time.IsZero() {
h.qlogger.RecordEvent(qlog.LossTimerUpdated{
Type: qlog.LossTimerUpdateTypeCancelled,
TimerType: qlog.TimerTypePTO,
EncLevel: encLevel,
},
- qlog.MetricsUpdated{
- PTOCount: pointer(uint32(1)),
- },
+ qlog.PTOCountUpdated{PTOCount: 1},
qlog.LossTimerUpdated{
Type: qlog.LossTimerUpdateTypeSet,
TimerType: qlog.TimerTypePTO,
Time: sendTimes[2].Add(2 * rttStats.PTO(encLevel == protocol.Encryption1RTT)).ToTime(),
},
},
- eventRecorder.Events(qlog.MetricsUpdated{}, qlog.LossTimerUpdated{}),
+ eventRecorder.Events(qlog.PTOCountUpdated{}, qlog.LossTimerUpdated{}),
)
// PTO timer expiration doesn't declare packets lost
require.Empty(t, packets.Lost)
TimerType: qlog.TimerTypePTO,
EncLevel: encLevel,
},
- qlog.MetricsUpdated{
- PTOCount: pointer(uint32(2)),
- },
+ qlog.PTOCountUpdated{PTOCount: 2},
qlog.LossTimerUpdated{
Type: qlog.LossTimerUpdateTypeSet,
TimerType: qlog.TimerTypePTO,
Time: sendTimes[6].Add(4 * rttStats.PTO(encLevel == protocol.Encryption1RTT)).ToTime(),
},
},
- eventRecorder.Events(qlog.LossTimerUpdated{}, qlog.MetricsUpdated{}),
+ eventRecorder.Events(qlog.LossTimerUpdated{}, qlog.PTOCountUpdated{}),
)
eventRecorder.Clear()
// PTO timer expiration doesn't declare packets lost
require.Len(t, eventRecorder.Events(qlog.PacketLost{}), 2)
require.Equal(t,
[]qlogwriter.Event{
- qlog.MetricsUpdated{PTOCount: pointer(uint32(0))},
+ qlog.PTOCountUpdated{PTOCount: 0},
},
- eventRecorder.Events(qlog.MetricsUpdated{})[:1],
+ eventRecorder.Events(qlog.PTOCountUpdated{})[:1],
)
require.Equal(t,
[]qlogwriter.Event{
},
})
- minRTT := rttStats.MinRTT()
- smoothedRTT := rttStats.SmoothedRTT()
- latestRTT := rttStats.LatestRTT()
- rttVariance := rttStats.MeanDeviation()
- cwndInt := int(12345 + protocol.ByteCount(2*i))
- bytesInt := int(12345 + protocol.ByteCount(i))
tracer.RecordEvent(&MetricsUpdated{
- MinRTT: &minRTT,
- SmoothedRTT: &smoothedRTT,
- LatestRTT: &latestRTT,
- RTTVariance: &rttVariance,
- CongestionWindow: &cwndInt,
- BytesInFlight: &bytesInt,
- PacketsInFlight: &i,
+ MinRTT: rttStats.MinRTT(),
+ SmoothedRTT: rttStats.SmoothedRTT(),
+ LatestRTT: rttStats.LatestRTT(),
+ RTTVariance: rttStats.MeanDeviation(),
+ CongestionWindow: int(12345 + protocol.ByteCount(2*i)),
+ BytesInFlight: int(12345 + protocol.ByteCount(i)),
+ PacketsInFlight: i,
})
if i%2 == 0 {
return h.err
}
+// MetricsUpdated logs RTT and congestion metrics as defined in the
+// recovery:metrics_updated event.
+// The PTO count is logged via PTOCountUpdated.
type MetricsUpdated struct {
- MinRTT *time.Duration
- SmoothedRTT *time.Duration
- LatestRTT *time.Duration
- RTTVariance *time.Duration
- CongestionWindow *int
- BytesInFlight *int
- PacketsInFlight *int
- PTOCount *uint32
+ MinRTT time.Duration
+ SmoothedRTT time.Duration
+ LatestRTT time.Duration
+ RTTVariance time.Duration
+ CongestionWindow int
+ BytesInFlight int
+ PacketsInFlight int
}
func (e MetricsUpdated) Name() string { return "recovery:metrics_updated" }
func (e MetricsUpdated) Encode(enc *jsontext.Encoder, _ time.Time) error {
h := encoderHelper{enc: enc}
h.WriteToken(jsontext.BeginObject)
- if e.MinRTT != nil {
+ if e.MinRTT != 0 {
h.WriteToken(jsontext.String("min_rtt"))
- h.WriteToken(jsontext.Float(milliseconds(*e.MinRTT)))
+ h.WriteToken(jsontext.Float(milliseconds(e.MinRTT)))
}
- if e.SmoothedRTT != nil {
+ if e.SmoothedRTT != 0 {
h.WriteToken(jsontext.String("smoothed_rtt"))
- h.WriteToken(jsontext.Float(milliseconds(*e.SmoothedRTT)))
+ h.WriteToken(jsontext.Float(milliseconds(e.SmoothedRTT)))
}
- if e.LatestRTT != nil {
+ if e.LatestRTT != 0 {
h.WriteToken(jsontext.String("latest_rtt"))
- h.WriteToken(jsontext.Float(milliseconds(*e.LatestRTT)))
+ h.WriteToken(jsontext.Float(milliseconds(e.LatestRTT)))
}
- if e.RTTVariance != nil {
+ if e.RTTVariance != 0 {
h.WriteToken(jsontext.String("rtt_variance"))
- h.WriteToken(jsontext.Float(milliseconds(*e.RTTVariance)))
+ h.WriteToken(jsontext.Float(milliseconds(e.RTTVariance)))
}
- if e.CongestionWindow != nil {
+ if e.CongestionWindow != 0 {
h.WriteToken(jsontext.String("congestion_window"))
- h.WriteToken(jsontext.Uint(uint64(*e.CongestionWindow)))
+ h.WriteToken(jsontext.Uint(uint64(e.CongestionWindow)))
}
- if e.BytesInFlight != nil {
+ if e.BytesInFlight != 0 {
h.WriteToken(jsontext.String("bytes_in_flight"))
- h.WriteToken(jsontext.Uint(uint64(*e.BytesInFlight)))
+ h.WriteToken(jsontext.Uint(uint64(e.BytesInFlight)))
}
- if e.PacketsInFlight != nil {
+ if e.PacketsInFlight != 0 {
h.WriteToken(jsontext.String("packets_in_flight"))
- h.WriteToken(jsontext.Uint(uint64(*e.PacketsInFlight)))
- }
- if e.PTOCount != nil {
- h.WriteToken(jsontext.String("pto_count"))
- h.WriteToken(jsontext.Uint(uint64(*e.PTOCount)))
+ h.WriteToken(jsontext.Uint(uint64(e.PacketsInFlight)))
}
h.WriteToken(jsontext.EndObject)
return h.err
}
+// PTOCountUpdated logs the pto_count value of the
+// recovery:metrics_updated event.
+type PTOCountUpdated struct {
+ PTOCount uint32
+}
+
+func (e PTOCountUpdated) Name() string { return "recovery:metrics_updated" }
+
+func (e PTOCountUpdated) Encode(enc *jsontext.Encoder, _ time.Time) error {
+ h := encoderHelper{enc: enc}
+ h.WriteToken(jsontext.BeginObject)
+ h.WriteToken(jsontext.String("pto_count"))
+ h.WriteToken(jsontext.Uint(uint64(e.PTOCount)))
+ h.WriteToken(jsontext.EndObject)
+ return h.err
+}
+
type PacketLost struct {
Header PacketHeader
Trigger PacketLossReason
rttStats.UpdateRTT(15*time.Millisecond, 0)
rttStats.UpdateRTT(20*time.Millisecond, 0)
rttStats.UpdateRTT(25*time.Millisecond, 0)
- minRTT := rttStats.MinRTT()
- smoothedRTT := rttStats.SmoothedRTT()
- latestRTT := rttStats.LatestRTT()
- rttVariance := rttStats.MeanDeviation()
- cwndInt := 4321
- bytesInt := 1234
- packetsInt := 42
name, ev := testEventEncoding(t, &MetricsUpdated{
- MinRTT: &minRTT,
- SmoothedRTT: &smoothedRTT,
- LatestRTT: &latestRTT,
- RTTVariance: &rttVariance,
- CongestionWindow: &cwndInt,
- BytesInFlight: &bytesInt,
- PacketsInFlight: &packetsInt,
+ MinRTT: rttStats.MinRTT(),
+ SmoothedRTT: rttStats.SmoothedRTT(),
+ LatestRTT: rttStats.LatestRTT(),
+ RTTVariance: rttStats.MeanDeviation(),
+ CongestionWindow: 4321,
+ BytesInFlight: 1234,
+ PacketsInFlight: 42,
})
require.Equal(t, "recovery:metrics_updated", name)
require.Equal(t, "congestion_avoidance", ev["new"])
}
-func TestMetricsUpdatedPTO(t *testing.T) {
- value := uint32(42)
- name, ev := testEventEncoding(t, &MetricsUpdated{PTOCount: &value})
+func TestPTOCountUpdated(t *testing.T) {
+ name, ev := testEventEncoding(t, &PTOCountUpdated{PTOCount: 42})
require.Equal(t, "recovery:metrics_updated", name)
require.Equal(t, float64(42), ev["pto_count"])