双路 Xeon + 7900 XTX 跑本地大模型:一启动推理服务就整机硬死机,三轮排查最后定位到 IOMMU
先说结论:不是推理引擎的 bug,也不是显卡驱动报错那种"看得见"的故障。最后靠两个内核参数解决——iommu=pt + pcie_aspm=off,再叠加把 7900 XTX 功率封到 272W。整个过程走了三轮,前两轮的结论都是错的,把踩的坑记下来给同样遇到"日志戛然而止式死机"的人参考。
一、环境
| 项 | 值 |
|---|---|
| 机器 | 双路 Xeon(Broadwell-EP)、125 GB 内存、Ubuntu 24.04.5、内核 7.0.0-34 |
| 计算卡 | AMD RX 7900 XTX 24G(挂在 PCIe 交换机后面,Gen4 x16) |
| 显示卡 | NVIDIA Quadro P600(走 nouveau) |
| 推理引擎 | strata(MoE 专家层放主机内存,显存放不下) |
| 负载画像 | ~47 GB 固定(pin)在主机内存的专家权重 + ~23.5 GB 显存 + 3 GB 固定 KV + 18 个 CPU 线程 |
二、症状:不是崩溃,是"断电式"整机死机
- 屏幕定格、键鼠无反应,没有 kernel panic、没有 Oops、没有 OOM;
- journal 在半行中间断掉,完全没走关机流程;
- 重启后 journald 报
user-1000.journal corrupted or uncleanly shut down; - 更诡异的是:这台机器空载也冻过——推理服务没启动、开机 3 分钟也冻过。
这类"日志戛然而止"的冻结基本可以排除软件 bug:软件 bug 会留下 panic 或 Oops。它是死在比 CPU 更底层的位置。
三、第一轮:先修掉那条"看得见"的因果链
之前为了 P600 装过 nvidia 580 专有驱动。装完之后日志里出现一条非常清晰的死亡链:
SMU: No response msg_reg: 12
Failed to export SMU metrics table!
MES failed to respond to msg=REMOVE_QUEUE / SUSPEND / RESET
Failed to quiesce KFD
ring sdma0 timeout
GPU reset begin!
(日志到此为止)
两条 GPU 驱动在同一台机器上抢 PCIe / 电源管理资源:amdgpu 的 SMU、MES 先死,然后 GPU reset 把整机一起带走。卸掉 nvidia、P600 回到 nouveau,这条链就消失了。
顺手还修了一个一直没生效的功率封顶服务:unit 里把 DRM 的 card1 写成了网络设备依赖,导致每次开机 Job ...start timed out / Dependency failed,封顶从来没落地过,实际一直是出厂 303W。修好后 power1_cap 才真的读到 272W。
四、第二轮:还是冻 —— 于是先搭取证,不再靠猜
因为冻结不留日志,第一件事是让现场能留下来:
# /etc/sysctl.d/99-strata-freeze-forensics.conf
kernel.hardlockup_panic = 1 # CPU 硬锁定就直接 panic 留现场
kernel.softlockup_panic = 1
kernel.panic_on_oops = 1
kernel.panic = 30 # panic 后 30 秒自动重启,无人值守
kernel.sysrq = 1
再加一个把内核 ring buffer 实时落盘的服务,关键是它能跨重启保住冻结前最后的内核动作:
# /usr/local/lib/kmsg-forensic/kmsg-forensic.sh
printf '\n===== boot %s uptime=%ss =====\n' "$(date '+%F %T')" "$(cut -d' ' -f1 /proc/uptime)"
exec dmesg -w
unit 里不要在 ExecStart 里写 shell 重定向,systemd 会展开 $ 和 %T,会报 Failed to resolve unit specifiers ... Invalid slot。用 StandardOutput=append::
ExecStart=/usr/local/lib/kmsg-forensic/kmsg-forensic.sh
StandardOutput=append:/var/log/kmsg-forensic.log
Restart=always
踩坑提醒:用
journalctl -b <id> | grep -c 'systemd-shutdown|Journal stopped'判断某次开机是不是硬冻结时,grep 会匹配到你自己那条诊断命令(systemd 会把执行的完整命令行记进 journal),出现假阳性。要么只看该 boot 的最后几行,要么把 pattern 写成[s]ystemd-shutdown。
五、第三轮:取证抓到了,也排除了几个很像嫌疑人的东西
冻结那次的取证段(dmesg -w 实时落盘,重启后还在)最后几行:
[ 1280.83] amdgpu 0000:05:00.0: Using 44-bit DMA addresses
[ 1554.93] workqueue: svm_range_deferred_list_work [amdgpu] hogged CPU for >10000us 4 times, consider switching to WQ_UNBOUND
[ 2121.45] workqueue: svm_range_deferred_list_work [amdgpu] hogged CPU for >10000us 5 times, consider switching to WQ_UNBOUND
(之后 2.5 分钟完全空白,然后死)
同时确认:
hardlockup_panic=1没有触发 → 不是 CPU 硬锁定;- 没有 MCE / EDAC / PCIe AER / 温度告警 / OOM;
- 没有任何 amdgpu 报错——和第一轮那条链完全是两回事。
顺便排除一个当时看着最像嫌疑人的东西:svm_range_deferred_list_work hogged CPU 这个警告。去历史上稳定跑了 7 小时的那次开机里数了一下,出现了 6 次,比出事那次还多。所以它只是这个负载下的正常噪音。
六、真正的修复:两个内核参数
出事负载的特征是极大量的 DMA 重映射:47 GB 固定主机内存 + 24 GB 显存 + 64 GB GTT,还要把十万级 token 的 KV 从内存往显存搬。而这台机器 VT-d 是 Default domain type: Translated(逐页翻译),卡还挂在 PCIe 交换机后面。
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash iommu=pt pcie_aspm=off"
iommu=pt:设备走直通域,绕开逐页 IOMMU 翻译;pcie_aspm=off:关掉 PCIe 链路电源态切换。
重启后确认生效:
iommu: Default domain type: Passthrough (set via kernel command line)
PCIe ASPM is disabled
七、复测:这次专门打"上次致死的那个负载"
上一轮我犯过一个错:只测了"能启动 + 4 路并发短请求"就宣布修好了,结果当天 17 分钟后又冻。因为真正的触发条件是超长 prompt,短请求根本压不到。
上次冻结发生在处理 159,282 token 的 prompt 时,所以复测必须打这个量级:
| 测试 | 结果 |
|---|---|
| 受控启动 + 900 秒看守窗口 | 通过 |
| 66,480 token prompt × 3 轮 | 0 故障 |
| 166,034 token × 2 轮 | 0 故障 |
| 12 分钟浸泡:88,815 token 冷 prefill × 10 轮 | 0 故障 |
浸泡期间实测:GPU 贴着 272W 封顶、最高 72 °C、显存最低剩 1420 MiB、内存可用从 66 GiB 降到 60 GiB。strata 连续跑了 26 分钟以上(上次是启动后 17 分钟冻的),全 boot amdgpu 故障 0 条。
八、可以直接抄走的几条做法
- 判断某次是不是硬冻结:只看该 boot 最后几行有没有
systemd-shutdown/Reached target Power-Off,别全文 grep。 - 让冻结留现场:
hardlockup_panic=1+kernel.panic=30,再加一个dmesg -w落盘的服务。这套组合第一次就能保住现场。 - memtest 不用赌开机按 Esc(GRUB 菜单被隐藏、超时 0 秒时很难进):
bash sudo grub-reboot "Memory test (memtest86+x64.efi)" && sudo reboot只影响下一次启动,跑完正常重启就回来了。 - 压测要压真正的触发条件:短请求并发跑一小时,不如一次十万级 token 的 prefill。
- 每轮 prompt 内容要不同,否则第二轮开始命中 KV 缓存,几秒就跑完,等于没测。
九、还没结的账
- memtest 至今没跑过。历史上还有"空载也冻结"和一次 POST 内存训练跑了 7 分 33 秒,这两条都没被解释。
- 所以这次通过的准确说法是:在当前负载画像下不再冻结,不等于硬件没问题。
- 如果哪天 memtest 报错或者又冻,下一步就是供电 / 主板,不是软件。
有同样"日志戛然而止式死机"的,可以先试试 iommu=pt——成本是一行内核参数,而且可回滚。
请登录后发表回复