Reset cumulative error counts on space
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// Delivers a value every time space is pressed. Puts the terminal in
|
||||
// non-canonical mode so the keypress arrives without waiting for a newline,
|
||||
// and returns a function that restores the original settings.
|
||||
func watchSpace() (<-chan struct{}, func()) {
|
||||
ch := make(chan struct{}, 1)
|
||||
restore := func() {}
|
||||
fd := int(os.Stdin.Fd())
|
||||
|
||||
if orig, err := unix.IoctlGetTermios(fd, unix.TCGETS); err == nil {
|
||||
saved := *orig
|
||||
raw := *orig
|
||||
raw.Lflag &^= unix.ICANON | unix.ECHO
|
||||
raw.Cc[unix.VMIN] = 1
|
||||
raw.Cc[unix.VTIME] = 0
|
||||
if unix.IoctlSetTermios(fd, unix.TCSETS, &raw) == nil {
|
||||
restore = func() { unix.IoctlSetTermios(fd, unix.TCSETS, &saved) }
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 64)
|
||||
for {
|
||||
n, err := os.Stdin.Read(buf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, b := range buf[:n] {
|
||||
if b != ' ' {
|
||||
continue
|
||||
}
|
||||
select {
|
||||
case ch <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return ch, restore
|
||||
}
|
||||
@@ -45,10 +45,12 @@ type direction struct {
|
||||
rxFDs []int
|
||||
reports chan string
|
||||
|
||||
prev sample
|
||||
drops uint64
|
||||
nicTX nicCounters
|
||||
nicRX nicCounters
|
||||
prev sample
|
||||
drops uint64
|
||||
errBase sample
|
||||
dropBase uint64
|
||||
nicTX nicCounters
|
||||
nicRX nicCounters
|
||||
}
|
||||
|
||||
type sample struct {
|
||||
@@ -121,6 +123,14 @@ func (d *direction) snapshot() sample {
|
||||
return s
|
||||
}
|
||||
|
||||
// Counters keep climbing in the workers, so resetting just moves the origin
|
||||
// the display subtracts from.
|
||||
func (d *direction) resetErrors() {
|
||||
d.sampleDrops()
|
||||
d.errBase = d.snapshot()
|
||||
d.dropBase = d.drops
|
||||
}
|
||||
|
||||
func (d *direction) sampleDrops() {
|
||||
for _, fd := range d.rxFDs {
|
||||
d.drops += packetDrops(fd)
|
||||
@@ -157,7 +167,13 @@ func (d *direction) intervalRow(elapsed time.Duration, secs, target float64) []s
|
||||
rxB := now.rxBytes - p.rxBytes
|
||||
|
||||
d.sampleDrops()
|
||||
total := now.lost + now.crcErr + now.badMagic + now.badLen + d.drops
|
||||
b := d.errBase
|
||||
lost := now.lost - b.lost
|
||||
late := now.late - b.late
|
||||
crc := now.crcErr - b.crcErr
|
||||
badMagic := now.badMagic - b.badMagic
|
||||
badLen := now.badLen - b.badLen
|
||||
drops := d.drops - d.dropBase
|
||||
|
||||
return []string{
|
||||
uptime(elapsed),
|
||||
@@ -166,12 +182,12 @@ func (d *direction) intervalRow(elapsed time.Duration, secs, target float64) []s
|
||||
rateCell(gbps(txB, txF, secs), target),
|
||||
commas(uint64(float64(rxF) / secs)),
|
||||
rateCell(gbps(rxB, rxF, secs), target),
|
||||
statusCell(now.lost),
|
||||
statusCell(now.late),
|
||||
statusCell(now.crcErr),
|
||||
statusCell(now.badMagic),
|
||||
statusCell(d.drops),
|
||||
statusCell(total),
|
||||
statusCell(lost),
|
||||
statusCell(late),
|
||||
statusCell(crc),
|
||||
statusCell(badMagic),
|
||||
statusCell(drops),
|
||||
statusCell(lost + crc + badMagic + badLen + drops),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,7 +421,7 @@ func run(aName, bName, sizesArg, patArg string,
|
||||
humanBytes(uint64(sockBufSize(dirs[0].txFDs[0], unix.SO_SNDBUF))),
|
||||
humanBytes(uint64(sockBufSize(dirs[0].rxFDs[0], unix.SO_RCVBUF))))},
|
||||
}))
|
||||
fmt.Println(paint("rates are per interval; error counts are cumulative since start", cDim))
|
||||
fmt.Println(paint("rates are per interval; error counts are cumulative, press space to reset them", cDim))
|
||||
fmt.Println()
|
||||
|
||||
var doneTx, doneRx atomic.Bool
|
||||
@@ -423,6 +439,9 @@ func run(aName, bName, sizesArg, patArg string,
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
space, restoreTerm := watchSpace()
|
||||
defer restoreTerm()
|
||||
|
||||
start := time.Now()
|
||||
close(startTx)
|
||||
tick := time.NewTicker(reportInterval)
|
||||
@@ -437,6 +456,12 @@ func run(aName, bName, sizesArg, patArg string,
|
||||
doneRx.Store(true)
|
||||
wg.Wait()
|
||||
return nil
|
||||
case <-space:
|
||||
for _, d := range dirs {
|
||||
d.resetErrors()
|
||||
}
|
||||
stats.sinceHeader = 0
|
||||
fmt.Println(paint("error counts reset", cDim))
|
||||
case now := <-tick.C:
|
||||
secs := now.Sub(last).Seconds()
|
||||
last = now
|
||||
|
||||
Reference in New Issue
Block a user