当前配置快照:双路 Xeon + RX 7900 XTX 跑 strata 的完整环境(重装参考)
配套上一帖(三轮排查定位到 IOMMU)。这篇只记录当前机器上实际生效的配置,全部是从文件里读出来的、不是凭记忆写的,重装后照这个清单复原即可。
日期:2026-10-09
一、硬件
| 项 | 值 |
|---|---|
| CPU | 双路 Xeon(Broadwell-EP),sb_edac 内存控制器 |
| 内存 | 125 GiB |
| 系统盘 | /dev/sda2 233 G(ext4,已用 81%) |
| 模型盘 | /dev/sdb1 220 G(GLOWAY STK240GS3,ext4,noatime,已用 74%) |
| 计算卡 | 05:00.0 AMD Navi 31 / RX 7900 XTX 24G [1002:744c],挂在 PCIe 交换机后面,Gen4 x16,NUMA 0 |
| 显示卡 | 01:00.0 NVIDIA Quadro P600 [10de:1cb2],走 nouveau |
二、系统与内核
Ubuntu 24.04.5 LTS
内核 7.0.0-34-generic
/etc/default/grub 关键行:
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=0
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash iommu=pt pcie_aspm=off"
GRUB_CMDLINE_LINUX=""
iommu=pt和pcie_aspm=off就是上一帖的修复,重装后第一件事就是加这两个参数。 菜单被隐藏 + 超时 0 秒,想进 GRUB 菜单要开机按住Esc。跑 memtest 不用赌按键:bash sudo grub-reboot "Memory test (memtest86+x64.efi)" && sudo reboot
三、显卡驱动(这里最容易装错)
ROCm: /opt/rocm-7.1.1 (版本 7.1.1)
DKMS: amdgpu/7.1.3-2390945.24.04 → 已对 7.0.0-31 和 7.0.0-34 两个内核安装
加载模块: amdgpu(计算卡)、nouveau(P600)
⚠️ 绝对不要装 nvidia 专有驱动。装过 580 之后出现过一条清晰的死亡链(SMU: No response → MES failed to respond → Failed to quiesce KFD → ring sdma0 timeout → GPU reset begin! → 整机冻结)。P600 用 nouveau 就够,它只负责亮屏。
amdgpu 模块参数(当前值,来自 /sys/module/amdgpu/parameters/,无需手动设置):
ppfeaturemask = 0xfff7bfff
uni_mes = 1
svm_default_granularity = 9
注意:这个 DKMS 驱动下 power_dpm_force_performance_level 写入会失败(EROFS 类错误),所以降功耗只能走 power1_cap,见下面第四节。
四、sysctl
/etc/sysctl.d/99-strata-freeze-forensics.conf:
kernel.hardlockup_panic = 1
kernel.softlockup_panic = 1
kernel.panic_on_oops = 1
kernel.panic = 30
kernel.sysrq = 1
和 strata 相关的其它已有项:
vm.max_map_count = 1048576 # /etc/sysctl.d/10-map-count.conf,大模型必须
vm.nr_hugepages = 0 # 大页没开;strata 会报 MAP_HUGETLB unavailable,正常
五、三个自定义 systemd 服务
1. gpu-powercap —— 把 7900 XTX 封到 272W(驱动允许的最小值)
/etc/systemd/system/gpu-powercap.service(注意权限是 600 root):
[Unit]
Description=GPU power cap 272W for RX 7900 XTX (driver minimum)
After=multi-user.target
Wants=multi-user.target
[Service]
Type=oneshot
RemainAfterExit=yes
Environment=GPU_POWERCAP_W=272
ExecStart=/usr/local/lib/gpu-powercap/gpu-powercap.sh
StandardOutput=append:/var/log/gpu-powercap.log
StandardError=append:/var/log/gpu-powercap.log
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
踩过的坑:原来这个 unit 写了
After=sys-subsystem-net-devices-card1.device—— 把 DRM 的card1当成网络设备依赖,结果每次开机Job ... timed out/Dependency failed,封顶从来没生效过,卡一直跑出厂 303W。别加任何.device依赖,让脚本自己轮询等 hwmon。
/usr/local/lib/gpu-powercap/gpu-powercap.sh:
#!/bin/bash
# 把 AMD amdgpu 显卡的功率封顶写到驱动允许的最小值(默认 272W)。
set -uo pipefail
TARGET_W="${GPU_POWERCAP_W:-272}"
DEADLINE=$(( SECONDS + 120 ))
log() { echo "[gpu-powercap] $*"; }
find_cap_file() {
local d f
for d in /sys/bus/pci/devices/*; do
[ -r "$d/vendor" ] || continue
[ "$(cat "$d/vendor" 2>/dev/null)" = "0x1002" ] || continue
for f in "$d"/hwmon/hwmon*/power1_cap; do
[ -w "$f" ] && { echo "$f"; return 0; }
done
done
for f in /sys/class/drm/card*/device/hwmon/hwmon*/power1_cap; do
[ -w "$f" ] && { echo "$f"; return 0; }
done
return 1
}
CAP=""
while [ "$SECONDS" -lt "$DEADLINE" ]; do CAP="$(find_cap_file)" && break; sleep 2; done
[ -z "$CAP" ] && { log "错误: 120 秒内没找到可写的 power1_cap"; exit 1; }
log "找到: $CAP"
MIN="$(cat "$(dirname "$CAP")/power1_cap_min" 2>/dev/null || echo 0)"
log "当前封顶 = $(( $(cat "$CAP")/1000000 ))W, 驱动最小 = $((MIN/1000000))W"
[ "$(cat "$CAP")" = "$((TARGET_W*1000000))" ] && { log "已是目标值"; exit 0; }
if echo "$((TARGET_W*1000000))" > "$CAP" 2>/dev/null; then
log "✓ 已封顶至 ${TARGET_W}W (实际读回 $(( $(cat "$CAP")/1000000 ))W)"
else
log "错误: 写入失败"; exit 1
fi
2. kmsg-forensic —— 硬冻结后还能看到内核最后说了什么
/etc/systemd/system/kmsg-forensic.service:
[Unit]
Description=Persist kernel messages to disk (freeze forensics)
After=multi-user.target
[Service]
Type=simple
ExecStart=/usr/local/lib/kmsg-forensic/kmsg-forensic.sh
StandardOutput=append:/var/log/kmsg-forensic.log
StandardError=append:/var/log/kmsg-forensic.log
Restart=always
RestartSec=2
Nice=10
[Install]
WantedBy=multi-user.target
/usr/local/lib/kmsg-forensic/kmsg-forensic.sh:
#!/bin/bash
# 把内核日志实时追加到文件,供硬冻结后取证(journald 有时来不及落盘)
printf '\n===== boot %s uptime=%ss =====\n' "$(date '+%F %T')" "$(cut -d. -f1 /proc/uptime)"
exec dmesg -w
/etc/logrotate.d/kmsg-forensic:
/var/log/kmsg-forensic.log {
weekly
rotate 4
maxsize 64M
missingok
notifempty
compress
delaycompress
copytruncate
}
踩过的坑:一开始把 shell 逻辑写在
ExecStart里(ExecStart=/bin/bash -c '... exec >>/var/log/...'),systemd 报Failed to resolve unit specifiers ...: Invalid slot/bad-setting—— 因为 systemd 会展开$和%T。 正确做法:shell 逻辑放进脚本文件,unit 里只用StandardOutput=append:。 另外这个日志文件里有 NUL 字节,grep会报"匹配到二进制文件",要用grep -a。
3. power-saver —— CPU 调频/boost 随负载切换
/etc/systemd/system/power-saver.service(User=root,ExecStart=.../power-saver.sh watch)。
配置默认值写在脚本里,可用 /etc/power-saver/power-saver.conf 覆盖:
GOV_PERF=performance BOOST_PERF=1
GPU_DPM_PERF=highperformance # 这个驱动下写不进去,会打 warn,无害
它会在 GPU 忙时把 CPU governor 切到 performance、打开 turbo。如果怀疑供电余量不足,把 BOOST_PERF 改成 0 可以明显降低推理时的 CPU 峰值功耗(代价是专家层算得慢)。
六、strata 安装
仓库: https://github.com/Niko1221/Strata
版本: 0.1.40.3 (git d5ea713)
venv: Python 3.12.3
后端: HIP (gfx1100)
挂载(/etc/fstab)
UUID=a3c8fda5-7d6b-4bce-8765-2177cadc5d30 /mnt/strata ext4 defaults,noatime 0 2
/mnt/strata /home/mm/桌面/DP/strata-data none bind 0 0
注意这个 bind 挂载:
strata-iq3_s.json里所有路径都写成/home/mm/桌面/DP/strata-data/...,实际文件在/mnt/strata/。重装后如果少了这条 bind,配置里的路径全部失效。UUID 也要重新生成。
模型与数据(共 161 G)
/mnt/strata/Strata-data/models/ 151 G
/mnt/strata/Strata-data/mtp/ 6.5 G
/mnt/strata/Strata-data/packs/ 2.9 G
Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00001-of-00002.gguf 54.8 GB ← 主模型分片
Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00002-of-00002.gguf 28.8 GB ← PLE 分片
mmproj-Qwen3.8-Flash-Next-BF16.gguf 0.91 GB ← 视觉投影
mtp/mtp-q2_0.gguf 0.89 GB ← MTP 草稿模型
(另有 swift-IQ3_XXS 两套分片共 76 GB,当前配置没用)
辅助文件:
/mnt/strata/Strata/data/expert-profile.bin 196 KB
/mnt/strata/Strata/tools/hip/gfx1100-hipblaslt-100100-full.txt 1.2 KB
strata-iq3_s.json(当前完整内容)
{
"exe": "/home/mm/桌面/DP/strata-data/Strata/engine/strata",
"args": [
"--pack", "/home/mm/桌面/DP/strata-data/Strata-data/packs/iq3_s",
"--native", "/home/mm/桌面/DP/strata-data/Strata-data/models/IQ3_S/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00001-of-00002.gguf",
"--ple-gguf", "/home/mm/桌面/DP/strata-data/Strata-data/models/IQ3_S/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00002-of-00002.gguf",
"--expert-profile", "/home/mm/桌面/DP/strata-data/Strata/data/expert-profile.bin",
"--expert-cache", "auto",
"--prefill", "auto",
"--spec", "4",
"--spec-min-p", "0.5",
"--mtp", "/home/mm/桌面/DP/strata-data/Strata-data/mtp/rt",
"--mtp-window", "65536",
"--max-context", "262144",
"--kv", "int8",
"--kv-resident", "32768",
"--vision",
"--vram-reserve-mib", "2560"
],
"cwd": "/home/mm/桌面/DP/strata-data/Strata",
"tokenizer": "/home/mm/桌面/DP/strata-data/Strata-data/packs/iq3_s/tokenizer",
"model_name": "qwen3.8-flash-next-iq3_s",
"log": "/home/mm/桌面/DP/strata-data/Strata/strata-iq3_s.log",
"lib_dirs": ["/opt/rocm/lib"],
"port": 8180,
"backend": "hip",
"env": {
"STRATA_HIPBLASLT_TUNING": "/home/mm/桌面/DP/strata-data/Strata/tools/hip/gfx1100-hipblaslt-100100-full.txt"
},
"vision": {
"exe": "/home/mm/桌面/DP/strata-data/Strata/engine/strata-vision",
"mmproj": "/home/mm/桌面/DP/strata-data/Strata-data/models/mmproj-Qwen3.8-Flash-Next-BF16.gguf",
"model": "/home/mm/桌面/DP/strata-data/Strata-data/models/IQ3_S/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_S-00001-of-00002.gguf",
"gpu": false,
"max_tokens": 300,
"threads": 18
},
"fit_max_tokens": true
}
这个日志文件是 NUL 填充的,读的时候要
tr -d '\000' < strata-iq3_s.log。
~/.config/systemd/user/strata.service
[Unit]
Description=Strata 本地大模型服务 (Qwen3.8-Flash-Next IQ3_S / RX 7900 XTX / HIP)
After=default.target
[Service]
Type=simple
WorkingDirectory=/mnt/strata/Strata
# 直接调 server.py 而不走 run-*.sh:脚本里带 --open,每次重启会弹浏览器窗口
ExecStart=/mnt/strata/Strata/.venv/bin/python /mnt/strata/Strata/serve/server.py \
--engine strata \
--config /mnt/strata/Strata/strata-iq3_s.json \
--port 8180
# 首次加载要把 ~47GB 专家读进内存并填充显存,1-3 分钟,别掐断
TimeoutStartSec=900
TimeoutStopSec=120
Restart=on-failure
RestartSec=15
KillMode=mixed
Nice=-5
IOSchedulingClass=best-effort
IOSchedulingPriority=2
[Install]
WantedBy=default.target
当前状态是 disabled(不开机自启),故意的:确认稳定几天后再 systemctl --user enable strata.service。
用户级服务要在注销后也能跑,必须开 linger:
sudo loginctl enable-linger mm # 当前已是 Linger=yes
七、重装复原顺序(照这个走)
- 装系统 → 装 ROCm 7.1.1 + DKMS amdgpu 7.1.3(
amdgpu-install带 dkms)。 - 不要装 nvidia 专有驱动,P600 用 nouveau。
- 改
/etc/default/grub加iommu=pt pcie_aspm=off→sudo update-grub→ 重启。 - 挂模型盘到
/mnt/strata,加那条 bind 挂载,确认strata-iq3_s.json里的路径都能解析。 - 写
/etc/sysctl.d/99-strata-freeze-forensics.conf→sudo sysctl --system。 - 装
gpu-powercap(unit + 脚本)→sudo systemctl enable --now gpu-powercap.service→ 读回确认:bash echo $(( $(cat /sys/class/drm/card1/device/hwmon/hwmon0/power1_cap)/1000000 ))W # 应为 272W - 装
kmsg-forensic(unit + 脚本 + logrotate)→ enable。 git cloneStrata → checkout0.1.40.3→ 建 venv → 拷模型(161 G,最花时间)。- 写
strata-iq3_s.json和strata.service→loginctl enable-linger→ 先手动受控启动一次,别直接 enable。
八、装完怎么确认没问题
# 内核参数生效
cat /proc/cmdline | grep -o 'iommu=pt\|pcie_aspm=off'
dmesg | grep -i "Default domain type" # 应为 Passthrough
# 功率封顶真的落地
echo $(( $(cat /sys/class/drm/card1/device/hwmon/hwmon0/power1_cap)/1000000 ))W
# 服务健康
curl -s http://127.0.0.1:8180/health
# 显卡有没有报错(本次开机)
journalctl -k -b 0 | grep -cE 'SMU: No response|MES failed|ring .* timeout|GPU reset begin'
# 判断上一次开机是不是硬冻结:只看最后几行,别全文 grep(会匹配到诊断命令本身)
journalctl -b -1 -n 5 | grep -E 'systemd-shutdown|Reached target Power-Off' || echo "上次是硬冻结"
九、负载画像(压测要压这个才有效)
主机内存固定(pin): ~46.8 GiB 专家权重 + ~3.1 GiB KV
显存占用: ~23.5 GiB(剩余常在 1.4–1.7 GiB)
CPU: 18 线程
压测必须用十万级 token 的冷 prefill(每轮内容不同,否则命中 KV 缓存几秒就跑完)。短请求并发跑一小时也测不出来 —— 上一帖就是栽在这里。
请登录后发表回复