Cycle every payload pattern per packet and always run both directions

This commit is contained in:
flamingcow
2026-07-25 23:03:31 -07:00
parent 0f16edfe61
commit e77574712d
8 changed files with 75 additions and 104 deletions
+21 -37
View File
@@ -414,15 +414,15 @@ func (d *direction) row(elapsed time.Duration, v view, target float64, length st
}
}
// Read once a second rather than per frame, since these are sysfs files; the
// display uses whatever the last sample left behind.
// Sampled once a second, since these are sysfs reads; the display uses whatever
// the last sample left behind.
func (d *direction) sampleNIC() {
tx := readNIC(d.tx.name)
rx := readNIC(d.rx.name)
d.nicNow = tx.tx + rx.rx + tx.carrierDown
}
func buildDirection(label string, tx, rx endpoint, patIdx int, sizes []int, cfg config) (*direction, error) {
func buildDirection(label string, tx, rx endpoint, sizes []int, cfg config) (*direction, error) {
d := &direction{
label: label,
short: tx.tag + "→" + rx.tag,
@@ -434,7 +434,7 @@ func buildDirection(label string, tx, rx endpoint, patIdx int, sizes []int, cfg
for i := 0; i < cfg.streams; i++ {
et := uint16(etherBase + i)
d.specs = append(d.specs, newFrameSpec(patIdx, rx.mac, tx.mac, et, sizes))
d.specs = append(d.specs, newFrameSpec(rx.mac, tx.mac, et, sizes))
fd, err := openTxSocket(tx.idx)
if err != nil {
@@ -451,10 +451,9 @@ func buildDirection(label string, tx, rx endpoint, patIdx int, sizes []int, cfg
d.rxStats = append(d.rxStats, &rxStats{})
}
// The probe carries its own ethertype so it lands on a socket of its own, but
// it is left unsteered: it is a few frames a second and does not need a queue
// to itself, and the stamps are taken at the wire either way.
d.probeSpec = newFrameSpec(patIdx, rx.mac, tx.mac, cfg.probeEther, []int{probeSize})
// Deliberately given no flow rule: a few frames a second does not need a
// queue of its own, and the stamps are taken at the wire either way.
d.probeSpec = newFrameSpec(rx.mac, tx.mac, cfg.probeEther, []int{probeSize})
fd, err := openTxSocket(tx.idx)
if err != nil {
return nil, fmt.Errorf("%s probe tx socket: %w", label, err)
@@ -549,17 +548,15 @@ func main() {
aName = flag.String("a", "", "first interface")
bName = flag.String("b", "", "second interface")
sizesArg = flag.String("sizes", "64,128,256,512,1024,1280,1514", "frame sizes in bytes, excluding FCS, cycled per packet")
patArg = flag.String("pattern", "prbs", "payload pattern")
streams = flag.Int("streams", 7, "independent streams per direction, capped by rx rings; each gets its own ethertype, steered by a flow rule to its own rx queue")
batch = flag.Int("batch", 64, "frames per sendmmsg/recvmmsg call")
duplex = flag.Bool("duplex", true, "run both directions simultaneously")
zeroNS = flag.Float64("zero-ns", 4327.5, "both directions summed at zero cable length; belongs to the media adapters, recalibrate when they change")
nsPerM = flag.Float64("ns-per-m", 10.909, "both directions summed, per metre of cable")
zeroNS = flag.Float64("zero-ns", 2163.77, "mean of both directions at zero cable length; belongs to the media adapters, recalibrate when they change")
nsPerM = flag.Float64("ns-per-m", 5.4545, "mean of both directions, per metre of cable")
)
flag.Parse()
if err := run(*aName, *bName, *sizesArg, *patArg,
*streams, *batch, *duplex, *zeroNS, *nsPerM); err != nil {
if err := run(*aName, *bName, *sizesArg,
*streams, *batch, *zeroNS, *nsPerM); err != nil {
fmt.Fprintln(os.Stderr, "error:", err)
os.Exit(1)
}
@@ -576,8 +573,8 @@ const (
totalsHold = 50 * time.Millisecond
)
func run(aName, bName, sizesArg, patArg string,
nStreams, batch int, duplex bool, zeroNS, nsPerM float64) error {
func run(aName, bName, sizesArg string,
nStreams, batch int, zeroNS, nsPerM float64) error {
if aName == "" || bName == "" {
return fmt.Errorf("both -a and -b are required")
@@ -586,10 +583,6 @@ func run(aName, bName, sizesArg, patArg string,
if err != nil {
return err
}
patIdx, err := patternIndex(patArg)
if err != nil {
return err
}
a, err := lookupEndpoint(aName)
if err != nil {
return err
@@ -641,17 +634,12 @@ func run(aName, bName, sizesArg, patArg string,
}
var dirs []*direction
d0, err := buildDirection(a.name+"->"+b.name, a, b, patIdx, sizes, cfg)
if err != nil {
return err
}
dirs = append(dirs, d0)
if duplex {
d1, err := buildDirection(b.name+"->"+a.name, b, a, patIdx, sizes, cfg)
for _, p := range [][2]endpoint{{a, b}, {b, a}} {
d, err := buildDirection(p[0].name+"->"+p[1].name, p[0], p[1], sizes, cfg)
if err != nil {
return err
}
dirs = append(dirs, d1)
dirs = append(dirs, d)
}
defer func() {
for _, d := range dirs {
@@ -678,23 +666,19 @@ func run(aName, bName, sizesArg, patArg string,
for i, s := range sizes {
sizeStrs[i] = fmt.Sprintf("%d", s)
}
fmt.Println(renderBox("TEST",
fmt.Println(renderBox("CONFIG",
[]string{"SETTING", "VALUE"},
[]bool{false, false}, [][]string{
{"pattern", patterns[patIdx].name},
{"frame sizes", strings.Join(sizeStrs, " ")},
{"streams", fmt.Sprintf("%d per direction, ethertypes 0x%04x-0x%04x, one rx queue each",
{"streams", fmt.Sprintf("%d per direction, ethertypes 0x%04x-0x%04x",
nStreams, ethertypes[0], ethertypes[len(ethertypes)-1])},
{"probe", fmt.Sprintf("ethertype 0x%04x every %s", cfg.probeEther, probeInterval)},
{"batch", fmt.Sprintf("%d frames per syscall", batch)},
{"payload verify", "crc32c on every frame"},
{"cable probe", fmt.Sprintf("%d-byte frame on ethertype 0x%04x every %s, hardware stamped at both macs",
probeSize, cfg.probeEther, probeInterval)},
{"duplex", fmt.Sprintf("%v", duplex)},
{"socket buffers", fmt.Sprintf("sndbuf %s, rcvbuf %s (granted)",
{"calibration", fmt.Sprintf("%g ns at zero length, %g ns/m", zeroNS, nsPerM)},
{"buffers", fmt.Sprintf("sndbuf %s, rcvbuf %s",
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, press space to reset them", cDim))
fmt.Println()
var doneTx, doneRx atomic.Bool