diff --git a/main.go b/main.go index 9f923f0..d510281 100644 --- a/main.go +++ b/main.go @@ -94,24 +94,25 @@ func (d *direction) capture(t time.Time) counterSet { return counterSet{t: t, s: d.snapshot(), drops: d.drops, nic: d.nic.Load()} } -// Late is counted but left out of the total, since a reordered frame arrived. +// What someone testing a cable is asking, rather than how each failure happened +// to be noticed. Corruption arrives as three different symptoms and the kernel +// drops frames for reasons that are ours rather than the cable's, but none of +// that is a distinction worth reading off a panel. type errs struct { - lost, late uint64 - crc, badMagic uint64 - badLen uint64 - kdrop, link uint64 + lost uint64 + corrupt uint64 + link uint64 + internal uint64 } func (e errs) total() uint64 { - return e.lost + e.crc + e.badMagic + e.badLen + e.kdrop + e.link + return e.lost + e.corrupt + e.link + e.internal } func (e errs) add(o errs) errs { return errs{ - lost: e.lost + o.lost, late: e.late + o.late, - crc: e.crc + o.crc, badMagic: e.badMagic + o.badMagic, - badLen: e.badLen + o.badLen, - kdrop: e.kdrop + o.kdrop, link: e.link + o.link, + lost: e.lost + o.lost, corrupt: e.corrupt + o.corrupt, + link: e.link + o.link, internal: e.internal + o.internal, } } @@ -309,11 +310,9 @@ var intervalCols = []colSpec{ {title: "RX pps", width: 9, right: true}, {title: "RX Gb/s", width: 7, right: true}, {title: "LOST", width: 11, right: true}, - {title: "LATE", width: 9, right: true}, - {title: "CRC", width: 7, right: true}, - {title: "BADMAG", width: 7, right: true}, - {title: "KDROP", width: 11, right: true}, - {title: "LINK", width: 13, right: true}, + {title: "CORRUPT", width: 11, right: true}, + {title: "LINK", width: 11, right: true}, + {title: "INTERNAL", width: 11, right: true}, {title: "ERRORS", width: 13, right: true}, {title: "MIN ns", width: 9, right: true}, {title: "LEN m", width: 6, right: true}, @@ -332,16 +331,21 @@ type view struct { func errsBetween(b, n counterSet) errs { return errs{ - lost: n.s.lost - b.s.lost, - late: n.s.late - b.s.late, - crc: n.s.crcErr - b.s.crcErr, - badMagic: n.s.badMagic - b.s.badMagic, - badLen: n.s.badLen - b.s.badLen, - kdrop: n.drops - b.drops, + lost: n.s.lost - b.s.lost, + // Three ways of noticing one thing: a payload that does not match its + // checksum, a header that is not ours, and a length that cannot be. + corrupt: (n.s.crcErr - b.s.crcErr) + (n.s.badMagic - b.s.badMagic) + + (n.s.badLen - b.s.badLen), // A frame the stack refused and a frame the driver dropped are the same // failure seen from either side of the ring, and never the same frame // twice: a send that fails never reaches the driver to be dropped. link: (n.nic - b.nic) + (n.s.txErrs - b.s.txErrs) + (n.s.rxErrs - b.s.rxErrs), + // Ours rather than the cable's: frames the kernel threw away because we + // did not drain the ring fast enough, and frames so far out of order + // that our own bookkeeping had already written them off. The second is + // unreachable while each stream has a flow rule to its own queue, which + // is exactly why it is worth counting: it fires if that stops holding. + internal: (n.drops - b.drops) + (n.s.late - b.s.late), } } @@ -433,11 +437,9 @@ func (d *direction) row(elapsed time.Duration, v view, target float64, length st commas(uint64(v.rxPPS)), rateCell(v.rxGbps, target), statusCell(v.since.lost), - statusCell(v.since.late), - statusCell(v.since.crc), - statusCell(v.since.badMagic), - statusCell(v.since.kdrop), + statusCell(v.since.corrupt), statusCell(v.since.link), + statusCell(v.since.internal), statusCell(v.since.total()), paint(v.cable.minText(), cCyan), paint(length, cCyan), diff --git a/ui.go b/ui.go index 5d8fb09..3afb3a3 100644 --- a/ui.go +++ b/ui.go @@ -195,12 +195,9 @@ var errRows = []struct { get func(errs) uint64 }{ {"lost", func(e errs) uint64 { return e.lost }}, - {"late", func(e errs) uint64 { return e.late }}, - {"crc", func(e errs) uint64 { return e.crc }}, - {"bad magic", func(e errs) uint64 { return e.badMagic }}, - {"bad length", func(e errs) uint64 { return e.badLen }}, - {"kernel drops", func(e errs) uint64 { return e.kdrop }}, + {"corrupt", func(e errs) uint64 { return e.corrupt }}, {"link", func(e errs) uint64 { return e.link }}, + {"internal", func(e errs) uint64 { return e.internal }}, } func (d *display) errBlock(x, w, y int, e errs) int {