rdmaperf

command
v0.6.17 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 23 Imported by: 0

README

rdmaperf

rdmaperf compares TCP over ordinary network links, TCP over Thunderbolt Bridge, and RDMA userspace readiness.

Run a server on the receiving Mac:

GOWORK=off go run ./examples/rdma/rdmaperf serve -listen 169.254.x.y:9000

Run clients from the other Mac:

GOWORK=off go run ./examples/rdma/rdmaperf tcp -addr 169.254.x.y:9000 -pattern stream -size 1M -duration 30s
GOWORK=off go run ./examples/rdma/rdmaperf tcp -addr 169.254.x.y:9000 -pattern pingpong -size 64 -duration 30s
GOWORK=off go run ./examples/rdma/rdmaperf sweep -addr 169.254.x.y:9000 -pattern stream -duration 10s

Use interfaces to find local addresses:

GOWORK=off go run ./examples/rdma/rdmaperf interfaces

Use the same commands against Wi-Fi, Ethernet, and Thunderbolt Bridge addresses. The TCP tests measure the chosen IP path; they do not prove RDMA datapath use.

Check RDMA userspace readiness separately:

GOWORK=off go run ./examples/rdma/rdmaperf rdma-probe -timeout 10s -json

The rdma-rc-capability command is a separate, one-shot provider capability experiment. It opens one device, allocates one PD and CQ, creates exactly one RC QP, and immediately destroys it. It does not query a port, transition a QP, register memory, or post work. Both -allow-rc-probe and CONFIRM_RDMA_RC_CAPABILITY=one-shot-qp-create are required. Do not run it without a human-approved plan; a successful creation means only that RC QP creation is supported, not that RDMA READ or WRITE is supported.

The rdma-rkey-capability command is a separate, one-shot provider capability experiment. It opens one device, allocates one PD, and registers exactly one 4096-byte buffer with local-write and remote-read/write access flags. It reports the local address, lkey, and rkey, then deregisters the buffer. It creates no QP, does not query a port, and does not post work. Both -allow-rkey-probe and CONFIRM_RDMA_RKEY_CAPABILITY=one-shot-mr-register are required. Do not run it without a human-approved plan; a zero or nonzero rkey reports only that registration's key value, not whether a one-sided operation will succeed.

Measured on rdma_en3 on 2026-07-17: the guarded RC create returned a nil QP with Darwin EOPNOTSUPP (errno 102; strerror reports "Operation not supported on socket"), and the guarded memory registration returned rkey=0x0 after requesting remote-read/write access. These are observations for that device, configuration, and run. The zero rkey is not a recorded rejection of a one-sided operation; neither READ nor WRITE has been attempted.

True RDMA datapath benchmarking requires successful protection-domain, completion-queue, memory-region, queue-pair lifecycle, QP transition, and work completion polling. When provider calls block, the probe watchdog exits 124 instead of leaving the command hung.

Lifecycle stress ladder

rdma-lifecycle-stress is a two-rank, bounded stress command. It reuses the guarded UC lifecycle path, so it can wedge either provider. Build it locally, copy the same binary to the peer, and obtain approval for each invocation. Do not run it on only one host: every level reaches RTR/RTS on both hosts.

Each invocation needs the level gate:

CONFIRM_RDMA_LIFECYCLE_STRESS=l1-count-scale \
  rdmaperf rdma-lifecycle-stress -level l1-count-scale \
  -allow-lifecycle-stress ...

With -data, it also needs CONFIRM_RDMA_LIFECYCLE_DATA=uc-send-recv and -allow-lifecycle-data. Data mode posts UC SEND/RECV ping-pong traffic after all QPs reach RTS. It verifies the received deterministic payload on both ranks. A mismatch exits nonzero with failure_class=data_mismatch; it is not classified as a resource-reclamation failure.

L1 count-scale holds multiple QPs and a total of 1--101 MRs live in each round, then tears them all down. It permits 1--11 QPs and 1--3 rounds, with a maximum 10-minute whole-probe watchdog. -mrs is the total MRs per rank, not MRs per QP. This is a two-host wedge risk because both ranks allocate resources and drive RTR/RTS.

L2 round-depth holds one QP and 1--4 MRs, then repeats the full lifecycle for 1--2000 rounds. Its maximum whole-probe watchdog is six hours. This isolates cumulative reclamation from high simultaneous resource pressure, but remains a two-host wedge risk.

L3 is the -data composition of either L1 or L2. It accepts payloads from 1 byte through 4 MiB and 1--10,000 ping-pongs per QP per round. The current provider passed the single-SGE path through 1 MiB and cleanly rejected a 4 MiB receive post with ENOMEM; this is a provider limit, not a retry target. The combined data soak is L1 or L2 with -data: it measures cleanup after actual UC SEND/RECV completions, not merely QP state transitions.

L4 concurrency uses 2--11 requested QPs and starts one UC SEND/RECV ping-pong goroutine per QP after all QPs reach RTS. It requires -rounds=1, -data, and the normal lifecycle and data gates. JSON reports aggregate bytes plus a qp_data entry for every QP, so serialization, corruption, and individual-QP provider errors remain visible. It is a two-host wedge/corruption risk.

L5 idle degradation uses one QP. It runs verified pre-idle data, exchanges a TCP control barrier, holds the QP idle for -idle-dwell, exchanges a second barrier, and runs verified post-idle data. It requires -rounds=1, -qps=1, -data, and an idle dwell between one second and two hours. JSON records idle_dwell, pre_idle_verified, post_idle_verified, and phase-labelled per-QP data. It is a two-host wedge and long-duration risk.

