Judge loss by arrival order and a deadline, one tx ring per stream
This commit is contained in:
@@ -722,6 +722,45 @@ func checkRings(fd int, ifname string, rxWant, txWant uint32) checkResult {
|
||||
return res
|
||||
}
|
||||
|
||||
// With PACKET_QDISC_BYPASS the hardware ring comes from XPS, which maps the
|
||||
// sending cpu to a ring, so an unpinned sender migrating across cpus spreads
|
||||
// one stream over rings that drain concurrently and reorder it on the wire.
|
||||
// Each stream's pinned feeder cpu maps to the stream's own ring instead. The
|
||||
// rings sit past the flow-rule queues because ixgbe pairs rx and tx of one
|
||||
// index on one interrupt vector, and tx cleanup does not belong on the
|
||||
// vectors delivering the streams.
|
||||
func checkTxQueues(ifname string, iface int) checkResult {
|
||||
res := checkResult{item: ifname + " tx queues"}
|
||||
queues, err := filepath.Glob("/sys/class/net/" + ifname + "/queues/tx-*/xps_cpus")
|
||||
if err != nil || len(queues) == 0 {
|
||||
res.err = fmt.Errorf("no tx queues found: %v", err)
|
||||
return res
|
||||
}
|
||||
masks := make(map[string]string, numStreams)
|
||||
for s := 0; s < numStreams; s++ {
|
||||
masks[fmt.Sprintf("tx-%d", numStreams+s)] = fmt.Sprintf("%x", uint64(1)<<txCPU(iface, s))
|
||||
}
|
||||
pinned := 0
|
||||
for _, q := range queues {
|
||||
want := "0"
|
||||
if m, ok := masks[filepath.Base(filepath.Dir(q))]; ok {
|
||||
want = m
|
||||
pinned++
|
||||
}
|
||||
if err := os.WriteFile(q, []byte(want), 0); err != nil {
|
||||
res.err = fmt.Errorf("%s: %w", q, err)
|
||||
return res
|
||||
}
|
||||
}
|
||||
if pinned != numStreams {
|
||||
res.err = fmt.Errorf("pinned %d of %d streams across %d tx queues", pinned, numStreams, len(queues))
|
||||
return res
|
||||
}
|
||||
res.state = fmt.Sprintf("streams on tx-%d..%d, feeder cpus %d/%d",
|
||||
numStreams, 2*numStreams-1, txCPU(iface, 0), txCPU(iface, numStreams-1))
|
||||
return res
|
||||
}
|
||||
|
||||
func withIoctlSocket(fn func(fd int) []checkResult) []checkResult {
|
||||
fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
|
||||
if err != nil {
|
||||
@@ -737,16 +776,17 @@ func configureSystem(ifnames []string, ethertypes []uint16) []checkResult {
|
||||
return withIoctlSocket(func(fd int) []checkResult {
|
||||
out := []checkResult{checkGovernor(wantGovernor), checkMaxFreq(wantMaxFreqKHz),
|
||||
checkIdleLatency(wantIdleLatency)}
|
||||
for _, ifname := range ifnames {
|
||||
for i, ifname := range ifnames {
|
||||
out = append(out, checkLinkUp(fd, ifname))
|
||||
out = append(out, checkMTU(fd, ifname, wantMTU))
|
||||
out = append(out, clearFlowRules(fd, ifname))
|
||||
|
||||
// Ring changes reprogram the queues, so flow rules pointing at those
|
||||
// queues have to be installed afterwards.
|
||||
// Ring changes reprogram the queues, so flow rules and the xps pin,
|
||||
// which point at those queues, have to be installed afterwards.
|
||||
out = append(out, checkRings(fd, ifname, wantRxRing, wantTxRing))
|
||||
out = append(out, checkCoalesce(fd, ifname, wantCoalesceUsecs))
|
||||
out = append(out, checkFlowRules(fd, ifname, ethertypes))
|
||||
out = append(out, checkTxQueues(ifname, i))
|
||||
}
|
||||
return out
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user