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
|
rxFDs []int
|
||||||
reports chan string
|
reports chan string
|
||||||
|
|
||||||
prev sample
|
prev sample
|
||||||
drops uint64
|
drops uint64
|
||||||
nicTX nicCounters
|
errBase sample
|
||||||
nicRX nicCounters
|
dropBase uint64
|
||||||
|
nicTX nicCounters
|
||||||
|
nicRX nicCounters
|
||||||
}
|
}
|
||||||
|
|
||||||
type sample struct {
|
type sample struct {
|
||||||
@@ -121,6 +123,14 @@ func (d *direction) snapshot() sample {
|
|||||||
return s
|
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() {
|
func (d *direction) sampleDrops() {
|
||||||
for _, fd := range d.rxFDs {
|
for _, fd := range d.rxFDs {
|
||||||
d.drops += packetDrops(fd)
|
d.drops += packetDrops(fd)
|
||||||
@@ -157,7 +167,13 @@ func (d *direction) intervalRow(elapsed time.Duration, secs, target float64) []s
|
|||||||
rxB := now.rxBytes - p.rxBytes
|
rxB := now.rxBytes - p.rxBytes
|
||||||
|
|
||||||
d.sampleDrops()
|
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{
|
return []string{
|
||||||
uptime(elapsed),
|
uptime(elapsed),
|
||||||
@@ -166,12 +182,12 @@ func (d *direction) intervalRow(elapsed time.Duration, secs, target float64) []s
|
|||||||
rateCell(gbps(txB, txF, secs), target),
|
rateCell(gbps(txB, txF, secs), target),
|
||||||
commas(uint64(float64(rxF) / secs)),
|
commas(uint64(float64(rxF) / secs)),
|
||||||
rateCell(gbps(rxB, rxF, secs), target),
|
rateCell(gbps(rxB, rxF, secs), target),
|
||||||
statusCell(now.lost),
|
statusCell(lost),
|
||||||
statusCell(now.late),
|
statusCell(late),
|
||||||
statusCell(now.crcErr),
|
statusCell(crc),
|
||||||
statusCell(now.badMagic),
|
statusCell(badMagic),
|
||||||
statusCell(d.drops),
|
statusCell(drops),
|
||||||
statusCell(total),
|
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].txFDs[0], unix.SO_SNDBUF))),
|
||||||
humanBytes(uint64(sockBufSize(dirs[0].rxFDs[0], unix.SO_RCVBUF))))},
|
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()
|
fmt.Println()
|
||||||
|
|
||||||
var doneTx, doneRx atomic.Bool
|
var doneTx, doneRx atomic.Bool
|
||||||
@@ -423,6 +439,9 @@ func run(aName, bName, sizesArg, patArg string,
|
|||||||
sig := make(chan os.Signal, 1)
|
sig := make(chan os.Signal, 1)
|
||||||
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
space, restoreTerm := watchSpace()
|
||||||
|
defer restoreTerm()
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
close(startTx)
|
close(startTx)
|
||||||
tick := time.NewTicker(reportInterval)
|
tick := time.NewTicker(reportInterval)
|
||||||
@@ -437,6 +456,12 @@ func run(aName, bName, sizesArg, patArg string,
|
|||||||
doneRx.Store(true)
|
doneRx.Store(true)
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
return nil
|
return nil
|
||||||
|
case <-space:
|
||||||
|
for _, d := range dirs {
|
||||||
|
d.resetErrors()
|
||||||
|
}
|
||||||
|
stats.sinceHeader = 0
|
||||||
|
fmt.Println(paint("error counts reset", cDim))
|
||||||
case now := <-tick.C:
|
case now := <-tick.C:
|
||||||
secs := now.Sub(last).Seconds()
|
secs := now.Sub(last).Seconds()
|
||||||
last = now
|
last = now
|
||||||
|
|||||||
Reference in New Issue
Block a user