给无线电插上 AI 的翅膀(下)从跑通到可信
从“跑通”到“可信”:100G FPGA RDMA 数据面的验证与 AI 协作复盘
上篇讲的是为什么选择 RDMA,以及 MRF8/XCZU47DR 100G RoCEv2 端点已经做到哪里;下篇想讨论一个更难的问题:当带宽接近 100G、应用结果也正确时,我们凭什么相信整个数据面真的可靠?
在高速硬件项目里,“跑通”很让人兴奋,但也最容易让人放松警惕。
服务器 CQ 全部成功,readback 数据一致,吞吐数字接近线速——这些当然是好消息,却不是完整答案。可靠协议会重传,缓存会暂时吸收突发,测试脚本也可能掩盖异常。如果只看最后一行PASS,一个存在溢出、坏包甚至状态恢复问题的设计,也可能被误认为已经稳定。
所以这篇文章不再重点谈“怎样跑到 100G”,而是复盘怎样从一次看似成功的测试中发现问题,怎样建立严格判据,以及 AI 如何参与真实硬件的验证闭环。
七、一个比“跑到 100G”更重要的教训
1. 最危险的结果:应用成功,内部却已经出错
问题出现在多 QP、高 in-flight depth 的持续压力测试中。
从服务器应用看,一切似乎正常:QP 可以进入 RTS,CQ completion 最终成功,写入 FPGA DDR 的数据也能通过 RDMA READ 回读。只看应用日志,很容易给出“测试通过”的结论。
但 FPGA 内部计数器给出了不同答案:
- RX FIFO overflow 增长;
- 出现坏 iCRC;
- invalid/duplicate PSN 增长;
- FIFO 高水位已经触顶。
也就是说,可靠连接最终把数据送到了,但数据面中途并不干净。
这正是 RoCEv2 RC 的双刃剑。ACK、timeout 和重传提高了端到端可靠性,也可能让底层偶发异常在应用层“看起来没事”。如果把“最终完成”直接等价为“链路无错”,测试判据就会被协议恢复能力欺骗。
2. 第一轮假设:是不是 QP 太多?
看到多 QP 压力下出错,最直觉的判断是调度器可能不公平,或者 QP context 切换出现问题。但把不同 QP 数、WQE 长度和 depth 组合放进矩阵之后,现象并不支持这个猜测。
真正稳定相关的变量不是 QP 数,而是持续在途深度:
- 8 QP、64 KiB、depth 128 会出错;
- 4 QP、64 KiB、depth 128 同样会出错;
- 8 QP、16 KiB、depth 128 仍然会出错。
QP 数和 WQE 长度发生了变化,FIFO 溢出却始终随着深在途流量出现。这把排查方向从“QP 状态机错误”转向了“入口速率与下游服务率不匹配”。
3. 根因:FIFO 可以吸收突发,不能填平长期速率差
修复前,高 depth 测试中的网络入口接近 100 Gbit/s,而下游持续服务率大约只有 83 Gbit/s。两者之间存在长期速率差。
FIFO 能解决什么?它能吸收微突发、仲裁抖动和短时间 backpressure。但只要平均输入速率长期大于平均输出速率,再深的有限 FIFO 最终都会填满:
FIFO 占用增长速度 ≈ 输入速率 − 下游服务速率这不是简单地“再加一点缓存”就能永久解决的问题。缓存只能延后溢出,不能改变长期收支关系。
4. 修复:增加缓冲,同时建立真正的流控闭环
最终采用了两层修复。
第一层是在 CMAC RX 与下游处理之间加入16,384 beat、约 1 MiB 的 UltraRAM burst FIFO,用于吸收短时间微突发,并增加 FIFO 高水位和下游停顿遥测。
第二层是根据 FIFO 水位加入IEEE 802.3x 全局 PAUSE 滞回控制:
- FIFO 达到 8,192 beat 时请求对端暂停;
- FIFO 回落到 4,096 beat 时解除暂停;
- assert 和 release 使用不同阈值,避免在边界附近反复抖动。
服务器 RNIC 的 PAUSE 计数出现明确增量,证明它确实接收并执行了 FPGA 发出的流控,而不是测试刚好没有再次触发问题。
5. 如何证明修复有效?不是只重跑一个用例
修复后,首先重跑了原先能够稳定复现溢出的三个 16.384 GB 高 depth 用例。它们全部满足严格判据:服务器 CQ 与 readback 成功,同时 FPGA overflow、坏 iCRC、无故障 PSN、MR、DataMover 和数据 checker 错误均为 0。
随后又扩大验证范围:
- 1/4/8 QP;
- 16/64 KiB WQE;
- depth 1/2/4/8/16/32/64/128;
- 共 48 项 PAUSE 回归矩阵;
- 功能长度、错误 rkey、越界 VA、丢 WRITE ACK、丢 READ response;
- 链路断开与恢复;
- 10 分钟全数据校验。
10 分钟测试共传输6.5536 TB,带宽约98.007 Gbit/s,1.6G 个数据块的数据、序列、iCRC、PSN、MR、DMA 和 overflow 错误均为 0。
这个结果比“某个用例重新跑通”更可信,因为它证明修复没有只照顾一个参数点,也没有破坏原有功能。
6. 新边界:流控解决了溢出,却不等于 depth 越大越好
加入 PAUSE 后,单向高深度流量可以避免溢出。但在全双工场景里,问题又多了一层:全局 PAUSE 会同时影响反向流量。
服务器方向突发过深时,FPGA 为保护 RX FIFO 发出 PAUSE,反方向的 FPGA→服务器发送也会受到影响。于是峰值 depth 虽然不再导致错误,却可能让另一方向的稳态带宽下降。
最终推荐的工作点不是“参数开到最大”,而是:
- 4+4 QP:服务器方向 16 KiB、depth/QP 4;
- 2+2 QP:服务器方向 16 KiB、depth/QP 8;
- FPGA requester:4 KiB、window 64;
- 累计 ACK 阈值 4;
- timeout 1 ms。
在正式正时序 bitstream 的 4+4 QP 回归中,服务器→FPGA 为96.203 Gbit/s,FPGA→服务器稳态采样为95.834~98.825 Gbit/s,PAUSE、重传及各层错误均为 0。
这次经历留下的结论是:
可靠协议最终把数据送到,不等于数据面全过程无错;跑出峰值带宽,也不等于找到了可以长期使用的配置。
八、一次严格 PASS,究竟需要哪些证据?
高速数据面不能只有一个PASS。我更愿意把拆成五层,每一层回答不同的问题。
第一层:应用结果
检查 QP 是否正常进入 RTS、CQ completion 是否成功、readback 或接收缓冲是否逐字节正确、payload hash 是否一致。
这是最直观的一层,但也是最容易被重传机制“修复”后掩盖问题的一层。
第二层:RDMA 协议状态
检查 issued 与 ACK 是否匹配、测试结束 outstanding 是否归零、无故障用例 retransmission 是否为 0,以及 PSN、MR、QP、unexpected ACK 等错误计数是否增长。
故障注入用例与 clean test 的判据必须分开:主动丢 ACK 时出现重传是预期结果;没有注入故障时出现重传,则必须解释根因。
第三层:FPGA 数据面
检查 FIFO overflow/drop、iCRC、format、DataMover command/status、DDR 数据与序列 checker。尤其要确认 DMA 命令数与完成状态数一致,不能只看网络侧完成。
第四层:物理链路
检查 FPGA CMAC 和服务器 RNIC 两侧的 FEC corrected/uncorrected、CRC、discard、bad-code、high-BER、link-down 和 PAUSE 增量。
PAUSE 不一定是数据错误,但它是拥塞和工作点边界的重要证据,不能因为最终数据正确就忽略。
第五层:实现
确认测试所用 bitstream ,设计 fully routed,setup/hold 为正,DRC Error 为 0。先行功能镜像可以帮助排查,但不能代替最终正时序镜像的关键回归。
只有五层证据同时成立,clean test 才能被称为严格 PASS。
这套判据还有一个好处:发生失败时,能够快速判断问题大致属于应用、协议、数据面、物理层还是实现层,而不是在所有模块之间盲目搜索。
九、长期测试:完成到什么程度,就只说到什么程度
几秒钟的线速测试可以证明吞吐能力,却不能证明长期可靠性。
长时间运行会暴露很多短测看不到的问题:
- 计数器回卷和 snapshot 不一致;
- 缓慢累积的缓存或描述符泄漏;
- 温度变化后的时序、PHY 或 DDR 边界;
- 极低概率的 bit error;
- 24-bit PSN 长周期行为;
- timeout、重传和链路恢复的偶发竞态;
- 测试工具自身的日志增长、SSH 重连和文件采集问题。
因此当前使用阶梯式长测:
60 秒门禁 → 1 小时 → 8 小时 → 24 小时前一级不过,不进入后一级;每一级都记录两个方向的实际字节数和带宽、payload hash、FPGA 协议/数据面计数、RNIC PHY 计数、FIFO 水位、CPU 和温度。
一次很有价值的“自动化失败”
上一轮测试中,1 小时阶段自动 PASS。8 小时数据面证据经服务器原始日志和 FPGA 运行时计数恢复核对后也通过:两个方向达到目标,payload hash mismatch 为 0,FPGA 和 RNIC 错误计数均为 0。
但整个 campaign 不能被写成完整 PASS。
原因不是数据面,而是旧 SSH 收集器在结束阶段高频读取不断增长的四份完整日志,触发 Paramiko rekey 超时,本地 harness 提前退出,计划中的 24 小时阶段没有启动。
这件事让我把“通过”进一步拆成两个概念:
- Data-plane PASS:现有原始证据证明被测数据面满足判据;
- Campaign PASS:自动化流程完整执行、证据收集闭合、最终状态文件可信。
数据面通过不能自动修复 harness,harness 失败也不能抹去已经保存的有效数据面证据。两者必须分别记录,不能为了一个漂亮的总结互相替代。
收集器后来改为 5 秒一次的 SFTP 尾部采样、15 分钟主动重连,并在阶段结束后才读取完整日志。新的 24 小时 campaign 已于2026 年 8 月 18 日 06:30开始。
写下本文时它第一轮测试已经顺利完成,开始第二轮测试。因此这里只能写“正在测试”,不能提前写完成”。
工程可信度,很多时候就体现在这种不抢跑上。
十、AI 在这个项目里具体做了什么?
这个项目不是“让 AI 一句话生成一个 100G RDMA 核”。真正有效的方式,是让 AI 进入每一个可验证的小闭环。
1. 把模糊目标改写成可实现指标
“实现 FPGA RDMA”不是一个可以直接验证的目标。它必须被展开为:
- 哪个方向:RNIC→FPGA、FPGA→RNIC,还是全双工;
- 哪种操作:WRITE、READ、SEND;
- 多少 QP、什么 WQE 大小、多少 in-flight;
- 最低带宽是多少;
- clean test 哪些计数必须为 0;
- 故障注入时哪些异常属于预期;
- 什么条件下必须停止测试并判失败。
AI 很适合根据工程背景生成第一版检查表,但最终指标必须由人确认,因为只有工程师知道哪些边界与真实产品有关。
2. 建立接口、状态和所有权模型
高速设计中最容易出问题的,常常不是算法本身,而是“谁拥有这个 buffer”“谁推进 PSN”“什么时候允许回收 WQE”“backpressure 能否穿过所有流水级”。
让 AI 帮忙梳理接口时,我会要求它明确列出:生产者、消费者、时钟域、有效条件、完成条件、错误路径和复位行为。这样得到的不是一段泛泛解释,而是一份可以和 RTL/HLS 对照的状态模型。
3. 生成测试矩阵,而不是只生成代码
每增加一项能力,都必须增加对应证据:
| 新能力 | 必须补充的测试 |
|---|---|
| iCRC 与 padding | 0~3 字节 padding、好包、坏 iCRC、随机 backpressure |
| MR 保护 | 正确 rkey、错误 rkey、边界地址、越界 VA |
| RC 重传 | 丢 WRITE ACK、丢 READ response、duplicate 抑制 |
| 多 QP | 1/2/4/8 QP、公平性、状态隔离、不同 depth |
| 双 DDR | 两个方向并发、命令/状态配对、跨 bank 顺序 |
| 链路恢复 | 运行态断链、在途断链、retry exhaustion、重新建 QP |
AI 可以帮助发现组合缺口、生成参数矩阵和日志解析逻辑。相比只让它写一个模块,这类工作更容易被验证,也更能持续提高项目质量。
4. 从证据出发形成根因假设
当高 depth 用例出错时,与其问 AI“为什么 FPGA 丢包”,不如提供结构化证据:
现象:CQ/readback 成功,但 overflow、bad iCRC、invalid PSN 增长 变量:QP=4/8,WQE=16/64 KiB,depth=128 均可复现 速率:入口接近 100G,下游约 83G 水位:FIFO 触顶 约束:不得依靠降低链路速率掩盖问题 期望:列出最可能根因、区分性实验和每种修复的副作用这样的输入能够让 AI 帮助组织假设和实验,而不是凭空猜测。最终根因仍必须由计数器、ILA、矩阵和板上复现确认。
5. 把测试工具也当成需要验证的软件
AI 辅助生成的脚本同样可能有 bug:把正常 stderr 当失败、把零计数解析错、读取陈旧状态文件,或者因为日志越来越大而拖垮 SSH 会话。
因此自动化工具也要有已知输入、边界用例和自检。脚本打印的PASS不是事实,脚本怎样得到这个结论才是事实。
6. 把每次失败变成下一轮上下文
每次异常都记录为:现象、影响范围、根因、修复、回归范围、残余风险和复现入口。这样下一次让 AI 参与时,它看到的是项目历史,而不是一段孤立代码。
这也是 AI 在长期工程里最容易被低估的价值:它不仅能帮助“做”,还能帮助团队不再反复遗忘“为什么这样做”。
7. AI 不能替代的三件事
第一,不能替代硬件测量。时序报告、ILA、协议计数器和线上每一个 bit 才是裁判。
第二,不能替代边界判断。AI 往往倾向于给出完整、积极的结论,而工程师必须明确哪些已经验证、哪些只是推断、哪些仍然待测。
第三,不能替代责任。最终 bitstream 是否可交付、数据是否可信、测试是否足够,签字的仍然应该是人。
我越来越认可这样一句总结:
AI 负责扩大搜索、表达和执行面;工程师负责定义问题、控制变量、验证证据,并为结论负责。
十一、40+ 硬件工程师的优势,可能正在重新变得重要
AI 擅长快速生成候选方案,但候选方案越多,越需要有人知道什么不能做。
多年硬件经验带来的,不只是更熟练地写代码,而是一种系统性的“边界感”:看到 100G 入口时会先问下游能不能持续接住;看到 CQ 成功时会追问有没有发生重传;看到自动化 PASS 时会检查证据是否闭合;看到漂亮架构图时会想到复位、CDC、缓存所有权和异常恢复。
这种判断力很难从一次问答里获得。AI 可以让检索、编码、测试和写作更快,但决定往哪里走、在哪里停下来验证,仍然依赖长期积累。
所以我不再把 AI 只看成新的竞争压力。对愿意继续学习的资深工程师来说,它也可能是一个杠杆:让过去积累的系统经验,以更快的速度转化为新的工程成果。
十二、下一步:从网络端点走向真正的无线电 AI 数据面
当前网络端点已经打通,但最终目标还没有完成。现阶段顶层尚未正式接入 RF Data Converter,ADC/DAC 数据面与 GPU 直接处理链路仍属于下一阶段。
后续工作主要包括:
- 完成 24 小时全双工长测;
- 增加适合长期运行的 64-bit 原子 snapshot 和 PHY/RDMA/DMA 遥测;
- 接入 RFDC、sample pack/unpack 和 RF 时钟域;
- 建立 ADC→DDR4-B ring→RDMA WRITE→服务器的上行路径;
- 建立服务器 RDMA WRITE→DDR4-A ring→DAC 的下行路径;
- 处理 ring descriptor、overflow、underrun、DAC prefill 和异常恢复;
- 评估注册主机内存、GPU 直接内存访问及实际 AI 推理流水。
后续文章会继续拆解这些问题,包括 RoCEv2 报文与 iCRC、QP/MR/PSN、主动 requester、多 QP 性能、全双工边界、长测自动化,以及 RF/GPU 接入。
结语
“给无线电插上 AI 的翅膀”听起来像一句很大的口号,但真正落地时,它由许多很小、很具体的工程问题组成:一个时钟域、一段 FIFO、一个 PSN、一条 ACK、一份时序报告、一次持续数小时的压力测试。
这两篇开篇文章想表达的,不只是我们做出了一个接近 100G 的 FPGA RoCEv2 端点,更是一种工程态度:不只追求“能跑”,还要追问“为什么可信”;不只记录成功,也记录失败怎样改变了设计;不把 AI 当成答案,而是把它放进一条可以被验证的工作流。
对一个四十多岁的硬件工程师来说,AI 不是用来抹掉过去经验的浪潮。它更像一个新的放大器:如果我们仍然愿意动手、愿意验证、愿意承认边界,那么多年积累的系统理解和工程判断,可能比以往任何时候都更有价值。
下一篇,我们从最基础也最容易被低估的问题开始:无线电采样数据到底有多大,100G 链路又为什么很快就会变得“不够用”?
参考资料
- FPGA Network Stack:TCP/IP、RoCEv2、UDP/IP 10–100 Gbit/s 开源网络栈
- MRF8 / XCZU47DR 100G RoCEv2 实践仓库
- Linux Kernel:Userspace Verbs Access
- 项目采用的MRF8 YunSDR板卡资料