For L1/L2, success is JSON with outcome="reclaimed", the requested rounds_done, mr_count, and qps_per_round, and no error. In data mode, also require data_verified=true and exactly rounds * qps * iters * size * 2 bytes on each rank. A nonzero exit with a round error is a failure/degradation signal; exit 124 is watchdog containment for a possible wedge. A watchdog can also fire if the peer was not launched or the control connection was malformed, so confirm provider health with a read-only rdma-probe on both hosts before declaring a wedge. Do not retry either signal automatically.

bytes_per_sec covers the full lifecycle command, including rank-0 listen and resource setup. For a payload throughput sweep, use datapath_bytes_per_sec and datapath_elapsed: they cover only the verified UC SEND/RECV phase. They are bidirectional application-payload rates, not raw link-layer rates.

mrs_opened, pds_opened, and qps_opened report the resources actually opened in the current (or failing) round before teardown. For example, a QP ceiling can be reported as qps_per_round=11 and qps_opened=10. A provider EBUSY resource refusal is classified as resource_exhausted; it remains distinct from a watchdog wedge or a data mismatch.

Conservative, approved-run cards should start with L1 at one round, 16 MRs, and one QP, then L2 at 50 rounds, two MRs, and one QP. Add -data -size 64 -iters 10 only under the additional data gate. Increase one dimension at a time and save JSON, stderr, and exit status from both ranks.

The rdma-pingpong command drives QP INIT->RTR. On the Apple Thunderbolt RDMA provider, repeated failed RTR attempts have been observed to tear down the kernel transmit path and wedge the port until reboot. The command therefore requires -allow-rtr. Treat each run as one bounded experiment, not as a retry loop.

AppleThunderboltRDMA has small resource limits. The provider reports limits near 100 MRs and 11 QPs, although those values are not uniformly hard-enforced on every host. Bounded lifecycle tests reclaimed resources cleanly; a resource refusal is not by itself evidence that a reboot is needed. rdma-pingpong opens one context, one protection domain, one completion queue, one memory region, and one queue pair per role; do not wrap it in a retry loop or launch many instances in parallel.

Long-lived applications should still bound and observe idle QPs. EXO/JACCL reports describe idle connections degrading after tens of minutes, although the current two-host probe passed a 30-minute idle dwell with verified post-idle traffic. This tool runs its TCP post-RTS barrier and immediately starts traffic; code that keeps QPs open should add an application-level heartbeat or tear down idle QPs.

To test the RDMA datapath, run rdma-pingpong on two Macs connected by Thunderbolt. TCP is used only to exchange LID/QPN/PSN/GID setup data; measured traffic uses RDMA UC SEND/RECV.

By default rdma-pingpong chooses the source GID by preferring IPv4-mapped GIDs, then Apple Thunderbolt GID index 1, then the first non-zero GID on non-Thunderbolt link layers. On Apple Thunderbolt, auto-selection never uses index 0, even when index 0 is non-zero or IPv4-mapped. This matches the JACCL Thunderbolt fallback and avoids the observed index-0 route that can fail at INIT->RTR with errno 60. Use -gid-index 0 only for an explicit diagnostic run.

Server:

perl -e 'alarm shift; exec @ARGV' 30 env GOWORK=off \
  go run ./examples/rdma/rdmaperf rdma-pingpong \
  -listen 169.254.x.y:19100 -size 64 -iters 10000 \
  -setup-timeout 12s -allow-rtr -json

Client:

perl -e 'alarm shift; exec @ARGV' 30 env GOWORK=off \
  go run ./examples/rdma/rdmaperf rdma-pingpong \
  -addr 169.254.x.y:19100 -size 64 -iters 10000 \
  -setup-timeout 12s -allow-rtr -json

Save JSON, stderr, and exit status from both roles. If QP setup fails after resources open, the output includes the local and remote LID, QPN, PSN, GID index, and GID needed for the next QP transition fix. If local resource setup times out first, the JSON reports the setup timeout instead.

-setup-timeout lets the command write a structured error when a provider call blocks, but it does not recover a wedged provider goroutine. Keep the outer timeout wrapper while testing ports or machines that may wedge in the RDMA provider. The perl wrapper above is available on stock macOS. If the remote side is launched by non-login SSH, ensure PATH includes the Go toolchain before the script runs its preflight.

If both roles reach QP INIT->RTR and fail with modify qp RTR: errno 60, save both JSON files, stderr, exit status, and recent AppleThunderboltRDMA logs, then stop. Do not retry the same topology in a loop; repeated failed RTR attempts can wedge the provider even when one bounded attempt cleans up.

Omit -name and -device after Thunderbolt cable or port changes so rdma-pingpong can auto-select a PORT_ACTIVE RDMA device. Use explicit selection only after confirming the RDMA device's port is active. With -setup-timeout, auto-selection probes each candidate in a child process so a wedged port query does not block the parent command. A wedged provider may still leave the isolated child process behind until the kernel releases it. On Apple Thunderbolt RDMA, a nonzero GID at index 0 is not auto-selected; use -gid-index 0 only for a deliberate one-shot diagnostic.

If RDMA setup starts failing with protection-domain allocation errors, or if a provider probe leaves uninterruptible child processes behind, reboot the affected node before another performance run. After reboot, confirm RDMA is still enabled and verify the selected rdma_en* port is PORT_ACTIVE. Prefer assigning explicit IP addresses to the underlying per-port Thunderbolt interfaces over destroying bridge0, especially on headless machines or setups that also use USB Ethernet adapters.

Documentation

Overview

Command rdmaperf measures TCP and RDMA readiness paths.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL