Restructure stats into delta, mask, and aggregate layers
This commit is contained in:
@@ -12,13 +12,13 @@ const (
|
||||
)
|
||||
|
||||
type lossWindow struct {
|
||||
mu sync.Mutex
|
||||
base uint64
|
||||
inited bool
|
||||
quietEra bool
|
||||
bits []uint64
|
||||
lost atomic.Uint64
|
||||
late atomic.Uint64
|
||||
mu sync.Mutex
|
||||
base uint64
|
||||
inited bool
|
||||
maskedEra bool
|
||||
bits []uint64
|
||||
lost atomic.Uint64
|
||||
late atomic.Uint64
|
||||
|
||||
// The sending half of this stream. Both halves are in this process and the
|
||||
// receiving socket ignores its own outgoing frames, so this window is fed by
|
||||
@@ -48,24 +48,25 @@ func newLossWindows(tx []*txStats) []lossWindow {
|
||||
// the run. Nothing that arrives later is evidence enough to undo that, which is
|
||||
// why the sender's own frontier is the guard rather than a limit on how far a
|
||||
// single step may move.
|
||||
// quiet slides the window without charging: gaps written off during a cable
|
||||
// measure are its own link blip, suppressed at the source while the state
|
||||
// machine stays in sync with the wire.
|
||||
func (w *lossWindow) observe(seq uint64, quiet bool) bool {
|
||||
// masked slides the window without charging. A gap's charge lands at eviction,
|
||||
// which can fall after the mask lifts, so this source judges each charge
|
||||
// against the mask itself rather than leaving a deferred judgment to the
|
||||
// sampler's gate.
|
||||
func (w *lossWindow) observe(seq uint64, masked bool) bool {
|
||||
if seq >= w.sent.Load() {
|
||||
return false
|
||||
}
|
||||
w.mu.Lock()
|
||||
if w.quietEra && !quiet {
|
||||
if w.maskedEra && !masked {
|
||||
// Leaving a measure: the window was full when it began, so every hole
|
||||
// still inside went missing while failures were suppressed. Marking
|
||||
// them delivered keeps the write-off complete however the eviction
|
||||
// timing falls, instead of charging the gap's in-window tail later.
|
||||
// still inside went missing while the mask was up. Marking them
|
||||
// delivered keeps the write-off complete however the eviction timing
|
||||
// falls, instead of charging the gap's in-window tail later.
|
||||
for i := range w.bits {
|
||||
w.bits[i] = ^uint64(0)
|
||||
}
|
||||
}
|
||||
w.quietEra = quiet
|
||||
w.maskedEra = masked
|
||||
if !w.inited {
|
||||
// Start half a window below the first sequence seen, so anything the
|
||||
// sender put on the wire before it lands inside the window rather than
|
||||
@@ -77,13 +78,13 @@ func (w *lossWindow) observe(seq uint64, quiet bool) bool {
|
||||
}
|
||||
if seq < w.base {
|
||||
w.mu.Unlock()
|
||||
if !quiet {
|
||||
if !masked {
|
||||
w.late.Add(1)
|
||||
}
|
||||
return true
|
||||
}
|
||||
if seq >= w.base+lossSlots {
|
||||
w.evict(seq-lossSlots+1, quiet)
|
||||
w.evict(seq-lossSlots+1, masked)
|
||||
}
|
||||
idx := seq & (lossSlots - 1)
|
||||
w.bits[idx>>6] |= 1 << (idx & 63)
|
||||
@@ -91,7 +92,7 @@ func (w *lossWindow) observe(seq uint64, quiet bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *lossWindow) evict(newBase uint64, quiet bool) {
|
||||
func (w *lossWindow) evict(newBase uint64, masked bool) {
|
||||
span := newBase - w.base
|
||||
if span >= lossSlots {
|
||||
var missing uint64
|
||||
@@ -99,7 +100,7 @@ func (w *lossWindow) evict(newBase uint64, quiet bool) {
|
||||
missing += uint64(64 - bits.OnesCount64(w.bits[i]))
|
||||
w.bits[i] = 0
|
||||
}
|
||||
if !quiet {
|
||||
if !masked {
|
||||
w.lost.Add(missing + span - lossSlots)
|
||||
}
|
||||
w.base = newBase
|
||||
@@ -115,7 +116,7 @@ func (w *lossWindow) evict(newBase uint64, quiet bool) {
|
||||
}
|
||||
w.bits[word] &^= bit
|
||||
}
|
||||
if !quiet {
|
||||
if !masked {
|
||||
w.lost.Add(missing)
|
||||
}
|
||||
w.base = newBase
|
||||
|
||||
Reference in New Issue
Block a user