网卡性能测试矩阵:测什么、为什么这么测¶
日期:2026-08-08 标签:rust, network, benchmark, testing, virtio, qemu, performance, matrix
来源:StarryOS 基准测试分析文档和资格扫描操作手册。 位置:中断诊断完成之后、异步 RX 开发之前,用于在引入异步前固定测试口径和基线方法。
为什么需要这个矩阵¶
异步 RX 引入后,性能变化要对照基线才能判断是改善还是退化。如果不在轮询阶段先把"测什么、怎么测、怎么算、记录什么"定下来,每次改驱动都要重新争论测量方法,数据也无法横向对比。
本阶段不产生正式性能结论,只固定一套复用的测试口径。之后 QEMU、真板、轮询、异步共用同一套测试编号、公式和记录格式;换平台或换驱动只替换适配层,测试语义不变。
设计思路¶
三条原则¶
-
正确性先于性能。 一个包从发送到对端确认,中间经过六个完成点:系统调用返回(C1)→ 协议栈接受(C2)→ 描述符提交(C3)→ 描述符回收(C4)→ 对端收到(C5)→ 对端校验确认(C6)。
send()返回只代表数据进了本机 socket 缓冲区,不代表对端收到。因此吞吐和正确性一律以对端校验确认(C6)为准,发送端统计的字节只算"入队指标"。 -
先校准环境,再测网卡。 N00-N03 校准组先验证测量工具本身:时钟读数开销多少、软件栈上限多少、网络路径通不通。环境误差先扣除,后面才轮到网卡本身。
-
QEMU 只做相对比较。 QEMU 不仿真物理线延迟,也不仿真真板的 DMA、cache 和 PHY。QEMU 上能比的是"轮询 vs 异步"这类相对变化;真板单独建基线,两者不合并、不排总榜。
四种测试环境¶
| 环境 | 用途 | 能说明什么 |
|---|---|---|
| guest 回环 | 协议栈对照 | 系统调用、缓冲区、协议栈上层的成本,不含网卡 |
| QEMU user-net | 功能冒烟 | 功能能否跑通(QEMU 内置的用户态网络栈,入站依赖端口转发),不做性能结论 |
| QEMU TAP | 正式性能基线 | guest 到 host 的完整 VirtIO 路径。TAP 把 guest 网卡接到主机虚拟接口,主机可运行对端、抓包、限速 |
| 真板外部对端 | 板级性能 | DMA、cache、PLIC、PHY 等真实硬件成本 |
三个 QEMU 环境不得合并统计。正式吞吐、延迟、CPU 基线固定用 TAP;user-net 只做兼容冒烟。
测试项目¶
矩阵按"要回答的问题"分成五组,编号 N00-N54。每个测试固定六个维度:协议(TCP/UDP)、方向(收/发/双向)、包大小、流数、负载档位、时长档位。
校准组 N00-N03(必测):测量工具本身可靠吗¶
| 编号 | 测什么 | 得到什么信息 |
|---|---|---|
| N00 环境清单 | 记录环境与配置的哈希 | 数据可回溯、可对比,知道这组数是在什么环境下跑的 |
| N01 计时校准 | 测时钟读取本身的开销 | 把测量误差从结果中扣除 |
| N02 回环对照 | 不走网卡的 TCP/UDP 传输 | 软件栈自身上限,作为网卡性能的天花板参照 |
| N03 路径校准 | ARP、ICMP、MTU 基本连通 | 测网卡之前先确认网络路径是通的 |
吞吐组 N10-N14(必测):能传多快¶
| 编号 | 测什么 | 得到什么信息 |
|---|---|---|
| N10 TCP 单向吞吐 | 单连接持续收发 | 最基本的有效吞吐数字 |
| N11 写入尺寸 | 从 1 字节到 64KB 逐档测 | 小写量看系统调用开销,大写量看缓冲区上限,找出吞吐与开销的平衡点 |
| N12 TCP 双向 | 两个方向同时传 | 收发同时进行时能否互相推进,还是互相饿死 |
| N13 多连接 | 1/2/4/8 条连接并发 | 聚合吞吐是否随连接数增长,还是存在单点瓶颈 |
| N14 稳态 | 长时间稳定运行 | 吞吐是否漂移、有无卡顿 |
延迟组 N20-N24(必测):快不快、稳不稳¶
| 编号 | 测什么 | 得到什么信息 |
|---|---|---|
| N20 TCP 往返延迟 | 4 种包大小各测 200 次 | 报中位数/95%/99% 分位和最大值,看典型延迟和长尾 |
| N21 UDP 受控速率吞吐 | 按固定速率发送 | 先找无损区间,再逐档加压;同时报"发了多少、收了多少、错了几包",定位丢包发生在哪一端 |
| N22 UDP 往返与间隔误差 | 回环往返 + 接收间隔偏差 | 延迟抖动的代理指标 |
| N23 UDP 突发 | 32~257 个包一次性灌入 | 队列被填满时的丢包、乱序和恢复 |
| N24 负载下延迟 | 在 0%~90% 负载下测往返 | 网卡繁忙时延迟是否恶化,长尾是否出现 |
边界组 N30-N35(机制):背压和边界行为¶
| 编号 | 测什么 | 得到什么信息 |
|---|---|---|
| N30 非阻塞背压 | 一直写直到返回 EAGAIN | 缓冲区满时驱动是否正确告诉应用"先别发了",以及满了之后能否恢复 |
| N31 队列边界 | 63/64/65、127/128/129 包 | VirtIO 环形队列和缓冲池容量边界处的表现 |
| N32 连接周转 | 反复连接/断开 | 连接建立速率和失败率 |
| N33 多流公平 | 2/4/8 条流各分到多少 | 各流是否均分带宽(用公平指数量化) |
| N34 缓冲边界 | socket 缓冲、UDP 元数据、ARP 表满 | 容量满时的 EAGAIN、丢包和恢复 |
| N35 复制效率 | 每字节被复制了几次 | 需要驱动内部计数,可选 |
效率组 N40-N46(必测/机制):要花多少 CPU 和中断¶
| 编号 | 测什么 | 得到什么信息 |
|---|---|---|
| N40 空闲成本 | 没有流量时的 CPU 占用 | 对轮询驱动最关键:当前 10ms 兜底轮询让 QEMU 空闲 CPU 达 100-111%,这是异步化的主要动机之一 |
| N41 CPU 效率 | 每传 1GiB 花多少 CPU 秒、每字节多少指令 | 用 host 的 QEMU CPU 时间 + guest 的指令计数器(instret)近似整机成本 |
| N42 中断效率 | 每收一个包触发几次中断 | 中断风暴检测,用中断快照前后差值计算 |
| N43 定时器干扰 | 网卡繁忙时定时器是否准时 | 唤醒是否被推迟(overshoot) |
| N44 内存稳定性 | 持续分配/释放后的内存变化 | 用常驻内存和分配器前后差检测泄漏 |
| N45 唤醒效率 | 从事件到任务推进的延迟 | 异步驱动专用,机制 |
| N46 描述符效率 | 描述符占用、驻留时间、卡住次数 | 需要驱动内部遥测,机制 |
扩展组 N50-N54(扩展/真板):损坏环境、长时间、多核、真板¶
| 编号 | 测什么 | 得到什么信息 |
|---|---|---|
| N50 网络损伤 | 用 netem 注入延迟/丢包/乱序/限速 | 受损环境下的降级和恢复能力 |
| N51 稳定运行 | 固定负载跑 5 分钟 | 卡顿、丢包、资源增长 |
| N52 过载恢复 | 超载后降低负载 | 恢复时间和残留状态 |
| N53 SMP 多队列 | 1/2/4 核、多队列 | 多核扩展性和公平性 |
| N54 真板机制 | DMA、cache、PLIC、PHY | 真实硬件的机制成本 |
载荷尺寸怎么选¶
矩阵按边界选尺寸,让容量上限被踩到:
- TCP 写入尺寸:1、64、256、512、1024、1460、4096、16384、65536 字节(覆盖 64KB socket 缓冲上限)
- UDP 有效载荷:1、64、256、512、1024、1400、1472-头部 字节(1472 是 MTU 内不分片的上限)
- 边界值:VirtIO 队列 63/64/65 包、缓冲池 127/128/129 包、UDP 元数据 255/256/257 条、socket 缓冲 65535/65536/65537 字节
边界两侧各取一个值(如 63、65),才能看出容量边界处是正常退化还是行为突变。
执行流程:六方向 + 固定步骤¶
每个测试按 TCP/UDP × 收/发/双向 六个方向执行。每个方向输出:环境清单、原始记录、双端账本(各自统计发了多少包、收了多少包、错了多少包)。
流程固定,顺序不可跳:
测试支持四个档位:smoke(1 秒,功能冒烟)、quick(5 秒,开发回归)、standard(10 秒,正式基线)、soak/board(300 秒以上,长稳/损伤/真板)。当前前三个可执行,最后一个只冻结格式未执行。
结果怎么判定¶
三层判定,逐层通过:
| 层 | 通过 | 失败 |
|---|---|---|
| 执行 | 双端启动、输出记录 | 卡死、崩溃、无法建连 |
| 正确性 | 对端校验指纹一致、账本闭合 | 异常计数、账本不符 |
| 性能 | 轮次有效、采样覆盖负载 | 轮次无效或能力缺失 |
"轮次无效"(invalid round)表示数据不全或账本对不上。无效轮次能证明命令、协议和失败分类可运行,但不能进入性能统计。无效轮次原样保留并注明原因,补跑使用新轮次编号,不删除异常值。
当前覆盖状态¶
当前在 QEMU user-net 环境(轮询驱动)取得的资格:
| 场景 | 执行 | 正确性 | 说明 |
|---|---|---|---|
| TCP RX | 通过 | 无效 | host 发 9964 包,guest 收 7788(不完整) |
| UDP RX | 通过 | 无效 | host 发 60822 包,guest 27 个迟到(缓冲满) |
| TCP TX | 通过 | 有效 | 双端各 4702 包、6582800 字节 |
| UDP TX | 通过 | 无效 | guest 发 4819,host 收 4812,7 个迟到 |
| TCP 双向 | 通过 | 无效 | 一个方向账本闭合,反向未闭合 |
| UDP 双向 | 通过 | 无效 | 双向有流量,但账本未闭合 |
这些结果证明六方向命令、协议记录和失败分类可以运行,不代表网卡性能结论。
还差什么:两类缺口¶
命令能表达但没跑(not-run):TAP 六方向、2/4/8 流、载荷矩阵、时长档位、空闲 CPU 对照、抓包。原因是 TAP 环境还没搭,不是测不了。
设施本身不支持(infrastructure-unavailable):TCP 往返、UDP 往返与间隔误差、精确突发、负载下延迟、填满到 EAGAIN 的背压、队列边界控制、指令/字节统计、中断快照集成、定时器干扰采样、分配器/描述符遥测。这些需要新增能力(如往返请求/应答模式、精确包数参数、驱动内部计数器),属于独立的功能需求,不能靠重复执行命令解决。
两类缺口的区分规则:命令能表达但没跑 → not-run;CLI、采集器或遥测根本不支持 → infrastructure-unavailable。不能混记。
工具链¶
| 文件 | 作用 |
|---|---|
tests/network_benchmark.c |
guest/host 共用的 workload |
tests/network_benchmark_protocol.h |
控制协议和记录格式 |
tests/network_benchmark_platform.h |
时钟、计数器和平台适配 |
scripts/network_benchmark_collect.py |
host CPU/内存采样 |
scripts/network_benchmark_report.py |
原始记录 → CSV/JSON 摘要 |
scripts/network_benchmark_evidence.py |
记录完整性与比较资格检查 |
guest 用 RISC-V 静态编译,host 用本机编译。同一个 C 程序支持 client/server、TCP/UDP、收/发、往返和校验模式。
每次正式运行保存什么¶
原始记录必须保留,CSV/JSON 摘要不能替代原始记录:
manifest.json 环境配置与哈希
qemu-command.txt 展开后的 QEMU 命令
qemu-serial.log 完整串口日志
guest-netbench.ndjson guest 原始记录(每行一条 JSON)
host-netbench.ndjson host 原始记录
host-cpu.ndjson QEMU/对端/采集器的 CPU 与内存
irq-snapshots.log 中断诊断前后快照
capture.pcap TAP 抓包见证
results.csv 逐轮次规范化数据
summary.json 汇总与有效性状态
evidence-check.json 完整性与比较资格检查
参考¶
- 网卡基准分析文档(729 行,完整测试目录与公式)
- 资格扫描操作手册(588 行,操作流程与缺口分类)
- QEMU 网络测试手册
- 轮询网络阶段操作记录
- 中断诊断阶段操作记录
- 基准分轴规则
- 基础设施缺口需求