Bucket received frames by their mac receive stamp and read one bucket back
This commit is contained in:
@@ -53,6 +53,14 @@ type direction struct {
|
||||
drops uint64
|
||||
base counterSet
|
||||
|
||||
// The completed receive bucket the display draws its rate from, refreshed by
|
||||
// the sampler because the buckets are keyed by the mac's clock and staleness
|
||||
// has to be judged against the wall.
|
||||
rateFrames uint64
|
||||
rateBytes uint64
|
||||
epoch int64
|
||||
epochAt time.Time
|
||||
|
||||
nic atomic.Uint64
|
||||
poller *nicPoller
|
||||
}
|
||||
@@ -129,25 +137,32 @@ func (w *rateWindow) at(i int) counterSet {
|
||||
return w.buf[i%len(w.buf)]
|
||||
}
|
||||
|
||||
func (w *rateWindow) latest(rate func(prev, cur counterSet, secs float64) float64) float64 {
|
||||
n := w.count()
|
||||
if n < 2 {
|
||||
return 0
|
||||
}
|
||||
prev, cur := w.at(n-2), w.at(n-1)
|
||||
secs := cur.t.Sub(prev.t).Seconds()
|
||||
if secs <= 0 {
|
||||
return 0
|
||||
}
|
||||
return rate(prev, cur, secs)
|
||||
}
|
||||
// How long the newest epoch may sit still before the wire is taken to have gone
|
||||
// quiet. A stamp only advances when a frame arrives, so a frozen epoch means no
|
||||
// traffic rather than an unchanged rate.
|
||||
const rateStale = 100 * time.Millisecond
|
||||
|
||||
func rxRatePPS(p, c counterSet, secs float64) float64 {
|
||||
return float64(c.s.rxFrames-p.s.rxFrames) / secs
|
||||
}
|
||||
|
||||
func rxRateGbps(p, c counterSet, secs float64) float64 {
|
||||
return gbps(c.s.rxBytes-p.s.rxBytes, c.s.rxFrames-p.s.rxFrames, secs)
|
||||
// The newest epoch is still filling, since frames received in it may not have
|
||||
// been drained yet, so the rate is read from the one before it.
|
||||
func (d *direction) readRateBucket(now time.Time) {
|
||||
var newest int64
|
||||
for _, r := range d.rxStats {
|
||||
if e := r.newest.Load(); e > newest {
|
||||
newest = e
|
||||
}
|
||||
}
|
||||
if newest > d.epoch {
|
||||
d.epoch, d.epochAt = newest, now
|
||||
}
|
||||
d.rateFrames, d.rateBytes = 0, 0
|
||||
if d.epoch == 0 || now.Sub(d.epochAt) > rateStale {
|
||||
return
|
||||
}
|
||||
for _, r := range d.rxStats {
|
||||
f, b := r.bucket(d.epoch - 1)
|
||||
d.rateFrames += f
|
||||
d.rateBytes += b
|
||||
}
|
||||
}
|
||||
|
||||
type sample struct {
|
||||
@@ -304,6 +319,7 @@ func totalView(views []view) view {
|
||||
func (d *direction) sample() {
|
||||
d.mu.Lock()
|
||||
d.win.push(d.capture())
|
||||
d.readRateBucket(time.Now())
|
||||
d.mu.Unlock()
|
||||
}
|
||||
|
||||
@@ -320,8 +336,8 @@ func (d *direction) displayView() view {
|
||||
if n >= 2 {
|
||||
v.window = errsBetween(d.win.at(0), d.win.at(n-1))
|
||||
}
|
||||
v.rxPPS = d.win.latest(rxRatePPS)
|
||||
v.rxGbps = d.win.latest(rxRateGbps)
|
||||
v.rxPPS = float64(d.rateFrames) / rateBucketSecs
|
||||
v.rxGbps = gbps(d.rateBytes, d.rateFrames, rateBucketSecs)
|
||||
d.mu.Unlock()
|
||||
return v
|
||||
}
|
||||
@@ -389,6 +405,11 @@ func buildDirection(label string, tx, rx endpoint) (*direction, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s rx socket for 0x%04x: %w", label, et, err)
|
||||
}
|
||||
// The mac already stamps every frame for the probe's sake, so this only
|
||||
// asks for the stamp to be delivered.
|
||||
if err := enableRxTimestamps(fd); err != nil {
|
||||
return nil, fmt.Errorf("%s rx timestamps for 0x%04x: %w", label, et, err)
|
||||
}
|
||||
d.rxFDs = append(d.rxFDs, fd)
|
||||
d.rxStats = append(d.rxStats, &rxStats{})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user