diff --git a/main.go b/main.go index f35484f..0cb9622 100644 --- a/main.go +++ b/main.go @@ -273,7 +273,7 @@ func buildDirection(label string, tx, rx endpoint, patIdx int, sizes []int, cfg } for i := 0; i < cfg.txWorkers; i++ { - fd, err := openTxSocket(tx.idx, cfg.sndbuf) + fd, err := openTxSocket(tx.idx) if err != nil { return nil, fmt.Errorf("%s tx socket: %w", label, err) } @@ -281,7 +281,7 @@ func buildDirection(label string, tx, rx endpoint, patIdx int, sizes []int, cfg d.txStats = append(d.txStats, &txStats{}) } for i := 0; i < cfg.rxWorkers; i++ { - fd, err := openRxSocket(rx.idx, cfg.rcvbuf, cfg.fanoutID, fm) + fd, err := openRxSocket(rx.idx, cfg.fanoutID, fm) if err != nil { return nil, fmt.Errorf("%s rx socket: %w", label, err) } @@ -313,7 +313,6 @@ func (d *direction) start(wg *sync.WaitGroup, doneTx, doneRx *atomic.Bool, cfg c fd: fd, batch: cfg.batch, cpu: cpuAt(cfg.rxCPUs, i), - verify: cfg.verify, spec: d.spec, stats: d.rxStats[i], streams: d.streams, @@ -341,9 +340,6 @@ type config struct { txWorkers int rxWorkers int batch int - verify bool - sndbuf int - rcvbuf int fanout string fanoutID int txCPUs []int @@ -360,46 +356,25 @@ func main() { txN = flag.Int("tx", 4, "tx workers per direction") rxN = flag.Int("rx", 4, "rx workers per direction") batch = flag.Int("batch", 64, "frames per sendmmsg/recvmmsg call") - verify = flag.Bool("verify", true, "verify payload CRC32C on receive") interval = flag.Duration("interval", time.Second, "report interval") - drain = flag.Duration("drain", 500*time.Millisecond, "keep receiving this long after tx stops, so in-flight frames are not counted as lost") fanout = flag.String("fanout", "lb", "rx fanout mode: none, hash, lb, cpu, rollover") duplex = flag.Bool("duplex", true, "run both directions simultaneously") - sndbuf = flag.Int("sndbuf", 8<<20, "SO_SNDBUFFORCE per tx socket") - rcvbuf = flag.Int("rcvbuf", 64<<20, "SO_RCVBUFFORCE per rx socket") txCPUs = flag.String("txcpus", "", "comma-separated CPUs to pin tx workers to") rxCPUs = flag.String("rxcpus", "", "comma-separated CPUs to pin rx workers to") - governor = flag.String("governor", "performance", "required cpufreq governor") - coalesce = flag.Uint("coalesce-usecs", 25, "required fixed rx/tx coalesce usecs, with adaptive coalescing off") - rxRing = flag.Uint("rx-ring", 8160, "required rx ring size, clamped to hardware maximum") - txRing = flag.Uint("tx-ring", 4096, "required tx ring size, clamped to hardware maximum") - color = flag.String("color", "auto", "colored output: auto, always, never") ) flag.Parse() - if err := initColor(*color); err != nil { - fmt.Fprintln(os.Stderr, "error:", err) - os.Exit(1) - } - - tcfg := systemConfig{ - governor: *governor, - rxUsecs: uint32(*coalesce), - txUsecs: uint32(*coalesce), - rxRing: uint32(*rxRing), - txRing: uint32(*txRing), - } - if err := run(*aName, *bName, *sizesArg, *patArg, *fanout, *txCPUs, *rxCPUs, - *duration, *interval, *drain, *txN, *rxN, *batch, *sndbuf, *rcvbuf, *verify, *duplex, tcfg); err != nil { + *duration, *interval, *txN, *rxN, *batch, *duplex); err != nil { fmt.Fprintln(os.Stderr, "error:", err) os.Exit(1) } } +const drainTime = 500 * time.Millisecond + func run(aName, bName, sizesArg, patArg, fanout, txCPUsArg, rxCPUsArg string, - duration, interval, drain time.Duration, txN, rxN, batch, sndbuf, rcvbuf int, - verify, duplex bool, tcfg systemConfig) error { + duration, interval time.Duration, txN, rxN, batch int, duplex bool) error { if aName == "" || bName == "" { return fmt.Errorf("both -a and -b are required") @@ -441,7 +416,7 @@ func run(aName, bName, sizesArg, patArg, fanout, txCPUsArg, rxCPUsArg string, var fatal []string var tuneRows [][]string - for _, r := range configureSystem(tcfg, ifnames) { + for _, r := range configureSystem(ifnames) { tuneRows = append(tuneRows, []string{r.item, r.status(), r.detail()}) if r.fatal { fatal = append(fatal, r.item) @@ -458,9 +433,6 @@ func run(aName, bName, sizesArg, patArg, fanout, txCPUsArg, rxCPUsArg string, txWorkers: txN, rxWorkers: rxN, batch: batch, - verify: verify, - sndbuf: sndbuf, - rcvbuf: rcvbuf, fanout: fanout, txCPUs: txCPUs, rxCPUs: rxCPUs, @@ -516,7 +488,7 @@ func run(aName, bName, sizesArg, patArg, fanout, txCPUsArg, rxCPUsArg string, {"ethertype", fmt.Sprintf("0x%04x", etherType)}, {"workers", fmt.Sprintf("%d tx, %d rx per direction", txN, rxN)}, {"batch", fmt.Sprintf("%d frames per syscall", batch)}, - {"payload verify", fmt.Sprintf("%v", verify)}, + {"payload verify", "crc32c on every frame"}, {"rx fanout", fanout}, {"duplex", fmt.Sprintf("%v", duplex)}, {"socket buffers", fmt.Sprintf("sndbuf %s, rcvbuf %s (granted)", @@ -589,7 +561,7 @@ loop: doneTx.Store(true) elapsed := time.Since(start).Seconds() - time.Sleep(drain) + time.Sleep(drainTime) doneRx.Store(true) wg.Wait() diff --git a/render.go b/render.go index f1185a5..b6d2f33 100644 --- a/render.go +++ b/render.go @@ -2,7 +2,6 @@ package main import ( "fmt" - "os" "strings" ) @@ -17,29 +16,8 @@ const ( cGrey = "\x1b[90m" ) -var useColor bool - -func initColor(mode string) error { - switch mode { - case "always": - useColor = true - case "never": - useColor = false - case "auto": - if os.Getenv("NO_COLOR") != "" || os.Getenv("TERM") == "dumb" { - useColor = false - return nil - } - st, err := os.Stdout.Stat() - useColor = err == nil && st.Mode()&os.ModeCharDevice != 0 - default: - return fmt.Errorf("unknown color mode %q (want auto, always, never)", mode) - } - return nil -} - func paint(s, code string) string { - if !useColor || s == "" { + if s == "" { return s } return code + s + cReset diff --git a/rx.go b/rx.go index 0cc505b..04adf3a 100644 --- a/rx.go +++ b/rx.go @@ -28,7 +28,6 @@ type rxWorker struct { fd int batch int cpu int - verify bool spec *frameSpec stats *rxStats streams []streamState @@ -79,9 +78,6 @@ func (w *rxWorker) run(done *atomic.Bool) { } } - if !w.verify { - continue - } if p.payLen > len(w.spec.ref) { w.stats.badLen.Add(1) continue diff --git a/sock.go b/sock.go index 4efd100..ac99258 100644 --- a/sock.go +++ b/sock.go @@ -31,7 +31,12 @@ func sockBufSize(fd, opt int) int { return v } -func openTxSocket(ifindex, sndbuf int) (int, error) { +const ( + sndbufBytes = 8 << 20 + rcvbufBytes = 64 << 20 +) + +func openTxSocket(ifindex int) (int, error) { fd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW, 0) if err != nil { return -1, fmt.Errorf("socket: %w", err) @@ -44,20 +49,20 @@ func openTxSocket(ifindex, sndbuf int) (int, error) { unix.Close(fd) return -1, fmt.Errorf("qdisc bypass: %w", err) } - if err := setBufForce(fd, unix.SO_SNDBUFFORCE, unix.SO_SNDBUF, sndbuf); err != nil { + if err := setBufForce(fd, unix.SO_SNDBUFFORCE, unix.SO_SNDBUF, sndbufBytes); err != nil { unix.Close(fd) return -1, fmt.Errorf("sndbuf: %w", err) } return fd, nil } -func openRxSocket(ifindex, rcvbuf, fanoutID, fanoutMode int) (int, error) { +func openRxSocket(ifindex, fanoutID, fanoutMode int) (int, error) { proto := int(htons(etherType)) fd, err := unix.Socket(unix.AF_PACKET, unix.SOCK_RAW, proto) if err != nil { return -1, fmt.Errorf("socket: %w", err) } - if err := setBufForce(fd, unix.SO_RCVBUFFORCE, unix.SO_RCVBUF, rcvbuf); err != nil { + if err := setBufForce(fd, unix.SO_RCVBUFFORCE, unix.SO_RCVBUF, rcvbufBytes); err != nil { unix.Close(fd) return -1, fmt.Errorf("rcvbuf: %w", err) } diff --git a/system.go b/system.go index d5b1f3d..a323138 100644 --- a/system.go +++ b/system.go @@ -62,13 +62,12 @@ type ethtoolCoalesce struct { rateSampleInterval uint32 } -type systemConfig struct { - governor string - rxUsecs uint32 - txUsecs uint32 - rxRing uint32 - txRing uint32 -} +const ( + wantGovernor = "performance" + wantCoalesceUsecs = 25 + wantRxRing = 8160 + wantTxRing = 4096 +) type checkResult struct { item string @@ -311,15 +310,15 @@ func withIoctlSocket(fn func(fd int) []checkResult) []checkResult { return fn(fd) } -func configureSystem(cfg systemConfig, ifnames []string) []checkResult { +func configureSystem(ifnames []string) []checkResult { return withIoctlSocket(func(fd int) []checkResult { - out := []checkResult{checkGovernor(cfg.governor)} + out := []checkResult{checkGovernor(wantGovernor)} for _, ifname := range ifnames { out = append(out, checkLinkUp(fd, ifname)) - out = append(out, checkCoalesce(fd, ifname, cfg.rxUsecs, cfg.txUsecs)) + out = append(out, checkCoalesce(fd, ifname, wantCoalesceUsecs, wantCoalesceUsecs)) carrierWait := 3 * time.Second - r, reset := checkRings(fd, ifname, cfg.rxRing, cfg.txRing) + r, reset := checkRings(fd, ifname, wantRxRing, wantTxRing) out = append(out, r) if reset { carrierWait = 10 * time.Second