摘要:本文系统剖析RDMA性能基准测试工具perftest的技术架构、核心工具矩阵、Verbs级实现机制与标准测试流程,详细讲解ib_write_bw/ib_write_lat的参数体系、输出指标含义与环境配置要点,帮助测试工程师建立RDMA性能基线测试的标准化方法。
一、perftest的技术定位与架构
perftest是基于InfiniBand Verbs API实现的RDMA性能基准测试工具集,由Mellanox(现NVIDIA)主导开发,作为OFED发行版的标准组件随驱动一起发布。它的核心设计原则是直接操作Verbs原语,跳过所有中间协议栈,测出RDMA硬件的极限性能------这使它成为行业内评估网卡、交换机、DPU等RDMA设备性能的事实标准。
1.1 在测试体系中的位置
┌───────────────────────────────────────────────────────┐
│ 业务层应用性能 │
│ (NCCL / MPI / NVMe-oF / 分布式数据库 / AI推理框架) │
├───────────────────────────────────────────────────────┤
│ 中间件/框架层 │
│ (UCX / libfabric / ROCm / CUDA) │
├───────────────────────────────────────────────────────┤
│ 协议栈层(内核+用户态) │
│ (RDMA-Core / libibverbs / 内核ULP驱动) │
├───────────────────────────────────────────────────────┤
│ perftest ←── 直接调用Verbs,处于协议栈之上、业务之下 │
├───────────────────────────────────────────────────────┤
│ 硬件层 │
│ (RDMA网卡 / DPU / 交换机 / 线缆) │
└───────────────────────────────────────────────────────┘
perftest的价值在于:当上层业务性能不达预期时,先用perftest确认硬件+驱动+基础网络这三层是否正常,再往上排查。如果perftest都跑不满,那问题一定在底层,调业务代码毫无意义。
1.2 代码结构与核心组件
perftest的源码组织结构清晰:
| 模块 | 功能 |
|---|---|
perftest_communication.c |
Client/Server间的控制通道(TCP套接字),用于交换GID、QPN、PSN等建链信息 |
perftest_resources.c |
RDMA资源管理:PD、CQ、QP、MR、SRQ等的创建与销毁 |
perftest_parameters.c |
命令行参数解析与默认值管理 |
perftest_bench_calls.c |
真正的测试循环逻辑:post_send、poll_cq、计时、统计 |
perftest_reporting.c |
结果格式化输出(带宽/延迟/百分位计算) |
write_bw.c / write_lat.c |
每种测试的入口文件,定义操作类型和测试参数 |
核心测试循环的伪代码如下:
c
// 带宽测试主循环
for (iteration = 0; iteration < num_iterations; iteration++) {
// 1. 批量post WR(发送工作请求)到SQ
for (i = 0; i < burst_size; i++) {
ibv_post_send(qp, &wr);
}
// 2. 轮询CQ(完成队列)等待完成
while (completed < burst_size) {
ibv_poll_cq(cq, batch_size, wc_array);
completed += batch_size;
}
// 3. 更新字节计数与时间戳
bytes_done += msg_size * burst_size;
}
// 4. 计算带宽 = 总字节 / 时间
bandwidth = (bytes_done * 8) / elapsed_time; // 转成bit/s
延迟测试的逻辑更简单------每发一个WR就立刻poll CQ等完成,测的是单次操作的端到端时间。
二、八大工具矩阵与操作语义
perftest按"RDMA操作类型 × 测试维度"形成8个核心工具,每个工具对应一种独立测试场景。
2.1 工具矩阵
| 工具名 | 操作类型 | 测试维度 | 典型用途 |
|---|---|---|---|
ib_send_bw |
RDMA Send | 带宽(Bandwidth) | 双边操作吞吐量,验证Send路径性能 |
ib_send_lat |
RDMA Send | 延迟(Latency) | 双边操作往返延迟 |
ib_write_bw |
RDMA Write | 带宽 | 最常用,单边写入吞吐量,对标线速 |
ib_write_lat |
RDMA Write | 延迟 | 单边写入延迟,通常最低 |
ib_read_bw |
RDMA Read | 带宽 | 单边读取吞吐量 |
ib_read_lat |
RDMA Read | 延迟 | 单边读取延迟 |
ib_atomic_bw |
Atomic(FetchAdd/CmpSwap) | 带宽 | 原子操作吞吐量 |
ib_atomic_lat |
Atomic(FetchAdd/CmpSwap) | 延迟 | 原子操作延迟 |
2.2 四种RDMA操作的语义差异
理解这四种操作的本质,是理解它们性能差异的基础。
RDMA Write(单边写入)
- 发起端指定本地源地址、远端目的地址、长度
- 对端CPU完全不参与,硬件直接把数据写入对端内存
- 不需要对端post receive
- 性能最高,是衡量网卡线速的标准操作
RDMA Read(单边读取)
- 发起端指定本地目的地址、远端源地址、长度
- 对端CPU不参与,硬件直接从对端内存读取数据
- 需要对端先注册MR(内存注册)并把rkey+地址告诉本端
- 性能略低于Write,因为读操作涉及远端内存响应和回传
RDMA Send(双边发送)
- 发送端把数据发到对端的Receive Queue
- 对端必须post receive buffer才能收到数据
- 需要两端配合,有接收侧开销
- 性能通常低于Write,尤其是小包场景(每次都要消耗Receive WQE)
Atomic(原子操作)
- FetchAdd:远端内存原子加法并返回旧值
- CmpSwap:远端内存原子比较交换
- 硬件级原子性,保证并发安全
- 性能最低,因为需要远端读-改-写,且原子操作串行化
2.3 性能数量级对比(100G网卡典型值)
| 操作 | 带宽(大包) | 延迟(小包) | 说明 |
|---|---|---|---|
| Write | ~97 Gb/s | ~1.0 μs | 最高,线速基准 |
| Read | ~90 Gb/s | ~1.5 μs | 略低,需要远端响应 |
| Send | ~85 Gb/s | ~2.0 μs | 更低,双边开销 |
| Atomic | ~10-20 Gb/s | ~3-5 μs | 最低,原子串行化 |
以上数值为典型100G RoCE网卡的大致量级,具体数值取决于网卡型号、固件版本、PCIe代际和测试配置。
三、标准测试环境配置
性能测试结果的可靠性,90%取决于测试环境是否配置正确。以下是标准化的环境配置Checklist。
3.1 硬件检查
bash
# 1. 确认网卡型号与固件版本
lspci -vvv -s <BDF> | grep -E "Product|Part|Firmware"
# 2. 确认PCIe链路状态(必须是x16 + Gen4/Gen5)
lspci -s <BDF> -vv | grep LnkSta:
# 期望输出:LnkSta: Speed 16GT/s (ok), Width x16 (ok) ← PCIe 4.0 x16
# 3. 确认网卡端口数量与速率
ibv_devices # 列出所有RDMA设备
ibv_devinfo -d <dev> # 查看设备详细信息
# 4. 确认网口协商速率
ethtool <netdev> | grep -E "Speed|Duplex"
PCIe是最容易出问题的环节。如果PCIe只有x8或降到了Gen3,RDMA带宽一定跑不满。
| 网卡速率 | 最低PCIe要求 |
|---|---|
| 25G | PCIe 3.0 x8 |
| 100G | PCIe 4.0 x8 或 PCIe 3.0 x16 |
| 200G | PCIe 4.0 x16 |
| 400G | PCIe 5.0 x16 |
3.2 驱动与系统配置
bash
# 1. 确认驱动版本
ofed_info -s
modinfo mlx5_core | grep version
# 2. 确认RDMA栈正常
lsmod | grep -E "rdma|ib_uverbs|mlx5"
# 3. 开启巨页(性能测试强烈建议)
echo 8192 > /proc/sys/vm/nr_hugepages
# 验证
grep Huge /proc/meminfo
# 4. 调整内存锁限制(perftest注册MR需要)
ulimit -l unlimited
# 永久生效:/etc/security/limits.conf 中加入
# * soft memlock unlimited
# * hard memlock unlimited
# 5. 关闭防火墙(RoCE场景)
systemctl stop firewalld
systemctl disable firewalld
# 或开放UDP/4791(RoCE v2端口)
# 6. 关闭SELinux
setenforce 0
3.3 CPU绑定配置
性能测试必须绑核,否则调度抖动会导致结果严重不准。
bash
# 先查网卡所在的NUMA节点
cat /sys/class/net/<netdev>/device/numa_node
# 返回0或1,表示属于NUMA0或NUMA1
# 查该NUMA节点的CPU列表
lscpu | grep -A 10 "NUMA node0 CPU(s):"
# 测试时用 -c 参数绑到对应NUMA的核心上
# 例如网卡在NUMA0,绑到core 2
ib_write_bw -d <dev> -c 2 -F <server_ip>
3.4 网络侧配置(RoCE场景)
交换机侧必须确保:
- PFC(优先级流量控制)已启用------RDMA需要无损以太网
- ECN(显式拥塞通知)已配置------拥塞控制需要
- 两端交换机端口的MTU一致(建议9000巨帧)
- 没有ACL或QoS策略意外拦截RDMA流量
四、基线测试标准流程
4.1 连通性验证(先确认链路OK)
跑性能之前,先用最简单的工具确认RDMA链路通畅:
bash
# 方式一:ibv_rc_pingpong(最基础的连通性测试)
# Server端
ibv_rc_pingpong -d <dev>
# Client端
ibv_rc_pingpong -d <dev> <server_ip>
# 方式二:rping(类似ping的RDMA版)
# Server端
rping -s -a <server_ip>
# Client端
rping -c -a <server_ip> -C 10
能ping通再上性能测试,不要上来就跑带宽。
4.2 带宽基线测试
标准的带宽测试命令:
bash
# Server端
ib_write_bw -d <dev> -F -c <core_id>
# Client端(大包测线速)
ib_write_bw -d <dev> -F -c <core_id> -s 8388608 -n 10000 <server_ip>
# Client端(自动遍历所有消息大小)
ib_write_bw -d <dev> -F -c <core_id> -a <server_ip>
参数选择说明:
-s 8388608:8MB消息,确保带宽跑满(消息越大,协议开销占比越低)-n 10000:足够多的迭代次数,消除启动波动-F:不自动降MTU(避免跟环境配置不一致)-c:绑定CPU核心,必加
4.3 延迟基线测试
bash
# Server端
ib_write_lat -d <dev> -F -c <core_id>
# Client端(小包测最低延迟)
ib_write_lat -d <dev> -F -c <core_id> -s 2 -n 10000 -I <server_ip>
# Client端(自动遍历所有消息大小)
ib_write_lat -d <dev> -F -c <core_id> -a <server_ip>
参数说明:
-s 2:最小消息size,测理论最低延迟-I:Inline模式,小包走网卡Inline路径,绕过PCIe内存访问,延迟更低- 延迟测试迭代次数不需要太多(1000次足够),但要关注P99和P999
4.4 多流并发测试
单流往往跑不满线速,需要多流并发:
bash
# 8流并发带宽测试
ib_write_bw -d <dev> -F -c <core_id> -q 8 -b 64 -s 65536 -n 10000 <server_ip>
# 参数组合:8个QP + 每QP 64个burst + 64KB消息 = 高聚合带宽
4.5 长稳测试
bash
# 跑1小时稳定性测试,输出最终结果
ib_write_bw -d <dev> -F -c <core_id> -D 3600 -s 65536 -N <server_ip>
长稳测试关注的不是峰值带宽,而是稳定性------有没有丢包、有没有性能下跌、有没有报错。
五、输出指标详解
5.1 带宽测试输出
#bytes #iterations BW peak[Gb/sec] BW average[Gb/sec] MsgRate[Mpps]
65536 5000 97.32 96.85 0.1846
| 指标 | 计算方式 | 验收关注点 |
|---|---|---|
BW peak |
采样窗口内的最大瞬时带宽 | 判断硬件极限 |
BW average |
总字节数 / 总时间 | 验收通过标准,必须达到标称值的95%以上 |
MsgRate |
迭代次数 / 总时间 | 小包场景的PPS指标 |
5.2 延迟测试输出
#bytes #iterations t_min t_max t_typical t_avg t_stdev t_99% t_99.9%
65536 1000 1.02 3.56 1.15 1.18 0.15 1.45 2.20
[usec] [usec] [usec] [usec] [usec] [usec] [usec] [usec]
| 指标 | 含义 | 工程意义 |
|---|---|---|
t_min |
所有采样中的最小值 | 理论最佳情况 |
t_max |
所有采样中的最大值 | 最坏情况,排查长尾问题时关注 |
t_typical |
典型值(众数/中位数) | 最能反映正常延迟的指标,比average可靠 |
t_avg |
算术平均值 | 被大值拉高后失真,参考价值有限 |
t_stdev |
标准差 | 稳定性指标,越小越稳定 |
t_99% |
P99分位延迟 | 99%的请求都低于此值,业务体验的下限 |
t_99.9% |
P99.9分位延迟 | 千分之一的最坏情况,AI训练/高频交易场景关键指标 |
P99为什么重要: 假设一个业务有1000次RDMA操作,P99是2μs意味着有10次操作延迟超过2μs。在AI大模型训练中,AllReduce操作需要所有节点同步完成,最慢的节点决定整体速度------这就是所谓的"长尾效应"。
六、常用参数完整手册
6.1 设备与连接参数
| 参数 | 全称 | 说明 | 默认值 |
|---|---|---|---|
-d |
device | RDMA设备名 | 第一个可用设备 |
-i |
port | 端口号 | 1 |
-p |
port | 控制通道TCP端口 | 18515 |
-x |
gid-index | GID索引(选RoCE v1/v2) | 第一个可用GID |
-m |
mtu | 路径MTU(1024/2048/4096) | 自动协商 |
-F |
force | 强制不修改MTU | 关闭 |
-R |
uc | 使用UC(不可靠连接) | RC |
-U |
ud | 使用UD(不可靠数据报) | RC |
-X |
xrc | 使用XRC | 关闭 |
6.2 测试参数
| 参数 | 全称 | 说明 | 默认值 |
|---|---|---|---|
-s |
size | 消息大小(字节) | BW: 65536, Lat: 2 |
-n |
iterations | 迭代次数 | BW: 5000, Lat: 1000 |
-a |
all | 自动遍历所有消息大小 | 关闭 |
-D |
duration | 按时间测试(秒),替代迭代数 | 关闭 |
-N |
no-echo | 不输出中间进度 | 关闭 |
-V |
verify | 验证数据正确性 | 关闭 |
6.3 性能调优参数
| 参数 | 全称 | 说明 | 对性能的影响 |
|---|---|---|---|
-q |
qp | 并发QP数量 | 多流提高聚合带宽 |
-Q |
cq-size | CQ深度 | 防止overflow |
-b |
burst | 每次post的WR数量 | 提高带宽,增加延迟 |
-c |
cpu | 绑定CPU核心 | 必加,消除调度抖动 |
-H |
hugepages | 使用巨页 | 减少TLB miss,提高性能 |
-I |
inline | 使用Inline数据 | 小包延迟降低 |
-S |
srq | 使用共享接收队列 | 节省内存,UD/Send场景 |
-l |
sl | 服务级别(优先级) | 对应VL和PFC优先级 |
6.4 特殊测试模式
| 参数 | 说明 |
|---|---|
-u |
单向转双向(带宽测试) |
-B |
双向同时测试(全双工) |
-A |
原子操作类型(fetch_add / cmp_swp) |
-t |
反向路径SL |
-o |
内存偏移量 |
-r |
接收队列深度(Send/UD测试) |
七、性能不达预期的系统化排查方法
当perftest结果明显低于预期时,按照以下顺序逐层排查,效率最高。
第一层:硬件层
bash
# 1. PCIe链路是否正常?
lspci -s <BDF> -vv | grep LnkSta:
# 期望:Speed 16GT/s (Gen4), Width x16
# 2. 光模块/线缆速率匹配吗?
ethtool -m <netdev> | grep -E "Rate|Speed"
# 3. 网卡温度/状态正常吗?
ethtool <netdev> | grep -E "Link detected|Speed"
第二层:驱动与固件层
bash
# 1. 驱动版本是否匹配?
ofed_info -s
modinfo mlx5_core | grep -E "version|firmware"
# 2. 固件版本是否是推荐版?
mlxfwmanager --query # NVIDIA网卡专用
第三层:系统配置层
bash
# 1. CPU绑核对了吗?有没有跨NUMA?
numactl -H
cat /sys/class/net/<netdev>/device/numa_node
# 2. 巨页开了吗?
grep Huge /proc/meminfo
# 3. 中断亲和性配置了吗?
cat /proc/interrupts | grep mlx5
# 4. irqbalance关了吗?
systemctl status irqbalance
第四层:测试参数层
bash
# 1. 消息大小够吗?(小包天然带宽低)
# 用 -s 8388608 测大包
# 2. 多流开了吗?
# 用 -q 8 或 -q 16
# 3. Burst够大吗?
# 用 -b 128 或 -b 256
# 4. CQ深度够吗?
# 用 -Q 2048 或更大
第五层:网络层
bash
# 1. PFC开了吗?(RoCE场景必须)
# 查交换机配置
# 2. 有没有丢包?
ibv_devinfo -d <dev> -i 1 | grep -E "port_rcv_errors|port_xmit_discards"
# 3. ECN配置对吗?
# 查交换机和网卡的ECN marking配置
八、进阶工具与同类对比
8.1 perftest进阶工具
| 工具 | 用途 |
|---|---|
ib_write_bw_post_list |
批量post list测试,优化send策略 |
raw_ethernet_bw/lat |
Raw Ethernet模式,非RDMA,用于对比有/无RDMA的性能差 |
ib_clock_test |
两端时钟同步测试,排查延迟测试的时钟偏差 |
8.2 同类工具对比
| 工具 | 层级 | 特点 | 适用场景 |
|---|---|---|---|
| perftest | Verbs层 | 最底层、最准、功能最全 | 性能基线、硬件验收 |
qperf |
Verbs层 | 同时测带宽+延迟+CPU占用 | 快速摸底对比 |
ibv_rc_pingpong |
Verbs层 | 极简,只有连通性测试 | 链路排障 |
rping |
RDMA-CM层 | 类似ping,连通性+延迟 | 快速验证 |
ucx_perftest |
UCX中间件层 | 基于UCX框架 | UCX生态测试 |
nccl-tests |
NCCL框架层 | AllReduce/AllGather等集合通信 | AI训练真实性能 |
mpi_perftest |
MPI层 | MPI级别的集合通信测试 | HPC场景 |
结论: perftest是标尺,nccl-tests/mpi_perftest是真实业务场景。做性能验收时,先过perftest(硬件层面达标),再过nccl-tests(业务层面达标),两层都过才算真正达标。
作者简介: 资深RDMA智能网卡、存储技术专家,拥有十余年DPU/RDMA/NVMe SSD芯片测试与工程经验,致力于推动高性能网络技术的开源与普及。
参考资料: