From 12cef6a89b68224b0b52c2183f3f8293cff63ff4 Mon Sep 17 00:00:00 2001 From: flamingcow Date: Tue, 4 Aug 2026 22:12:07 -0700 Subject: [PATCH] Fold the shutdown flags into one, take the smallest frame to the wire minimum, drop the speed column --- loss.go | 9 +++++---- main.go | 32 ++++++++++++++++---------------- sock.go | 5 ++--- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/loss.go b/loss.go index ed48417..aec5dca 100644 --- a/loss.go +++ b/loss.go @@ -36,8 +36,8 @@ func newLossWindows(tx []*txStats) []lossWindow { return w } -// A sequence number is only judged once it falls out of the window, so frames -// still queued in another rx worker are never miscounted as lost. +// A sequence number is only judged once it falls out of the window, so a frame +// that has arrived but not yet been drained is never miscounted as lost. // // Reports whether the sequence number could have come off the wire at all. One // above what the sender has reached is a damaged header rather than a gap, and @@ -53,8 +53,9 @@ func (w *lossWindow) observe(seq uint64) bool { } w.mu.Lock() if !w.inited { - // Start half a window below the first sequence seen, so frames another - // rx worker is still holding land inside the window rather than late. + // Start half a window below the first sequence seen, so anything the + // sender put on the wire before it lands inside the window rather than + // below the base. if seq > lossSlots/2 { w.base = seq - lossSlots/2 } diff --git a/main.go b/main.go index cbc9ddb..64a0edc 100644 --- a/main.go +++ b/main.go @@ -437,7 +437,7 @@ func buildDirection(label string, tx, rx endpoint) (*direction, error) { return d, nil } -func (d *direction) start(wg *sync.WaitGroup, doneTx, doneRx *atomic.Bool, rxReady *sync.WaitGroup, startTx <-chan struct{}) { +func (d *direction) start(wg *sync.WaitGroup, done *atomic.Bool, rxReady *sync.WaitGroup, startTx <-chan struct{}) { for i, fd := range d.txFDs { w := &txWorker{ fd: fd, @@ -450,7 +450,7 @@ func (d *direction) start(wg *sync.WaitGroup, doneTx, doneRx *atomic.Bool, rxRea wg.Add(1) go func() { defer wg.Done() - w.run(doneTx) + w.run(done) }() } for i, fd := range d.rxFDs { @@ -466,7 +466,7 @@ func (d *direction) start(wg *sync.WaitGroup, doneTx, doneRx *atomic.Bool, rxRea wg.Add(1) go func() { defer wg.Done() - w.run(doneRx) + w.run(done) }() } @@ -474,20 +474,20 @@ func (d *direction) start(wg *sync.WaitGroup, doneTx, doneRx *atomic.Bool, rxRea wg.Add(1) go func() { defer wg.Done() - sender.run(doneTx, startTx) + sender.run(done, startTx) }() receiver := &probeReceiver{fd: d.probeRxFD, stats: d.cable, ready: rxReady} wg.Add(1) go func() { defer wg.Done() - receiver.run(doneRx) + receiver.run(done) }() wg.Add(1) go func() { defer wg.Done() - d.poller.run(doneRx, startTx) + d.poller.run(done, startTx) }() } @@ -514,7 +514,9 @@ const ( linkSpeed = 10.0 ) -var frameSizes = []int{64, 128, 256, 512, 1024, 1280, 1514} +// The mac appends the fcs, so 60 and 1514 here are the smallest and largest +// standard frames, 64 and 1518 on the wire. +var frameSizes = []int{60, 128, 256, 512, 1024, 1280, 1514} func main() { // The names the kernel gives the only two ports built into it, since as @@ -611,19 +613,18 @@ func run(aName, bName string, nsPerM float64) error { var linkRows [][]string for _, e := range []endpoint{a, b} { linkRows = append(linkRows, []string{ - paint(e.tag, cCyan), e.name, e.macString(), - fmt.Sprintf("%.0f Gb/s", linkSpeed), fmt.Sprintf("%d", e.mtu), + paint(e.tag, cCyan), e.name, e.macString(), fmt.Sprintf("%d", e.mtu), }) } fmt.Println(renderBox("LINKS", - []string{"TAG", "INTERFACE", "MAC", "SPEED", "MTU"}, - []bool{false, false, false, true, true}, linkRows)) + []string{"TAG", "INTERFACE", "MAC", "MTU"}, + []bool{false, false, false, true}, linkRows)) fmt.Println() // One row carries both directions, so line rate is both links at once. target := linkSpeed * float64(len(dirs)) - var doneTx, doneRx atomic.Bool + var done atomic.Bool var wg sync.WaitGroup var rxReady sync.WaitGroup startTx := make(chan struct{}) @@ -631,13 +632,13 @@ func run(aName, bName string, nsPerM float64) error { rxReady.Add(len(d.rxFDs) + 1) } for _, d := range dirs { - d.start(&wg, &doneTx, &doneRx, &rxReady, startTx) + d.start(&wg, &done, &rxReady, startTx) } samp := &sampler{dirs: dirs} wg.Add(1) go func() { defer wg.Done() - samp.run(&doneRx, startTx) + samp.run(&done, startTx) }() rxReady.Wait() @@ -673,8 +674,7 @@ func run(aName, bName string, nsPerM float64) error { for { select { case <-sig: - doneTx.Store(true) - doneRx.Store(true) + done.Store(true) wg.Wait() return nil case <-space: diff --git a/sock.go b/sock.go index b68f240..564df22 100644 --- a/sock.go +++ b/sock.go @@ -15,9 +15,8 @@ type mmsghdr struct { func htons(v uint16) uint16 { return v<<8 | v>>8 } -// Set through the FORCE options alone: the plain ones are clamped to wmem_max -// and rmem_max, so falling back to them would quietly leave a fraction of this -// and go on measuring as though it had not. +// Set through the FORCE options alone, since the plain ones are clamped to +// wmem_max and rmem_max and would quietly leave a fraction of this. const ( sndbufBytes = 8 << 20 rcvbufBytes = 64 << 20