<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[双 RX 7900 XTX 跑 88GB 的 MoE：Strata HIP 后端单卡/双卡实测 + 踩坑全记录]]></title><description><![CDATA[<blockquote>
<p dir="auto"><strong>环境</strong>：i7-10700K（8C16T，无 AVX-512）+ 2× RX 7900 XTX 24GB + 64GB DDR4 + Ubuntu 22.04 / ROCm 7.2.1<br />
<strong>模型</strong>：Qwen3.8-Flash-Next-AD-4.27bpw-Q4_K_M-M64（33 分片，89GB，512 专家）<br />
<strong>引擎</strong>：Strata v0.1.38 HIP 后端 · 32K 上下文 · int8 KV · <code>--spec 4</code> 投机解码<br />
<strong>实测日期</strong>：2026-10-04</p>
</blockquote>
<hr />
<h2>首先说明，这是ai生成的报告，如果不想看内容，建议直接复制丢给ai总结</h2>
<h2>TL;DR</h2>
<ol>
<li><strong>能跑。</strong> 单卡 7900 XTX 就能带起 89GB 的 MoE —— 专家权重常驻内存、最热的缓进显存。单卡稳态 <strong>decode ≈ 63~66 tok/s、prefill 600+ tok/s</strong>。</li>
<li><strong>双卡只在 prefill 上赢。</strong> 多轮对话的追加延迟从 1444ms 砍到 754ms（快 1.9 倍）；<strong>decode 反而略降</strong>（66 → 63），因为 decode 是显存带宽瓶颈，layer-split 每步多一次跨卡同步。</li>
<li><strong>prefill 原本比官方低 35%，根因是自己踩的坑</strong>：hipBLASLt 调优表按「架构 + 库版本」精确匹配，官方 gfx1100 只给了 <code>100100</code>/<code>100200</code> 两张，我这台是 <strong>100202</strong> → 无表可用 → dense GEMM 走默认路径。<strong>自己标定一张接进去，fresh 8.8K prefill 722 → 1016 tok/s（+41%），直接反超官方。</strong></li>
<li>一共踩了 <strong>7 个坑</strong>，第 5 个（调优表）是最大的性能损失，第 7 个（大页）是「看起来该做、实测完全没用」的反面教材。</li>
</ol>
<hr />
<h2>1. Strata 是什么</h2>
<p dir="auto">Strata 是一个 <strong>MoE 专用推理引擎</strong>（<a href="https://github.com/Niko1221/Strata" rel="nofollow ugc">https://github.com/Niko1221/Strata</a>）。核心思路和 llama.cpp 不一样：</p>
<ul>
<li><strong>专家权重不像传统做法那样全塞进显存，而是常驻主机内存</strong>，只把路由最频繁的一小撮专家缓存进显存；</li>
<li>显存里的专家直接由 GPU 算，没命中的走 CPU/SSD 路径；</li>
<li>于是 <strong>24GB 的消费级卡也能跑 89GB 的大模型</strong>。</li>
</ul>
<p dir="auto">它还带一个 opt-in 的 <strong>gfx1100 HIP 后端</strong>，让 RDNA3 的 A 卡能用上 MMQ、校准过的 hipBLASLt dense GEMM、MTP 投机解码这些优化。</p>
<p dir="auto">对「双 7900 XTX + 大内存」这种配置来说，这是目前少数能让两张 XTX 真正一起干活的路径 —— llama.cpp 跑这种体量的 MoE，要么装不下、要么慢到没法用。</p>
<hr />
<h2>2. 硬件配置（全部实测，非标称）</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>项</th>
<th>值</th>
</tr>
</thead>
<tbody>
<tr>
<td>CPU</td>
<td>Intel Core i7-10700K @ 3.80GHz，<strong>8C/16T</strong>，L3 16MB，<strong>无 AVX-512</strong>（只有 AVX2）</td>
</tr>
<tr>
<td>主板</td>
<td>ASUS ROG STRIX Z590-A GAMING WIFI</td>
</tr>
<tr>
<td>内存</td>
<td><strong>64GB</strong>（2×32GB Corsair DDR4-3200），<strong>无 swap</strong>，系统可用 62.64 GiB</td>
</tr>
<tr>
<td>GPU</td>
<td><strong>2× Radeon RX 7900 XTX</strong> 24GB，gfx1100，PCIe host→device 实测 <strong>6.9 GB/s</strong></td>
</tr>
<tr>
<td>存储</td>
<td>aigo NVMe SSD P7000Z 2TB（数据都在这块盘上）</td>
</tr>
<tr>
<td>系统</td>
<td>Ubuntu 22.04.5 LTS，内核 6.8.0-138</td>
</tr>
<tr>
<td>ROCm</td>
<td><strong>7.2.1</strong>（HIP 7.2.53211，AMD clang 22）</td>
</tr>
<tr>
<td>hipBLASLt</td>
<td>1.2.2，<strong>版本号 100202</strong> ← 记住这个数，坑 5 全靠它</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>两个先天短板</strong>（后面会反复出现）：</p>
<ol>
<li><strong>CPU 没有 AVX-512</strong> —— 引擎启动时直接点名：<pre><code>strata generate: this CPU has no AVX-512: the expert kernels run on AVX-2
</code></pre>
官方测试机是 Ryzen 9 7950X3D（16C32T + AVX-512），CPU 侧算专家比我快不少。</li>
<li><strong>内存只有 64GB 且无 swap</strong> —— 而模型光专家就要 47.17 GiB。双卡全驻留会压到危险线。</li>
</ol>
<hr />
<h2>3. 模型与引擎：真实的加载方式</h2>
<p dir="auto">这部分我一开始理解错了，写出来给后来人少走弯路。</p>
<p dir="auto"><strong>模型</strong>：<code>Qwen3.8-Flash-Next-AD-4.27bpw-Q4_K_M-M64</code>，33 个分片共 <strong>89GB</strong>，架构 <code>qwen4exp</code>，<strong>512 个专家</strong>。</p>
<p dir="auto"><strong>Strata 不是把 89GB 全重新打包一遍。</strong> 它生成的 pack 目录只有 <strong>1.4 GiB</strong>：</p>
<pre><code>packs/iq3_xxs/
  dense.bin          1.42 GiB   ← 只有非专家的 dense/attention 权重
  native_experts.txt     8 KB   ← 48 层专家的清单（偏移表）
  index.txt             91 KB
  tokenizer/
</code></pre>
<p dir="auto"><code>native_experts.txt</code> 的头两行说明了关键机制：</p>
<pre><code># strata native experts v4: ... (n_expert 512, total 50646220800;
#   absolute offsets in Qwen3.8-Flash-Next-AD-4.27bpw-Q4_K_M-M64-00001-of-00033.gguf ...)
0 21 20 0 2329600 1193596736 1561038656 719996736 ...00003-of-00033.gguf
</code></pre>
<p dir="auto"><strong>专家权重根本没被搬走</strong> —— 它们原样留在原来的 33 个 GGUF 分片里，引擎记下每层每专家 gate/up/down 的<strong>绝对偏移</strong>，运行时直接从分片读。50646220800 字节 = <strong>47.17 GiB</strong>，正好等于引擎启动时那句 <code>loaded 47.17 GiB</code>。</p>
<p dir="auto">另外两个附件：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>文件</th>
<th>大小</th>
<th>作用</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>ple-q5_0.gguf</code></td>
<td><strong>32.78 GiB</strong></td>
<td>PLE（per-layer embedding 表），放 SSD 上按需读</td>
</tr>
<tr>
<td><code>mtp/rt</code></td>
<td><strong>787 MiB</strong></td>
<td>MTP 草稿层，投机解码用</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>磁盘预留</strong>：原 GGUF 89GB + <code>Strata-data</code> 41GB ≈ <strong>130GB</strong>，而且原 GGUF 必须留着（专家从它读）。</p>
<p dir="auto"><strong>引擎</strong>：Strata <strong>v0.1.38</strong>，HIP 后端。实测启动参数：</p>
<pre><code>--expert-cache auto --prefill auto --spec 4 --spec-min-p 0.5
--mtp .../mtp/rt --max-context 32768 --kv int8 --ple-gguf .../ple-q5_0.gguf
--layer-split auto
</code></pre>
<hr />
<h2>4. 部署步骤</h2>
<pre><code class="language-sh"># 1) 编译（用系统已装的 ROCm 7，不必再下 10GB 的 wheel）
./setup.sh --backend hip --family qwen --model IQ3_XXS \
  --gguf-dir /path/to/Qwen3.8-Flash-Next-AD-4.27bpw-Q4_K_M-M64 \
  --data-dir /path/to/Strata-data --context 32768 \
  --gpu 0 --build --no-start --yes

# 2) 单卡启动
run-iq3_xxs.sh
#    内部即 serve/server.py --engine strata --config strata-iq3_xxs.json --port 8080

# 3) 双卡：setup 时把 --gpu 0 换成 --gpus 1,0（自动 layer split）
</code></pre>
<p dir="auto">我这台 8C16T 编译耗时 <strong>8 分钟</strong>（官方标称 10~20 分钟）。</p>
<hr />
<h2>5. 实测速度</h2>
<p dir="auto"><strong>方法</strong>：用官方 <code>tools/hip/bench_prefill.py</code>，同一份合成 prompt（140/280 个 <code>rule</code> 函数），每档先 warmup 一次、再跑 <strong>2 轮</strong>，每轮先 fresh（零复用 KV）、紧跟一个 followup（带缓存追加）。输出固定 128 token，温度 0 / top-k 1。每组配置<strong>独立重启引擎</strong>后测量。</p>
<p dir="auto">单位 tok/s，括号内是波动范围。</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>指标</th>
<th>单卡</th>
<th>双卡 native</th>
<th>双卡 low-RAM</th>
</tr>
</thead>
<tbody>
<tr>
<td>fresh prefill 4.2K</td>
<td>607 (537~677)</td>
<td><strong>702</strong> (701~703)</td>
<td>479 (439~519)</td>
</tr>
<tr>
<td>fresh prefill 8.8K</td>
<td>628 (621~634)</td>
<td><strong>722</strong> (722~722)</td>
<td>543 (542~543)</td>
</tr>
<tr>
<td>followup prefill（113 token 追加）</td>
<td>78.6</td>
<td><strong>149.8</strong></td>
<td>107.8</td>
</tr>
<tr>
<td>↳ 这一轮的实际耗时</td>
<td>1444 ms</td>
<td><strong>754 ms</strong></td>
<td>1053 ms</td>
</tr>
<tr>
<td>fresh decode 4.2K</td>
<td>52.0 (40~64)</td>
<td>57.5 (54~60)</td>
<td>52.5 (46~59)</td>
</tr>
<tr>
<td>fresh decode 8.8K</td>
<td><strong>66.0</strong> (65~67)</td>
<td>62.9 (62~64)</td>
<td>60.7 (60~61)</td>
</tr>
<tr>
<td>followup decode 4.2K / 8.8K</td>
<td>50.2 / 61.7</td>
<td>58.3 / 55.8</td>
<td>53.3 / 56.1</td>
</tr>
<tr>
<td>稳态 decode（去掉每档第一枪）</td>
<td><strong>~63</strong></td>
<td>~59</td>
<td>~57</td>
</tr>
<tr>
<td>额外内存</td>
<td>~47GB 常驻，最省</td>
<td>双卡全驻留，最紧</td>
<td>自适应退回 mmap</td>
</tr>
<tr>
<td>VRAM 剩余</td>
<td>624 MiB</td>
<td>598 MiB</td>
<td>—</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>加调优表之后</strong>（见坑 5）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>指标</th>
<th>双卡 native</th>
<th>双卡 native + 调优表</th>
<th>变化</th>
</tr>
</thead>
<tbody>
<tr>
<td>fresh prefill 4.2K</td>
<td>702</td>
<td><strong>773</strong> (710~836)</td>
<td>+10%</td>
</tr>
<tr>
<td>fresh prefill 8.8K</td>
<td>722</td>
<td><strong>1016</strong> (992~1040)</td>
<td><strong>+41%</strong></td>
</tr>
<tr>
<td>followup prefill 4.2K</td>
<td>150</td>
<td><strong>221</strong></td>
<td>+47%</td>
</tr>
<tr>
<td>followup prefill 8.8K</td>
<td>153</td>
<td>175</td>
<td>+14%</td>
</tr>
<tr>
<td>decode（各档）</td>
<td>55.8~62.9</td>
<td>55.2~58.5</td>
<td>基本不动</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>引擎日志里的关键指标</strong>（同一批请求）：</p>
<ul>
<li>显存专家缓存命中率：<strong>96.9% ~ 99.5%</strong>（第一个冷请求 87.7%，长 prompt 越接近 99.5%）</li>
<li>投机解码接受率：<strong>70.6%</strong>（3116/4412）</li>
<li>layer split 决策：<code>K=22</code>，CUDA1 跑第 22~47 层 + head，CUDA0 跑第 0~21 层；CUDA1 专家缓存 8704 槽（16.81 GiB）</li>
<li>PCIe 探测：单卡 6.9 GB/s → <code>pcie_frac 0.19</code>（默认 0.55）</li>
</ul>
<hr />
<h2>6. 三个反直觉的结论</h2>
<p dir="auto"><strong>① 双卡的收益全在 prefill，decode 甚至倒退。</strong></p>
<p dir="auto">decode 阶段每生成一个 token 只算一遍专家，瓶颈是显存带宽；layer-split 让每层之后都要跨卡同步一次，纯亏。而 prefill 是把上万 token 一次性塞进去算，compute-bound，两张卡并行摊分，稳赚。</p>
<p dir="auto">所以 <strong>「双卡加速」是有条件的</strong>：看你负载是长 prompt（RAG / 代码库分析 / 长文档）还是长输出（写作 / 聊天）。</p>
<p dir="auto"><strong>② followup 那一行的 78.6 → 149.8，不是「吞吐翻倍」，是「每轮固定开销减半」。</strong></p>
<p dir="auto">它只处理 113 个新 token，却花了 1444ms（单卡）/ 754ms（双卡）—— 这是 prompt 分块的固定成本。换成体感：<strong>多轮对话里，第二轮开始每轮只等 1.44s 还是 0.76s</strong>，差一倍。这个才是双卡对聊天场景的实际价值。</p>
<p dir="auto"><strong>③ low-RAM 模式掉得比想象中多。</strong></p>
<p dir="auto">4.2K prefill 只有 479，比单卡的 607 还低 21%，比双卡 native 低 32%。它换来的是内存安全垫 —— 如果你内存不够又要开双卡，这是唯一能稳跑的选择。</p>
<hr />
<h2>7. 踩的 7 个坑（含解法）</h2>
<h3>坑 1：Strata 不直接吃 GGUF，下载又慢到不能看</h3>
<p dir="auto">引擎要自己的 pack 目录（见第 3 节）。同时还要额外拿 PLE（32.78 GiB）和 MTP 草稿层（787 MiB）。</p>
<p dir="auto"><strong>解法</strong>：预留 <strong>130GB</strong> 磁盘，下载走本地代理（我这边是 2080 端口的本地代理），直连速度没法看。<strong>原 GGUF 千万别删 —— 专家是从它读的。</strong></p>
<h3>坑 2：引擎要现场编译</h3>
<p dir="auto"><code>./setup.sh --backend hip --build</code>。我这台 8C16T 编了 <strong>8 分钟</strong>（官方标称 10~20 分钟）。依赖 <code>build-essential git</code>；系统要是已经装了 ROCm 7，可以直接复用，不用再下 10GB 的 TheRock wheel。</p>
<h3>坑 3：47GB 常驻内存是硬门槛</h3>
<p dir="auto">引擎启动时把专家权重常驻主机内存：</p>
<pre><code>strata generate: loaded 47.17 GiB at 2.58 GiB/s
</code></pre>
<p dir="auto">64GB 的机器单卡勉强够；<strong>双卡同时做全量驻留会直接把内存压到危险线</strong>。官方为此提供了低内存模式（自适应驻留、装不下就退回 mmap），代价是 prefill 掉 32%（见对照表）。</p>
<p dir="auto"><strong>注意</strong>：双卡 layer-split 模式下引擎还会警告：</p>
<pre><code>WARNING: the resident RAM mode (--resident-experts) does not support a layer split yet:
the experts the GPUs do not hold are read through the OS file cache (--mmap-experts),
and RAM may fill up during long prompts
</code></pre>
<p dir="auto">也就是 GPU 不持有的专家会走 OS 文件缓存，长 prompt 下 RAM 可能要涨。</p>
<h3>坑 4：hipBLASLt 调优表没有可用的（本次最大性能损失）</h3>
<p dir="auto">官方的调优表是<strong>按 (架构 + hipBLASLt 版本) 精确匹配</strong>的，表头直接写着版本：</p>
<pre><code>STRATA_HIPBLASLT_TUNING_V1 gfx1100 100200
</code></pre>
<p dir="auto">引擎会硬校验架构和版本号，<strong>对不上就整张拒绝</strong>：</p>
<pre><code>tuning architecture mismatch: file=... runtime=...
hipBLASLt version mismatch: file=... runtime=...
</code></pre>
<p dir="auto">仓库里 gfx1100 只有两张表：<code>-100100.txt</code> 和 <code>-100200.txt</code>。我这台是 hipBLASLt 1.2.2 = <strong>版本号 100202</strong> —— <strong>两张都对不上</strong>。（有意思的是同一个目录里 gfx1200 / gfx1201 <strong>都</strong>有 100202 的表，唯独 gfx1100 没有。）</p>
<p dir="auto">结果：配置里根本没有 <code>STRATA_HIPBLASLT_TUNING</code>，dense 矩阵乘法走默认 GEMM 路径。</p>
<p dir="auto">官方在 gfx1200 上量化过这张表的收益：<strong>2.4K prompt 提速 1.5x，65K/130K prompt 约 2x</strong>。gfx1100 官方没给数字，但机制相同。</p>
<p dir="auto"><strong>解法 —— 自己标定一张（官方工具就摆在仓库里）</strong>：</p>
<pre><code class="language-sh">cmake --build build-hip --target tune_hipblaslt

CASES=$(awk 'NR&gt;2 {printf " --case %s,%s,%s,%s,%s", $1, $5, $2, $3, $4}' \
        tools/hip/gfx1100-hipblaslt-100100.txt)
./build-hip/tune_hipblaslt $CASES --tuning-out tools/hip/gfx1100-hipblaslt-100202.txt
</code></pre>
<p dir="auto">几个要点：</p>
<ul>
<li><strong>形状集取仓库两张 gfx1100 表的并集</strong>（30 个形状，100200 那张是它的子集），覆盖更全；</li>
<li>工具自带精度门（relative L2 / max abs / padding 写入检查），跑完 <strong>30 条全过、零 reject</strong>；</li>
<li>产出的表头就是运行时的真实版本：<code>STRATA_HIPBLASLT_TUNING_V1 gfx1100 100202</code>；</li>
<li>跑完几分钟，然后接进配置（<code>strata-iq3_xxs.json</code> 加一个 <code>env</code> 键）：</li>
</ul>
<pre><code class="language-json">"env": {
  "STRATA_HIPBLASLT_TUNING": ".../tools/hip/gfx1100-hipblaslt-100202.txt"
}
</code></pre>
<p dir="auto">重启后引擎日志会确认（两张卡各一行）：</p>
<pre><code>prefill gemm: hipBLASLt tuning enabled (30 rows, gfx1100, version 100202)
</code></pre>
<p dir="auto"><strong>效果：fresh 8.8K prefill 722 → 1016 tok/s（+41%），一次把「比官方低 35%」打成反超。</strong></p>
<blockquote>
<p dir="auto"><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=fe25256ab4a" class="not-responsive emoji emoji-android emoji--warning" style="height:1.4em;width:auto;vertical-align:middle" title="⚠" alt="⚠" />️ 别被工具自己的输出骗了：它报的 <code>speedup_vs_blas</code> 中位数是 <strong>5x</strong>（最高 18x），那是<strong>单条 GEMM 对 plain hipBLAS 的微基准</strong>，不是端到端收益。端到端看上面那张表。</p>
<p dir="auto"><img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/26a0.png?v=fe25256ab4a" class="not-responsive emoji emoji-android emoji--warning" style="height:1.4em;width:auto;vertical-align:middle" title="⚠" alt="⚠" />️ <strong>维护提醒</strong>：表是绑死 (架构 + hipBLASLt 版本) 的。升级 ROCm 后版本号一变，表就被拒，要重跑一次标定。</p>
</blockquote>
<h3>坑 5：冷启动第一枪很慢</h3>
<p dir="auto">第一次请求（显存专家缓存未热）decode 只有 <strong>39.9 tok/s</strong>（warmup 那枪甚至 19），第二枪才回到 64+。</p>
<p dir="auto"><strong>解法</strong>：做基准测试必须先 warmup，否则平均分被第一枪拖死。这也是很多「评测翻车」的来源。</p>
<h3>坑 6：NVMe 卷是 NTFS，断电后拒挂</h3>
<p dir="auto">这块数据盘是 NTFS 格式。强制断电后重新开机，Linux 会因为 <strong>dirty bit</strong> 直接拒绝挂载（<code>$MFTMirr does not match $MFT</code>）。</p>
<p dir="auto"><strong>解法</strong>：<code>sudo ntfsfix -d /dev/nvmeXnY</code>，再 mount 即可。盘本身没坏，只是上次没正常卸载。</p>
<h3>坑 7：大页 —— 看起来该做，实测完全没用（反面教材）</h3>
<p dir="auto">引擎启动时会抱怨：</p>
<pre><code>expert arena: cudaHostRegister PORTABLE ok;
  MAP_HUGETLB unavailable (needed 24152 2 MiB pages, vm.nr_hugepages=0); using 4 KB pages
</code></pre>
<p dir="auto">4KB 页下 47 GiB 要 1200 万个 TLB 项，任何 TLB 都装不下。官方的设计注释也说大页能把 TLB 覆盖翻倍以上。看起来是个大便宜 —— <strong>我去试了，结论是：不值得。</strong></p>
<p dir="auto"><strong>第一关：运行时根本开不起来。</strong></p>
<p dir="auto">引擎要 <strong>24152 个 2 MiB 页</strong>（= 47.17 GiB，正好等于专家 arena），而 <code>MAP_HUGETLB</code> 是<strong>全有全无</strong>：池子少一页，整个映射就跟没有池子一样失败。</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>尝试</th>
<th>拿到的页数</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>sysctl vm.nr_hugepages=24152</code></td>
<td>12557</td>
</tr>
<tr>
<td>丢 page cache + 反复补池</td>
<td>搬到 19570，然后每次只 +几页</td>
</tr>
<tr>
<td>内存压缩（<code>compact_memory</code>）+ 丢缓存 + 反复补</td>
<td>卡在 <strong>19698</strong>（38.5 GiB）</td>
</tr>
<tr>
<td>整池释放、压缩、一次性要满</td>
<td>还是 <strong>19698</strong>（复现两次，非随机）</td>
</tr>
</tbody>
</table>
<p dir="auto">根因在 <code>/proc/buddyinfo</code>：运行中的内核 <strong><code>order-9</code>（2 MiB 连续块）恒为 0</strong>。内存虽然有 15 GiB 空闲，但已被切碎到没有 2 MiB 连续块，压缩也合并不出来。<strong>只能开机预留</strong>（内存未碎片化时才能一次拿到）：</p>
<pre><code># /etc/sysctl.d/99-strata-hugepages.conf
vm.nr_hugepages = 24152
</code></pre>
<p dir="auto"><strong>第二关：代价太大。</strong> 62.64 GiB 里内核/驱动先占掉约 9.8 GiB（<code>iommu=pt</code> + amdgpu），能给人用的只有 53 GiB。预留 47.17 GiB 后<strong>只剩 5.7 GiB 给整个系统</strong>（还没 swap）—— 开个浏览器就可能 OOM，ComfyUI / vLLM 全废。等于把这台机改成「Strata 专用机」。</p>
<p dir="auto"><strong>第三关：就算成了，也没用。</strong> 我换了条零成本的路验证 —— 把 <strong>THP（透明大页）</strong> 从 <code>madvise</code> 切成 <code>always</code>，arena 的匿名内存在分配时就直接拿 2 MiB 页，不占任何预留：</p>
<pre><code>引擎进程 RSS 49.56 GiB，其中 AnonHugePages = 38.38 GiB（77%）
</code></pre>
<p dir="auto"><strong>覆盖率和预留大页池能给到的 38.5 GiB 几乎一样</strong>。但压测结果：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>档位</th>
<th>有调优表</th>
<th>+ THP</th>
</tr>
</thead>
<tbody>
<tr>
<td>fresh 8.8K prefill（第 1 / 第 2 轮）</td>
<td>1040.1 / 991.5</td>
<td>900.0 / <strong>1035.9</strong></td>
</tr>
<tr>
<td>fresh 4.2K prefill（第 1 / 第 2 轮）</td>
<td>710.2 / 835.6</td>
<td>512.6 / 703.6</td>
</tr>
<tr>
<td>followup 4.2K prefill</td>
<td>270.3 / 171.3</td>
<td>269.9 / 170.5</td>
</tr>
<tr>
<td>decode（各档）</td>
<td>52.0~60.0</td>
<td>51.4~59.8</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>逐轮看，差值全在 run-to-run 噪声里</strong>（THP 组 8.8K 第二轮反而更高），followup 和 decode 两边几乎完全一致。</p>
<p dir="auto"><strong>为什么？</strong> 因为官方讲 TLB reach 的前提是「专家 arena 就是工作集」（小显存卡、流式取专家）。而这台机器 <code>--expert-cache auto</code> 拿了 8704~9724 个显存槽、<strong>命中率 96.9%~99.5%</strong> —— 绝大多数专家访问直接命中显存，主机 arena 的 TLB 根本没被压到。</p>
<p dir="auto"><strong>结论：大页（预留池也好、THP 也好）在这台机器上没有可测收益，不值得拿 47 GiB 去换。</strong></p>
<p dir="auto">（THP 已还原成 <code>madvise</code>，机器状态和之前一致。）</p>
<hr />
<h2>8. 我的数字 vs 官方：差距在哪</h2>
<p dir="auto">官方在同型号 IQ3_XXS 上的数据（<strong>单卡</strong> RX 7900 XTX / <strong>Ryzen 9 7950X3D 16C32T</strong> / 64GiB / Fedora / <strong>ROCm 7.1</strong> / 272W 功耗墙 / <strong>已启用 100100 调优表</strong> / <code>--resident-cpu-experts --mmap-experts</code> 路径 / <code>--max-context 262144</code> / <code>--pool-workers 15</code>）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>指标</th>
<th>官方（单卡，有表）</th>
<th>我这台（单卡，原先无表）</th>
<th>我这台（双卡 + 自标表）</th>
</tr>
</thead>
<tbody>
<tr>
<td>4.2K fresh prefill</td>
<td>447.5 首次 / 901.1 热</td>
<td>607 (537~677)</td>
<td>773</td>
</tr>
<tr>
<td>8.8K fresh prefill</td>
<td>873.7 首次 / 966.5 热</td>
<td>628 (621~634)</td>
<td><strong>1016</strong></td>
</tr>
<tr>
<td>decode</td>
<td>55.5 ~ 59.2</td>
<td>66 (65~67)</td>
<td>58.5 (双卡) / 66 (单卡)</td>
</tr>
</tbody>
</table>
<p dir="auto"><strong>修好调优表之前，我的 prefill 低约 35%，decode 反而略高。</strong> 根因：</p>
<ol>
<li><strong>hipBLASLt 调优表无表可用</strong> —— <strong>主因，现已修复（+41%）</strong>；</li>
<li><strong>CPU 没有 AVX-512</strong> —— 官方是 Zen4，CPU 侧算专家吃亏；</li>
<li><strong>CPU 核心数只有一半</strong>（8C16T vs 16C32T），引擎默认开 7 个 expert-pool worker；</li>
<li>官方配置里还有 <code>STRATA_PREFILL_MMQ=1</code>、<code>STRATA_PREFILL_RING=96</code>、<code>STRATA_IO_THREADS=32</code> 这些运行时变量，我没启用；</li>
<li>专家的驻留路径不同（官方 <code>--mmap-experts --resident-cpu-experts</code>，我是 pinned arena）。</li>
</ol>
<p dir="auto"><strong>公道说一句</strong>：这个对比<strong>不是干净的对照</strong>。官方是单卡 + 开了表 + 完全不同的专家路径 + 一个核心数是我两倍的 CPU。所以「我反超了官方」只在 8.8K fresh prefill 这一格成立，别当普遍结论。</p>
<p dir="auto"><strong>decode 我略高的原因</strong>：24GB 单卡就能全量缓存最热专家（命中率 96.9~99.5%），加上投机解码接受率 70.6%，恰好把官方在更大上下文下的缓存优势抹平了。</p>
<hr />
<h2>9. 复现清单</h2>
<pre><code class="language-sh"># 1) 编译（HIP 后端，复用系统 ROCm 7）
./setup.sh --backend hip --family qwen --model IQ3_XXS \
  --gguf-dir /path/to/Qwen3.8-Flash-Next-AD-4.27bpw-Q4_K_M-M64 \
  --data-dir /path/to/Strata-data --context 32768 \
  --gpu 0 --build --no-start --yes

# 2) 单卡启动
run-iq3_xxs.sh
# 3) 双卡：setup 时用 --gpus 1,0（layer split 自动分配）

# 4) 标定本机 hipBLASLt 调优表（关键！）
cmake --build build-hip --target tune_hipblaslt
CASES=$(awk 'NR&gt;2 {printf " --case %s,%s,%s,%s,%s", $1, $5, $2, $3, $4}' \
        tools/hip/gfx1100-hipblaslt-100100.txt)
./build-hip/tune_hipblaslt $CASES --tuning-out tools/hip/gfx1100-hipblaslt-&lt;arch&gt;-&lt;version&gt;.txt
#    然后在 config 的 "env" 里加 STRATA_HIPBLASLT_TUNING 指向它

# 5) 压测（每档会 warmup 一次）
python3 tools/hip/bench_prefill.py --model MODEL_NAME --url http://127.0.0.1:8080 \
  --engine-log engine.log --label candidate --output candidate.json
</code></pre>
<p dir="auto"><strong>引擎关键参数</strong>：</p>
<pre><code>--expert-cache auto --prefill auto --spec 4 --spec-min-p 0.5 
--mtp .../mtp/rt --max-context 32768 --kv int8 --ple-gguf .../ple-q5_0.gguf
</code></pre>
<hr />
<h2>10. 结论</h2>
<ul>
<li><strong>单卡就够用</strong>：不跑长文档/代码的话，7900 XTX 单卡 + Strata 是能真正把 89GB MoE 跑起来、而且速度可用的方案（decode 63~66 tok/s 对本地大模型来说相当体面）。</li>
<li><strong>双卡要挑场景</strong>：长 prompt（RAG、代码库分析、长文档）收益显著（fresh prefill +15%，多轮追加延迟 −48%）；纯聊天生成没收益，还多占内存。</li>
<li><strong>务必自己标定 hipBLASLt 调优表</strong>：这是投入产出比最高的一步（+10%~41%），官方工具就在仓库里，几分钟的事。不做的代价是 prefill 直接少三分之一。</li>
<li><strong>大页别折腾</strong>：运行时开不起来，开机预留要拿 47 GiB 换，而且实测零收益。<strong>这条是省时间，不是省事。</strong></li>
<li><strong>写评测先 warmup</strong>：冷启动第一枪 decode 掉到 40 以下，不 warmup 的跑分会误伤一半结论。</li>
</ul>
<hr />
<p dir="auto"><em>数据来源：<code>bench-single.json</code> / <code>bench-dual-native.json</code> / <code>bench-dual.json</code> / <code>bench-dual-table.json</code> / <code>bench-dual-table-thp.json</code> 原始输出 + 引擎 v0.1.38 运行日志。每组配置独立重启引擎，每档 warmup 1 次 + 2 轮，同一台机器、同一份 prompt。</em></p>
]]></description><link>https://lcz.me/topic/2076</link><generator>RSS for Node</generator><lastBuildDate>Mon, 12 Oct 2026 15:39:13 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/2076.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 04 Oct 2026 04:22:56 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to 双 RX 7900 XTX 跑 88GB 的 MoE：Strata HIP 后端单卡/双卡实测 + 踩坑全记录 on Wed, 07 Oct 2026 05:04:28 GMT]]></title><description><![CDATA[<blockquote>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/terry" aria-label="Profile: terry">@<bdi>terry</bdi></a> <a href="/post/22716">said</a>:</p>
<p dir="auto">strata是什么就不要放进去了，这玩意论坛都跑烂了</p>
</blockquote>
<p dir="auto">NInfer都消失了 @@ <img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/1f633.png?v=fe25256ab4a" class="not-responsive emoji emoji-android emoji--flushed" style="height:1.4em;width:auto;vertical-align:middle" title=":flushed:" alt="😳" /></p>
<p dir="auto">看來Strata 還要熱好一陣子</p>
]]></description><link>https://lcz.me/post/23007</link><guid isPermaLink="true">https://lcz.me/post/23007</guid><dc:creator><![CDATA[kos or]]></dc:creator><pubDate>Wed, 07 Oct 2026 05:04:28 GMT</pubDate></item><item><title><![CDATA[Reply to 双 RX 7900 XTX 跑 88GB 的 MoE：Strata HIP 后端单卡/双卡实测 + 踩坑全记录 on Tue, 06 Oct 2026 02:25:40 GMT]]></title><description><![CDATA[<p dir="auto">以后总结，strata是什么就不要放进去了，这玩意论坛都跑烂了，结论可以放到前面。</p>
]]></description><link>https://lcz.me/post/22716</link><guid isPermaLink="true">https://lcz.me/post/22716</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Tue, 06 Oct 2026 02:25:40 GMT</pubDate></item></channel></rss>