Restructure stats into delta, mask, and aggregate layers
This commit is contained in:
@@ -112,9 +112,11 @@ const (
|
||||
snrWarnMargin = 1.0
|
||||
)
|
||||
|
||||
// While masked a measure owns the module: every register it would poll is the
|
||||
// measure's own disturbance, so nothing is read at all.
|
||||
type phyModule struct {
|
||||
dev phyDev
|
||||
busy atomic.Bool
|
||||
dev phyDev
|
||||
masked atomic.Bool
|
||||
|
||||
mu sync.Mutex
|
||||
sampled bool
|
||||
@@ -131,9 +133,8 @@ type phyModule struct {
|
||||
notes []string
|
||||
}
|
||||
|
||||
// Silent while a measure owns the module.
|
||||
func (m *phyModule) poll() error {
|
||||
if m.busy.Load() {
|
||||
func (m *phyModule) poll(hist *history) error {
|
||||
if m.masked.Load() {
|
||||
return nil
|
||||
}
|
||||
link, linkRaw, err := devLinkUp(m.dev)
|
||||
@@ -156,11 +157,11 @@ func (m *phyModule) poll() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Setting busy is a measure's first act, so busy still clear here proves
|
||||
// every read above finished before the measure disturbed anything; a
|
||||
// measure that began mid-read makes the samples ambiguous, and forgive()
|
||||
// Setting masked is a measure's first act, so masked still clear here
|
||||
// proves every read above finished before the measure disturbed anything;
|
||||
// a measure that began mid-read makes the samples ambiguous, and forgive()
|
||||
// re-baselines after it anyway.
|
||||
if m.busy.Load() {
|
||||
if m.masked.Load() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -188,6 +189,7 @@ func (m *phyModule) poll() error {
|
||||
m.ber += ber
|
||||
m.retrains += rt
|
||||
m.recentDelta = delta
|
||||
hist.addCorrected(time.Now(), delta)
|
||||
} else {
|
||||
m.recentDelta = 0
|
||||
m.primed = true
|
||||
@@ -205,7 +207,7 @@ func (m *phyModule) takeNotes() []string {
|
||||
return n
|
||||
}
|
||||
|
||||
func (m *phyModule) run(done *atomic.Bool) {
|
||||
func (m *phyModule) run(done *atomic.Bool, hist *history) {
|
||||
tick := time.NewTicker(phyInterval)
|
||||
defer tick.Stop()
|
||||
|
||||
@@ -213,7 +215,7 @@ func (m *phyModule) run(done *atomic.Bool) {
|
||||
var lastErr error
|
||||
for !done.Load() {
|
||||
<-tick.C
|
||||
if err := m.poll(); err != nil {
|
||||
if err := m.poll(hist); err != nil {
|
||||
dark++
|
||||
lastErr = err
|
||||
if dark >= phyMaxDark {
|
||||
@@ -437,12 +439,12 @@ func bcmEnd(mods []*phyModule) *bcm {
|
||||
// relink, so the MDI resolution is the fresh one.
|
||||
func measureCable(mods []*phyModule, done *atomic.Bool) (cableInfo, error) {
|
||||
for _, m := range mods {
|
||||
m.busy.Store(true)
|
||||
m.masked.Store(true)
|
||||
}
|
||||
defer func() {
|
||||
for _, m := range mods {
|
||||
m.forgive()
|
||||
m.busy.Store(false)
|
||||
m.masked.Store(false)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -486,10 +488,10 @@ func measureCable(mods []*phyModule, done *atomic.Bool) (cableInfo, error) {
|
||||
type cableDiag struct {
|
||||
mods []*phyModule
|
||||
|
||||
// While set, every failure counter is suppressed at its source: the
|
||||
// measure's own link blip is never counted anywhere, rather than counted,
|
||||
// hidden and reverted.
|
||||
measuring atomic.Bool
|
||||
// The mask itself. While set, every fault delta is dropped at the mask
|
||||
// gate before it can reach an aggregate: the measure's own link blip is
|
||||
// never counted anywhere, rather than counted, hidden and reverted.
|
||||
masked atomic.Bool
|
||||
|
||||
mu sync.Mutex
|
||||
info cableInfo
|
||||
@@ -503,7 +505,7 @@ func newCableDiag(mods []*phyModule, info cableInfo) *cableDiag {
|
||||
func (c *cableDiag) snapshot() (cableInfo, cableLengths, bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return c.info, c.lengths, c.measuring.Load()
|
||||
return c.info, c.lengths, c.masked.Load()
|
||||
}
|
||||
|
||||
func (c *cableDiag) resetLengths() {
|
||||
@@ -516,7 +518,7 @@ func (c *cableDiag) resetLengths() {
|
||||
// tester that cannot run its diagnostics must not keep testing: the failure is
|
||||
// fatal, and the reboot's driver reload is also the wedged-µC recovery.
|
||||
func (c *cableDiag) kick(done *atomic.Bool) bool {
|
||||
if !c.measuring.CompareAndSwap(false, true) {
|
||||
if !c.masked.CompareAndSwap(false, true) {
|
||||
return false
|
||||
}
|
||||
go func() {
|
||||
@@ -533,7 +535,7 @@ func (c *cableDiag) kick(done *atomic.Bool) bool {
|
||||
}
|
||||
}
|
||||
c.mu.Unlock()
|
||||
c.measuring.Store(false)
|
||||
c.masked.Store(false)
|
||||
}()
|
||||
return true
|
||||
}
|
||||
@@ -575,9 +577,9 @@ func openModules(names [2]string) ([]*phyModule, [2]string, error) {
|
||||
time.Sleep(moduleUpPoll)
|
||||
}
|
||||
m := &phyModule{dev: dev}
|
||||
// Born busy: the pollers stay silent through bringup's SETs and
|
||||
// Born masked: the pollers stay silent through bringup's SETs and
|
||||
// retrains until the first measure completes and lifts the gate.
|
||||
m.busy.Store(true)
|
||||
m.masked.Store(true)
|
||||
mods = append(mods, m)
|
||||
}
|
||||
return mods, idents, nil
|
||||
|
||||
Reference in New Issue
Block a user