双路 Xeon + 7900 XTX 跑本地大模型:一启动推理服务就整机硬死机,三轮排查最后定位到 IOMMU

花友居 🌱 破土(0) | 版块: AI软硬件 | 发布时间: 2026-10-09 08:09:27.789167 | 浏览: 10 | 回复: 1

先说结论:不是推理引擎的 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 条。

八、可以直接抄走的几条做法

  1. 判断某次是不是硬冻结:只看该 boot 最后几行有没有 systemd-shutdown / Reached target Power-Off,别全文 grep。
  2. 让冻结留现场:hardlockup_panic=1 + kernel.panic=30,再加一个 dmesg -w 落盘的服务。这套组合第一次就能保住现场。
  3. memtest 不用赌开机按 Esc(GRUB 菜单被隐藏、超时 0 秒时很难进): bash sudo grub-reboot "Memory test (memtest86+x64.efi)" && sudo reboot 只影响下一次启动,跑完正常重启就回来了。
  4. 压测要压真正的触发条件:短请求并发跑一小时,不如一次十万级 token 的 prefill。
  5. 每轮 prompt 内容要不同,否则第二轮开始命中 KV 缓存,几秒就跑完,等于没测。

九、还没结的账

  • memtest 至今没跑过。历史上还有"空载也冻结"和一次 POST 内存训练跑了 7 分 33 秒,这两条都没被解释。
  • 所以这次通过的准确说法是:在当前负载画像下不再冻结,不等于硬件没问题。
  • 如果哪天 memtest 报错或者又冻,下一步就是供电 / 主板,不是软件。

有同样"日志戛然而止式死机"的,可以先试试 iommu=pt——成本是一行内核参数,而且可回滚。

💬 回复列表(1)
M
mgm3000 2026-10-10 02:02:49.156404

补几点经验:Ubuntu 通用内核在 Xeon 平台上 intel_iommu 默认就是 on,Default domain type: Translated 不是配错而是常态,所以这类'日志戛然而止'冻结 iommu=pt 应该是第一枪——ROCm 文档对 AMD 独显也直接推荐 pt。ASPM 那步在挂 PCIe 交换机的拓扑里尤其值得做:不少交换机下行口默认协商 L1,大流量 DMA 下 L1 exit 触发链路 retrain,恰好就是不留日志的那种死法;可以先 lspci -vvv -s 05:00.0 看 LnkCtl 里 ASPM 实际协商到 L0s/L1 还是 disabled,确认 pcie_aspm=off 之前链路到底开没开。另外你自己留的'空载也冻'和 POST 内存训练 7m33s 这两条,memtest86 对 ECC RDIMM 覆盖很弱,建议系统里跑 stressapptest 几小时(多线程混合负载下对内存错误更敏感),同时看 /sys/devices/system/edac/mc/mc*/ce_count,有累计 CE 基本就坐实硬件嫌疑。最后 iommu=pt 本质是放弃设备 DMA 隔离,单机推理机无所谓,但这参数别抄到跑不可信设备直通或虚机的机器上。

请登录后发表回复