Draw every panel figure from the latest sample instead of holding the totals

This commit is contained in:
flamingcow
2026-08-04 13:49:21 -07:00
parent 4e60757937
commit fbfcabda7e
2 changed files with 6 additions and 31 deletions
+2 -24
View File
@@ -55,26 +55,10 @@ type direction struct {
drops uint64 drops uint64
base counterSet base counterSet
heldFrames heldValue
heldBytes heldValue
nic atomic.Uint64 nic atomic.Uint64
poller *nicPoller poller *nicPoller
} }
// Monotonic totals climb by tens of thousands per frame, which is unreadable
// churn at 60Hz, so the drawn value is held and refreshed a few times a second.
type heldValue struct {
v uint64
at time.Time
}
func (h *heldValue) get(now time.Time, cur uint64) uint64 {
if now.Sub(h.at) >= totalsHold {
h.v, h.at = cur, now
}
return h.v
}
// Everything the display reads, taken at one instant, so a pair of these // Everything the display reads, taken at one instant, so a pair of these
// describes both the rates and the errors over the span between them. // describes both the rates and the errors over the span between them.
type counterSet struct { type counterSet struct {
@@ -238,8 +222,6 @@ func (d *direction) reset() {
d.win.push(d.base) d.win.push(d.base)
d.mu.Unlock() d.mu.Unlock()
d.heldFrames = heldValue{}
d.heldBytes = heldValue{}
d.cable.reset() d.cable.reset()
} }
@@ -361,7 +343,7 @@ func (d *direction) sample() {
// Draws what the sampler last put in the ring rather than reading the counters // Draws what the sampler last put in the ring rather than reading the counters
// again, so the display never participates in the measurement. // again, so the display never participates in the measurement.
func (d *direction) displayView(t time.Time) view { func (d *direction) displayView() view {
d.mu.Lock() d.mu.Lock()
n := d.win.count() n := d.win.count()
if n == 0 { if n == 0 {
@@ -377,9 +359,6 @@ func (d *direction) displayView(t time.Time) view {
v.txGbps = d.win.latest(txRateGbps) v.txGbps = d.win.latest(txRateGbps)
v.rxGbps = d.win.latest(rxRateGbps) v.rxGbps = d.win.latest(rxRateGbps)
d.mu.Unlock() d.mu.Unlock()
v.rxFrames = d.heldFrames.get(t, v.rxFrames)
v.rxBytes = d.heldBytes.get(t, v.rxBytes)
return v return v
} }
@@ -569,7 +548,6 @@ const (
// How far back the shown errors reach and how many buckets the median runs // How far back the shown errors reach and how many buckets the median runs
// over, so a step in the rate lands half this late. // over, so a step in the rate lands half this late.
rateWindowSpan = time.Second rateWindowSpan = time.Second
totalsHold = 50 * time.Millisecond
) )
// One sampler for both directions, so they are read back to back on one clock // One sampler for both directions, so they are read back to back on one clock
@@ -734,7 +712,7 @@ func run(aName, bName string, nsPerM float64) error {
start = resetAll(dirs, stats) start = resetAll(dirs, stats)
} }
for i, d := range dirs { for i, d := range dirs {
views[i] = d.displayView(now) views[i] = d.displayView()
} }
// Empty until the probe has a stamp from each direction, so the // Empty until the probe has a stamp from each direction, so the
// panel shows nothing there rather than a placeholder. // panel shows nothing there rather than a placeholder.
+2 -5
View File
@@ -1,9 +1,6 @@
package main package main
import ( import "testing"
"testing"
"time"
)
// A reset re-bases from a fresh capture while the ring still holds buckets from // A reset re-bases from a fresh capture while the ring still holds buckets from
// just before it, so the newest bucket must not be left behind the new origin. // just before it, so the newest bucket must not be left behind the new origin.
@@ -22,7 +19,7 @@ func TestResetDoesNotUnderflowTotals(t *testing.T) {
d.rxStats[0].bytes.Store(9600) d.rxStats[0].bytes.Store(9600)
d.reset() d.reset()
v := d.displayView(time.Now()) v := d.displayView()
if v.rxFrames != 0 { if v.rxFrames != 0 {
t.Errorf("rxFrames = %d, want 0", v.rxFrames) t.Errorf("rxFrames = %d, want 0", v.rxFrames)
} }