<?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[[實測IV] Strata / Qwen3.8 Flash IQ2_XS 單卡跑到 424K 155t/s — parking 能留幾條對話：含三個不利發現]]></title><description><![CDATA[<p dir="auto">這篇是 2026-10-01/02 我跑完整個 campaign 的記錄，承接前三篇 <a href="https://lcz.me/topic/1228">1228</a>、<a href="https://lcz.me/topic/1462">1462</a>、<a href="https://lcz.me/topic/1967">1967</a>。</p>
<p dir="auto">問題一開始很簡單：兩張空閒的卡有沒有用。跑著跑著變成另一件事——單卡把 context 從 256K 推到 1M 時，KV pool、parking 和能同時保留的對話數量會撞到哪裡。</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/28901c04-f9ba-4cd0-9af9-038e9613ddef.png" alt="cover.png" class="img-markdown  img-fluid" /></p>
<blockquote>
<p dir="auto"><strong>先給結論</strong>：256K 上，本機 Strata 與 NInfer 在無投機口徑下基本打平。真正的差別在 parking（Strata 單卡獨有）、記憶體（61.4 GiB 是硬限制）和投機窗口（<code>--spec 4</code> 優於 <code>--spec 8</code>）。</p>
</blockquote>
<p dir="auto">Phase 1–5 的數字有 <code>summary.json</code>、<code>results.json</code>、<code>startup.txt</code> 可核對。Phase 6 是即時執行，數字來自引擎 log 原文，沒有 <a href="http://benchmark.py" rel="nofollow ugc">benchmark.py</a> 的 artifact，下面都標明。</p>
<hr />
<h2>0. 結論</h2>
<p dir="auto"><img src="https://upload.lcz.me/uploads/a5fdba97-c2ac-41df-b893-20676337094a.png" alt="chart0_conclusions.png" class="img-markdown  img-fluid" /></p>
<p dir="auto">圖裡的六格是可量化的結論：256K 的 prefill、256K 的 decode、各 context 的 parking 上限、兩個 instance 的 batch wall time、available RAM、WS private。下面六條是圖表達不了、但同樣屬於這篇的結論：</p>
<ul>
<li><strong>Remote expert cache 是錯誤用法</strong>。它只分配第一張卡還沒 claim 的 cold tail：一次 request 的 1,057 次 layer launch 裡 2,919 個 entry、28.5 MiB、等待 368 ms、GPU 使用率 0–12%。第一張卡已經持有約 99.4% 的 routed mass。</li>
<li><strong>KV offload 關不掉</strong>。<code>--kv-resident N</code> 的意義是「在 VRAM 保留 N 個 cell/QSA layer 的鏡像，其餘完整的 K/V 留在 pinned host RAM」。提高 N 不會縮小 pinned pool，只改變 VRAM mirror、streaming 命中率和 expert cache 大小。</li>
<li><strong>Parking 只支持單 GPU</strong>。<code>generate.cpp:1220-1223</code> 拒絕 <code>--layer-split</code>，所以 B3 的 4,993 tok/s 與 parking 互斥。圖第 3 格的全部數字都是單卡配置。</li>
<li><strong><code>--spec 8</code> 比 <code>--spec 4</code> 慢</strong>（§9）。每 round 多產出 token，但每秒少做 round，decode 淨輸 2–8%。引擎自己的 cost model 也算出 window 4 是 optimum。</li>
<li><strong>YaRN 延伸的 quality 我沒測</strong>。1.5–4.0× factor 沒有 needle 或 perplexity 測試。這篇的長 context 數字是速度與容量，不是 accuracy。</li>
<li><strong>跟 NInfer 比（同一張 5090，詳見 §8）</strong>：Strata 能在 32 GB 卡上跑 125B-A6B 到 256K，NInfer 不能（expert 文件 34 GB 超出 VRAM，且沒有 CPU expert tier）。用本機自己的記錄、口徑對齊後：無投機 decode 兩邊基本相同（Strata 在 64K/128K/256K 略勝）；真實 agent 流量 Strata 155.1 優於 NInfer MTP3 143.6、不及 DFlash2 183.4。NInfer 的優勢在小 prompt prefill、C=1–8 真 batching，和 DFlash2 這類 Strata 沒有的 drafter。</li>
</ul>
<p dir="auto"><strong>Standing config</strong>：424K + <code>--resident-experts</code> + parking 26,624 MiB / 4 slots / 1,024 MiB floor。3 條對話在滿格 context 下同時保留，prefill 是 256K 的 91–92%。</p>
<hr />
<h2>1. 環境與測法</h2>
<ul>
<li><strong>卡</strong>：RTX 5090 32,607 MiB（Gen5 x16，PCIe probe 51.9–52.4 GB/s，<code>pcie_frac 0.55</code>）、RTX 5080 16,303 MiB（<strong>Gen4 x4</strong>，probe 6.5 GB/s）、RTX 5060 Ti 16,311 MiB（Gen4 x4，6.5 GB/s）。</li>
<li><strong>CPU / 記憶體</strong>：Ryzen 9 9950X3D；<strong>2 × 32 GiB DDR5，實跑 6000 MT/s</strong>（G.Skill F5-6400J3239G32G，BIOS 報 <code>ConfiguredClockSpeed 6000</code>，Windows 可見 <strong>61.4 GiB</strong>）。沒有 ECC、沒有注冊記憶體——所有容量與帶寬的結論都受這 61.4 GiB 限制。</li>
<li><strong>SSD</strong>：模型 GGUF、pack 與 MTP draft layer 都在同一張 <strong>Samsung SSD 9100 PRO 4 TB NVMe（C:）</strong>，跟 DDR5 同一個消費級平台；另有一張 GIGABYTE 1 TB NVMe（F:，IQ3 用）和 SATA 860 EVO（D:）。專家權重以 mmap 讀入，路徑是 <strong>NVMe → OS file cache（同一组 DDR5）→ PCIe → VRAM</strong>，所以 SSD 這一層跟 <code>--resident-experts</code> 爭同一份 61.4 GiB。實測引擎 working set 約 37 GiB、系統 free RAM 只剩約 1.2 GiB——parking 的准入檢查用的就是這個 free 口徑。</li>
<li><strong>模型</strong>：<code>qwen3.8-flash-next-iq2_xs</code>（48 layers × 512 experts = 24,576 個 expert pair，native context 262,144）。12 層 QSA 持有 KV，36 層 GDN 持有 running state。</li>
<li><strong>系統</strong>：Windows，engine <strong>0.1.31</strong>，port 18081。</li>
</ul>
<p dir="auto">測法：</p>
<ul>
<li>Phase 1–5：未修改的 <code>bench/results/2026-09-30-community-rtx-5090/benchmark.py</code>。每次執行用新的 nonce prompt（跨執行不重用）、greedy、256 token 輸出上限、streaming、<code>--targets 4096,32768,128000,256000 --runs 3</code>。TTFT 與 decode 速率取自引擎 <code>/metrics</code> 的 per-request 記錄，RAM 用 Windows counter。Run-to-run 離散約 5%（256K）、15%（4K）。</li>
<li>Phase 6：固定 filler prompt（12 個單字循環，實測 <strong>4.562 chars/token</strong>），每條對話用獨立 seed，一次輸入至接近 context 上限，<code>max_tokens 400</code>。TTFT 由 client 的第一個 delta 計算，parking 事件讀引擎 log 原文，RAM 用 <code>Win32_OperatingSystem.FreePhysicalMemory</code>——就是引擎准入檢查所用的同一個「free」口徑。</li>
</ul>
<hr />
<h2>2. Phase 1–3：多卡</h2>
<blockquote>
<p dir="auto">每加一張卡便损失 decode：136.7 → 120.7 → 98.9。256K 的 prefill 只有 B3 贏（4,993 對 4,079），但 B3 跟 parking 互斥。</p>
</blockquote>
<p dir="auto">Configs（可與 <code>summary.json</code> 核對）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>#</th>
<th>config</th>
<th style="text-align:right">VRAM 中的 experts</th>
<th>备注</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td><code>"gpu": 0</code></td>
<td style="text-align:right">16,640（68%）</td>
<td>只有 5090，48 層</td>
</tr>
<tr>
<td>B</td>
<td><code>"gpu": [0,1]</code>，<code>--layer-split auto</code></td>
<td style="text-align:right">18,139</td>
<td>auto 選了 <strong>K=47</strong>（5080 只得 1 層、0.72 GiB）</td>
</tr>
<tr>
<td>B2</td>
<td><code>"gpu": [0,1]</code>，<code>--layer-split ""</code>，<code>--expert-cache-device1 7000</code></td>
<td style="text-align:right">23,920（97.3%）</td>
<td>5080 作為纯 remote cache</td>
</tr>
<tr>
<td>B3</td>
<td><code>"gpu": [0,1]</code>，<code>--layer-split 36</code></td>
<td style="text-align:right">24,208（98.5%）</td>
<td>5090 為 0–35、5080 為 36–47（6,144 slots / 8.48 GiB）</td>
</tr>
<tr>
<td>C</td>
<td><code>"gpu": [0,1,2]</code>，<code>--layer-split 28,42</code></td>
<td style="text-align:right">24,576（100%）</td>
<td>5090 為 0–27、5080 為 28–41、5060 Ti 為 42–47</td>
</tr>
</tbody>
</table>
<p dir="auto">Decode tok/s（3 次的中位數）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>prompt</th>
<th style="text-align:right">A 5090</th>
<th style="text-align:right">B auto K=47</th>
<th style="text-align:right">B2 remote 7000</th>
<th style="text-align:right">B3 K=36</th>
<th style="text-align:right">C 3-GPU</th>
</tr>
</thead>
<tbody>
<tr>
<td>4,096</td>
<td style="text-align:right">144.8</td>
<td style="text-align:right">—</td>
<td style="text-align:right">141.5</td>
<td style="text-align:right">160.9</td>
<td style="text-align:right">129.7</td>
</tr>
<tr>
<td>32,768</td>
<td style="text-align:right">165.5</td>
<td style="text-align:right">—</td>
<td style="text-align:right">156.6</td>
<td style="text-align:right">157.0</td>
<td style="text-align:right">123.8</td>
</tr>
<tr>
<td>128,000</td>
<td style="text-align:right">153.7</td>
<td style="text-align:right">—</td>
<td style="text-align:right">143.2</td>
<td style="text-align:right">142.2</td>
<td style="text-align:right">108.3</td>
</tr>
<tr>
<td>256,000</td>
<td style="text-align:right"><strong>136.7</strong></td>
<td style="text-align:right">—</td>
<td style="text-align:right">—</td>
<td style="text-align:right">120.7</td>
<td style="text-align:right">98.9</td>
</tr>
<tr>
<td>~31,000（probe）</td>
<td style="text-align:right">173.7*</td>
<td style="text-align:right">125.0</td>
<td style="text-align:right">113.7</td>
<td style="text-align:right">183.1</td>
<td style="text-align:right">—</td>
</tr>
</tbody>
</table>
<p dir="auto">* 第一輪 A（<code>2026-10-01-5090-only</code>）在 4K/32K/128K 是 170.3 / 173.7 / 153.7；同一方法重跑（<code>-4targets</code>）是 144.8 / 165.5 / 153.7。4K 的離散約 15%，所以單次差異小於 10% 沒有統計意義。</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/49baca37-1d6e-40ef-bdb9-d0c22c5ce0a4.png" alt="chart2_decode_by_config.png" class="img-markdown  img-fluid" /></p>
<p dir="auto">Prefill tok/s / TTFT：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>prompt</th>
<th style="text-align:right">A 5090</th>
<th style="text-align:right">B3 K=36</th>
<th style="text-align:right">C 3-GPU</th>
</tr>
</thead>
<tbody>
<tr>
<td>4,096</td>
<td style="text-align:right">2,857 / 1.5 s</td>
<td style="text-align:right">1,893 / 2.2 s</td>
<td style="text-align:right">1,278 / 3.2 s</td>
</tr>
<tr>
<td>32,768</td>
<td style="text-align:right">4,187 / 7.9 s</td>
<td style="text-align:right">4,136 / 8.0 s</td>
<td style="text-align:right">2,298 / 14.3 s</td>
</tr>
<tr>
<td>128,000</td>
<td style="text-align:right">4,257 / 30.3 s</td>
<td style="text-align:right"><strong>5,017 / 25.7 s</strong></td>
<td style="text-align:right">2,886 / 44.5 s</td>
</tr>
<tr>
<td>256,000</td>
<td style="text-align:right">4,079 / 63.2 s</td>
<td style="text-align:right"><strong>4,993 / 51.7 s</strong></td>
<td style="text-align:right">2,773 / 92.8 s</td>
</tr>
</tbody>
</table>
<p dir="auto">我看到的東西：</p>
<ol>
<li><strong>256K 以下，prompt-heavy 工作的最佳配置是 B3</strong>。256K prompt 加 1–8K 輸出時整体較快；但 pure long-decode 仍然以單 5090 為佳。</li>
<li><strong>每加一個 stage 便损失 decode</strong>：136.7 → 120.7 → 98.9。第三張卡雖然持有 100% 的 experts，卻是全部分段最差。</li>
<li><strong>Remote cache 是第二張卡的錯誤用法</strong>（<code>remote_experts.cpp:140-148</code>：只分配第一張卡尚未 claim 的 pairs）——1,057 次 layer launch 裡 2,919 個 entry、28.5 MiB（unpacked 388.3 MiB）、<strong>等待 368 ms</strong>、GPU 使用率 0–12%。第一張卡已經持有熱的 68%（約 99.4% 的 routed mass）。</li>
<li><strong>手动 split 才真正用到第二張卡</strong>。K=36 時 5080 擁有 12 層、cache 其全部 6,144 個 pairs，request 期間 GPU 使用率 38–99%，24,208/24,576（98.5%）的 experts 在 VRAM。較窄的 split 較差：auto 按预測的 window 時間選了 K=47，讓 5080 有 9.87 GiB 閒置。</li>
<li><strong>代价是 x4 PCIe link 和每個 verify window 一次 hand-off</strong>。兩張 helper 卡 probe 為 6.5 GB/s；三個 stage 增加第二次 hand-off，所以 32K prefill 從 4,136 掉到 2,298 tok/s。</li>
<li><strong>CPU 是設計上必須工作，不是 cache miss</strong>。engine 的 idle CPU 是 0%，但 256K request 期間 <code>strata.exe</code> 是 950–1,040%（約 10 個核心）——QSA/GDN/rope 的 host-side path，除非啟用 <code>--native-qsa</code>、<code>--native-gdn</code>、<code>--native-rope</code>。decode 期間的 expert hit rate 測得 99.9%。</li>
<li><strong>RAM 是 256K 的真正上限</strong>。3-GPU 的 256K 執行用掉 58.9 / 61.4 GB（96%）。</li>
<li><strong>Warm-up 要算進去</strong>。啟动後第一條 request 較慢（B3 的 4K prefill 在 ladder 裡是 1,893，後续 probe 是 3,155）。</li>
</ol>
<hr />
<h2>3. Phase 4：記憶體與速度 flags（同一台機器、同一條 256K request，以 B3 為主）</h2>
<blockquote>
<p dir="auto"><code>--mmap-experts</code> 在速度上是免費的，而且把 25.6 GiB 的 locked arena 換成可被 OS 回收的 file-backed pages。</p>
</blockquote>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>variant</th>
<th style="text-align:right">prefill tok/s</th>
<th style="text-align:right">decode tok/s</th>
<th style="text-align:right">TTFT</th>
<th style="text-align:right">available RAM</th>
<th style="text-align:right">strata WS</th>
<th style="text-align:right">WS private</th>
</tr>
</thead>
<tbody>
<tr>
<td>B3（resident arena，int8 KV）</td>
<td style="text-align:right">4,945</td>
<td style="text-align:right">114.8</td>
<td style="text-align:right">52.2 s</td>
<td style="text-align:right">3.0–3.4 GB</td>
<td style="text-align:right">37.4 GB</td>
<td style="text-align:right">~37 GB</td>
</tr>
<tr>
<td>B3 + <code>--kv q4_0</code></td>
<td style="text-align:right">4,047</td>
<td style="text-align:right">115.6</td>
<td style="text-align:right">63.6 s</td>
<td style="text-align:right">5.1–5.4 GB</td>
<td style="text-align:right">40.0 GB</td>
<td style="text-align:right">39.9 GB</td>
</tr>
<tr>
<td>B3 + <code>--mmap-experts</code></td>
<td style="text-align:right">4,850</td>
<td style="text-align:right">119.4</td>
<td style="text-align:right">53.2 s</td>
<td style="text-align:right">3.2–3.6 GB</td>
<td style="text-align:right">42.1 GB</td>
<td style="text-align:right"><strong>8.0–8.2 GB</strong></td>
</tr>
<tr>
<td>A 5090 only + <code>--resident-experts</code></td>
<td style="text-align:right">3,929</td>
<td style="text-align:right">116.3</td>
<td style="text-align:right">65.6 s</td>
<td style="text-align:right"><strong>23.0 GB</strong></td>
<td style="text-align:right"><strong>17.8 GB</strong></td>
<td style="text-align:right">15.2 GB</td>
</tr>
<tr>
<td>A 5090 only，resident arena（control）</td>
<td style="text-align:right">4,079</td>
<td style="text-align:right">136.7</td>
<td style="text-align:right">63.2 s</td>
<td style="text-align:right">未取樣</td>
<td style="text-align:right">—</td>
<td style="text-align:right">—</td>
</tr>
</tbody>
</table>
<p dir="auto">三件事值得講：</p>
<ul>
<li><code>--mmap-experts</code> 速度不變，但 lock 消失了：25,626 MiB 的 <code>VirtualLock</code> arena 變成 file-backed pages（clean、可被 OS 回收）。Windows 的「available」counter 仍然偏低，因為 mapped GGUF pages 仍 resident，但它们跟 locked arena 不是一回事。</li>
<li><code>--resident-experts</code> = <code>--mmap-experts --resident-cpu-experts</code> + <code>resident_pin</code> + <code>resident_soft</code> + <code>resident_headroom = 4 GiB</code>（<code>generate.cpp:1177-1187</code>）。環境變量可覆盖：<code>STRATA_RESIDENT_PIN=0</code>、<code>STRATA_RESIDENT_HEADROOM_GIB=N</code>。<code>--resident-cpu-experts</code> 要求 <code>--mmap-experts</code> 與 static <code>--expert-profile</code>，並且<strong>拒絕 layer split 與 remote cache</strong>（<code>1279-1288</code>）。</li>
<li><code>--shared-expert-arena</code> 是 Linux-only，這裡用不了。</li>
</ul>
<p dir="auto">順帶一條：這就是為什麼 §1 說 SSD 那一層跟 <code>--resident-experts</code> 爭同一份 RAM。26.6 GiB 的 parking 预算把可用 RAM 壓到 13.58 GiB，减去 4 GiB headroom 只剩 9.58 GiB，而 resident complement 需要 10.53 GiB——所以引擎報 warning、fallback 到 mmap。兩個 arm 都在這個條件下跑，所以 §9 的 A/B 仍然成立。</p>
<hr />
<h2>4. Phase 5：兩個獨立 instance（真正的 C=2）——兩次都不可行</h2>
<blockquote>
<p dir="auto">平行效率 0.33×（C:）和 0.17×（F:）。瓶颈是 VRAM，不是磁盤帶寬。</p>
</blockquote>
<p dir="auto">Instance 1（5090，port 18081，<code>--resident-experts</code>，16,920 slots / 23.2 GiB，15 pool workers）跟 instance 2（5080，port 18082，<code>--mmap-experts</code>，6,503 slots / 8.71 GiB = 26.5%，8 pool workers，無 vision），兩者 context 都是 262,144。Workload：一條 23,523-token prompt、greedy、128 輸出 token、streaming。</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>lane</th>
<th style="text-align:right">TTFT</th>
<th style="text-align:right">total</th>
<th style="text-align:right">decode</th>
<th style="text-align:right">expert hit</th>
<th>VRAM</th>
</tr>
</thead>
<tbody>
<tr>
<td>5090（18081）</td>
<td style="text-align:right">7.00 s</td>
<td style="text-align:right">8.42 s</td>
<td style="text-align:right">~90 tok/s</td>
<td style="text-align:right">94.3%</td>
<td>31.1 GB used</td>
</tr>
<tr>
<td>5080（18082，C:）</td>
<td style="text-align:right">48.55 s</td>
<td style="text-align:right">53.10 s</td>
<td style="text-align:right">~28 tok/s</td>
<td style="text-align:right">56.9%</td>
<td>14.8 GB used，445 MiB free</td>
</tr>
</tbody>
</table>
<p dir="auto">兩條 request 的 batch：在 5090 排隊是 14.27 s，兩條 lane 平行是 42.62 s → <strong>0.33×</strong>。</p>
<p dir="auto">第二次我把 pack、兩個 GGUF shard 與 MTP head（72.1 GB、74 個文件）用 robocopy 複制到空閒的 F: NVMe（GIGABYTE GP-ASM2NE6100TTTD，Gen4，397 GB free），耗時 18 s（<strong>4.2 GB/s</strong>），instance 2 改讀 F:，flags 跟先前相同（<code>--mmap-experts</code>、6,503 slots、262K context）。測試結束後那份複制已删除，F: 目前不含任何 Strata 文件。</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>lane</th>
<th style="text-align:right">TTFT</th>
<th style="text-align:right">total</th>
<th style="text-align:right">engine prefill</th>
<th style="text-align:right">engine decode</th>
</tr>
</thead>
<tbody>
<tr>
<td>5090（C:，<code>--resident-experts</code>）</td>
<td style="text-align:right">8.61 s</td>
<td style="text-align:right">9.36 s</td>
<td style="text-align:right">2,799 tok/s</td>
<td style="text-align:right">162.3 tok/s</td>
</tr>
<tr>
<td>5080（F:，<code>--mmap-experts</code>）</td>
<td style="text-align:right"><strong>72.56 s</strong></td>
<td style="text-align:right"><strong>77.27 s</strong></td>
<td style="text-align:right"><strong>325 tok/s</strong></td>
<td style="text-align:right"><strong>26.9 tok/s</strong></td>
</tr>
</tbody>
</table>
<p dir="auto">兩條 request 的 batch：排隊 12.86 s，平行 73.55 s → <strong>0.17×</strong>。先前 <img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/1f604.png?v=fe25256ab4a" class="not-responsive emoji emoji-android emoji--smile" style="height:1.4em;width:auto;vertical-align:middle" title="C:" alt="😄" /> 版本（0.33×）之所以較快，只因為 <img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/1f604.png?v=fe25256ab4a" class="not-responsive emoji emoji-android emoji--smile" style="height:1.4em;width:auto;vertical-align:middle" title="C:" alt="😄" /> 已有 26.4 GB 的 warm standby cache，而 F: 從冷狀態開始。</p>
<ul>
<li>2 秒取樣：C: 讀取 0–26 MB/s（<strong>完全沒有 contention</strong>），F: 讀取 0.8–1.3 GB/s、約 70% disk time → <strong>磁盤帶寬不是瓶颈</strong>。</li>
<li>Available RAM 從 10.9 GB 掉到 0.31 GB 並維持：file-backed pages 消耗 RAM 的方式跟 <img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/1f604.png?v=fe25256ab4a" class="not-responsive emoji emoji-android emoji--smile" style="height:1.4em;width:auto;vertical-align:middle" title="C:" alt="😄" /> 相同。</li>
<li>Per-token cost：5080 lane 是 3.01 ms/token prefill、19.75 ms/token decode；5090 lane 是 0.25 與 4.07 ms/token。</li>
<li>結論：第二條 lane 由 <strong>VRAM</strong> 決定。16 GB 卡需要約 7.9 GB 用於非 expert 部分，剩下 8.71 GiB 只能容納 24,576 個 expert pair 中的 26.5%；其餘 73.5% 走 mmap + CPU pool，即使 page cache 已 warm 仍需約 20 ms/token（引擎自身把 warm mmap 估為 34.78 ms/token）。第二條 262K lane 要快，必須用能容納 experts 的卡（也就是另一張 32 GB 級卡），或者用較小的模型。把文件搬到第二個 NVMe 不改變結果。</li>
</ul>
<hr />
<h2>5. Phase 6：KV pool、parking 與 context ladder</h2>
<blockquote>
<p dir="auto">能同時保留的對話：256K 4 條、384K 3 條、424K 3 條、448K 2 條、512K 以上 0 條。checkpoint 約 118 MB 跟 context 長度無關，真正的成本是 positional KV，約 17–19 KB/token。</p>
</blockquote>
<h3>5.1 Parking 的記憶體模型</h3>
<p dir="auto"><code>SavedConversation</code> 複制 <code>ConversationKv</code>（k、v、k_scale、v_scale、pooled rows；<code>bytes()</code> 用 <code>.capacity()</code>）與 <code>ConversationCheckpoint</code>（gdn、ple、tails、dead、block_pos）：</p>
<ul>
<li><strong>checkpoint（running state）約 118 MB，跟 context 長度無關</strong>（<code>generate.cpp:804-815</code>）：36 個 GDN recurrence、conv history、per-QSA indexer tail 與 PLE history。Positional KV 不由 checkpoint 複制，它被 rewind。</li>
<li><strong>真正的 parking 成本是 positional KV，約 17–19 KB/token</strong>（int8、12 個 QSA layer）。</li>
<li>准入规则（<code>generate.cpp:4009</code>）：只有 <code>needed + --conversation-cache-min-free-mib &lt;= physically free RAM</code> 才 park。「physically free」<strong>不含</strong> Windows standby 與 file cache。</li>
<li><strong>Parking 只支持單 GPU</strong>：<code>generate.cpp:1220-1223</code> 拒絕 <code>--layer-split</code>（"conversation parking does not yet support --layer-split"）。所以 B3 的 4,993 tok/s 與 parking 互斥。</li>
</ul>
<p dir="auto"><img src="https://upload.lcz.me/uploads/8b21ba37-f494-47e5-ac59-dcb34f14a1cd.png" alt="diagram_memory.png" class="img-markdown  img-fluid" /></p>
<h3>5.2 Context ladder（全部實測；parking budget 26,624 MiB / 4 slots / floor 1,024 MiB，256K 使用 18,432）</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>context</th>
<th style="text-align:right">YaRN factor</th>
<th style="text-align:right">KV pool（pinned RAM）</th>
<th style="text-align:right">expert cache</th>
<th>resident arena</th>
<th style="text-align:right">cold prefill</th>
<th style="text-align:right">相對 256K</th>
<th style="text-align:right">park/條</th>
<th style="text-align:right">同時 parked</th>
</tr>
</thead>
<tbody>
<tr>
<td>256K</td>
<td style="text-align:right">1.0</td>
<td style="text-align:right">2.32 GiB</td>
<td style="text-align:right">16,982 / 22.77 GiB</td>
<td>通過，13.10 GiB</td>
<td style="text-align:right">4,431</td>
<td style="text-align:right">100%</td>
<td style="text-align:right">4.20 GiB @241K</td>
<td style="text-align:right"><strong>4</strong></td>
</tr>
<tr>
<td>384K</td>
<td style="text-align:right">1.5</td>
<td style="text-align:right">4.64 GiB</td>
<td style="text-align:right">16,815 / 22.56</td>
<td>通過，11.56</td>
<td style="text-align:right">4,079–4,173</td>
<td style="text-align:right">92–94%</td>
<td style="text-align:right">6.19 GiB @380K</td>
<td style="text-align:right"><strong>3</strong></td>
</tr>
<tr>
<td><strong>424K</strong></td>
<td style="text-align:right"><strong>1.65625</strong></td>
<td style="text-align:right"><strong>5.12 GiB</strong></td>
<td style="text-align:right"><strong>16,767 / 22.49</strong></td>
<td>通過，11.52</td>
<td style="text-align:right"><strong>4,010–4,083</strong></td>
<td style="text-align:right"><strong>91–92%</strong></td>
<td style="text-align:right"><strong>6.71 GiB @417K</strong></td>
<td style="text-align:right"><strong>3</strong></td>
</tr>
<tr>
<td>432K</td>
<td style="text-align:right">1.6875</td>
<td style="text-align:right">5.22 GiB</td>
<td style="text-align:right">16,757 / 22.47</td>
<td>通過，11.23</td>
<td style="text-align:right">3,966–4,081</td>
<td style="text-align:right">90–92%</td>
<td style="text-align:right">6.82 GiB @425K</td>
<td style="text-align:right">3，但需要 floor 512</td>
</tr>
<tr>
<td>448K</td>
<td style="text-align:right">1.75</td>
<td style="text-align:right">5.41 GiB</td>
<td style="text-align:right">16,738 / 22.45</td>
<td>通過，11.13</td>
<td style="text-align:right">3,946–4,024</td>
<td style="text-align:right">89–91%</td>
<td style="text-align:right">7.04 GiB @440K</td>
<td style="text-align:right"><strong>2</strong></td>
</tr>
<tr>
<td>512K</td>
<td style="text-align:right">2.0</td>
<td style="text-align:right">6.19 GiB</td>
<td style="text-align:right">16,652 / 22.33</td>
<td><strong>差 290 MiB 不通過</strong></td>
<td style="text-align:right">3,516–3,693</td>
<td style="text-align:right">79–83%</td>
<td style="text-align:right">需要 8,079 MiB</td>
<td style="text-align:right"><strong>0</strong>（被拒）</td>
</tr>
<tr>
<td>1M</td>
<td style="text-align:right">4.0</td>
<td style="text-align:right">12.38 GiB</td>
<td style="text-align:right">13,965 / 18.71</td>
<td>不通過</td>
<td style="text-align:right">2,578–2,724</td>
<td style="text-align:right">58–61%</td>
<td style="text-align:right">需要 15,781 MiB</td>
<td style="text-align:right"><strong>0</strong>（被拒）</td>
</tr>
</tbody>
</table>
<ul>
<li><strong>Pool 由 boot 時可用的 RAM 決定，不由 context 固定</strong>。同一個 256K 與 <code>--kv-resident 32768</code>，三次 boot 報 2.32 GiB，另一次報 3.09 GiB。從 384K 往上是線性（4.64 → 5.12 → 5.22 → 5.41 → 6.19 → 12.38）。</li>
<li><strong>Arena 與 parking 爭用同一份 RAM</strong>。512K 的 log 是 <code>resident complement 10.69 GiB exceeds available RAM (14.40 GiB) minus the 4 GiB safety headroom</code>，所以不通過、fallback 到 mmap、page cache 消耗 RAM，parking 被拒。1M 是 <code>14.31 GiB exceeds available RAM (10.33 GiB) minus the 4 GiB headroom</code>。</li>
<li><strong>1M 有兩個 variant，兩者都不可行</strong>：<code>--kv-resident 32768</code>（cache 15,974 / 21.44 GiB，arena 不通過：11.58 GiB 對 7.56 − 4.00）與 <code>--kv-resident 262144</code>（cache 13,965 / 18.71 GiB，arena 不通過：14.31 對 10.33 − 4.00）。上表的 1M 列用第二個 variant。512K 也測過 <code>--kv-resident 262144</code>，pool 仍是 6.19 GiB。</li>
</ul>
<p dir="auto"><img src="https://upload.lcz.me/uploads/a3e43c37-03a4-4a17-a401-0e5794c0e133.png" alt="diagram_parking.png" class="img-markdown  img-fluid" /></p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/863e2f65-c87e-470d-8259-bbdf0ba39cfa.png" alt="chart1_context_ladder.png" class="img-markdown  img-fluid" /></p>
<h3>5.3 各 context 的 log 原文</h3>
<ul>
<li><strong>256K（4 條 × 241K）</strong>：<code>parked 241123 tokens ... parked=3 bytes=13536720828 evictions=0</code>，四條全部命中，<code>restored 241112 tokens (checkpoint) in 341.7 ms</code>。</li>
<li><strong>384K（3 條 × 380K）</strong>：<code>parked=3 bytes=19918823816 evictions=0</code>；第 4 條被拒：<code>skip parking (need 6332 MiB plus 1024 MiB floor)</code>，當時 free 是 4,289 MiB（差 3,067 MiB）。重访是 2.38 / 1.90 / 2.15 s 命中，第 4 條 MISS（91.4 s 重新 prefill）。</li>
<li><strong>424K（3 條 × 417K，默認 floor 1,024 MiB）</strong>：沒有 skip 記錄；<code>parked 417308 tokens ... bytes=7205814172</code>、<code>restored 416901 tokens (checkpoint) ... parked=2 bytes=20781436496</code>（live 6.36 GB + 2 × 7.21 GB，即 3 條在 pool 中）。重访是 4.63 / 2.24 / 2.38 s 命中；decode 是 174.8 / 196.9 / 196.0 tok/s（accepted 299–300 / 400）。</li>
<li><strong>432K（3 條 × 425K）</strong>：floor 1,024 MiB 時第 3 條被拒：<code>need 6986 MiB plus 1024 MiB floor</code>，free 是 7,727 MiB（<strong>差 283 MiB</strong>）。改成 floor 512 MiB 後，同一组對話 3 條全部 park，重访是 4.72 / 2.19 / 2.30 s 命中，結束時 free 是 1,774 MiB。</li>
<li><strong>448K（2 條 × 440K）</strong>：<code>bytes=7557571128</code>（每條 7.04 GiB）、evictions=0、重访 4.68 / 2.56 s 命中；第 3 條需要 8.0 GB，而 free 只有 7.8 GB。</li>
<li><strong>512K / 1M</strong>：parking 被拒（<code>need 8079 MiB plus 1024 MiB floor</code>、<code>need 15781 MiB plus 1024 MiB floor</code>）。同一條對話的連续 turn 仍可通過 live checkpoint chain 重用（512K：TTFT 1.41 s、prefill 55 ms），但<strong>換對話便要重新 prefill</strong>（512K 的 A/B 交錯 → MISS、137 s；1M 命中 107.8 tok/s、cold 61.7 tok/s）。</li>
</ul>
<hr />
<h2>6. 三個不利但重要的發現</h2>
<blockquote>
<p dir="auto">縮短對話換不到第 4 個 slot；424K × 3 耗尽 headroom；slots 與 bytes 是兩件事。</p>
</blockquote>
<p dir="auto"><strong>1. 縮短對話無法換取第 4 個 slot。</strong></p>
<p dir="auto">380K、340K、330K 三次測試，3 條 park 完成後的 free RAM 都約 5.6 GB（4,289 / 5,585 / 5,615 MiB），第 4 條每次都差 1.0–3.0 GiB。省下來的 RAM 進入 file cache，而准入檢查只計 physically free RAM。要保留 4 條必須實際增加 RAM，或者接受 floor 接近 0（也就是沒有安全邊際）。</p>
<p dir="auto"><img src="https://upload.lcz.me/uploads/be662f74-2916-4697-bbe8-4ddd944a6b0c.png" alt="chart3_ram_headroom_384k.png" class="img-markdown  img-fluid" /></p>
<p dir="auto"><strong>2. 424K × 3 會耗尽 headroom。</strong></p>
<p dir="auto">3 條 park 後 free 只剩 2.5 GB。當同時存在另一條 live 對話（真實 agent 流量，prompt 83–90K、hit rate 98%）時，RAM 達到 <strong>54.6 / 61.4 GiB</strong>，restore 從 1.4 s 變成 <strong>25.9–27.0 s</strong>（<code>restored 416901 tokens (checkpoint) in 25918.3 ms</code>）。</p>
<blockquote>
<p dir="auto">「可保留 3 條」和「hit path 仍然快」是兩件事。</p>
</blockquote>
<p dir="auto">機制尚未證明（最可能是 parked blob 需經 page cache），但觀察是實測。</p>
<p dir="auto"><strong>3. Slots 與 bytes 是兩件事。</strong></p>
<p dir="auto">上面的上限指「每條對話接近完整 context」。同一個 424K config 在真實 agent 流量下，4 條 118–138K token 的對話可同時 parked（<code>parked=4 bytes=20315885712</code>、<code>evictions=0</code>），第 5 條才觸發一次 eviction（<code>evictions=1</code>）。所以「424K 可保留 3 條」指 3 條接近滿滿；如果每條約 130K，4 個 slot 仍可使用。</p>
<hr />
<h2>7. 配置建議（整個 campaign）</h2>
<blockquote>
<p dir="auto">要 4 條就留在 256K；要 3 條就 424K。prefill 為主且不需要 parking 才用 B3。</p>
</blockquote>
<ul>
<li><strong>長 context 且同時保留 3 條對話</strong>：424K（<code>--max-context 434176 --rope-scaling yarn --rope-scale 1.65625</code>）加 <code>--conversation-cache-mib 26624 --conversation-cache-slots 4 --conversation-cache-min-free-mib 1024</code>。這是目前的 standing config。</li>
<li><strong>需要 4 條</strong>：維持 256K（每條 4.20 GiB，mib ≥ 18,432）。</li>
<li><strong>需要 432K 以上</strong>：432K 需要 floor 512；448K 只能 2 條；512K 需要 96 GB RAM 才有 headroom。</li>
<li><strong>如果 prefill 是主要工作</strong>（單次 256K prompt、不需要 parking）：B3 <code>--layer-split 36</code>，4,993 tok/s / TTFT 51.7 s。但它與 parking 互斥。</li>
<li><strong>投機窗口</strong>：<code>--spec 4</code>（§9）。<code>--spec 8</code> 沒有數據支持。</li>
<li><strong>RAM budget</strong>：兩條 262K instance 約需 57 GB → 64 GB 是 practical floor，96 GB 較充裕，128 GB 有餘裕。</li>
</ul>
<hr />
<h2>8. Strata 對 NInfer（同一台機器，全部用本機實測過的數字）</h2>
<p dir="auto"><img src="https://upload.lcz.me/uploads/e50d6a65-c6ae-4808-ad5a-24ed77e0d6b7.png" alt="chart4_ninfer_compare.png" class="img-markdown  img-fluid" /></p>
<blockquote>
<p dir="auto">這一節第一版我寫錯了兩次：用了官方表，又把 Strata 含投機的 decode 直接對 NInfer 的 MTP0 列。下面全部改用本機自己的記錄——前三篇 <a href="https://lcz.me/topic/1228">1228</a>、<a href="https://lcz.me/topic/1462">1462</a>、<a href="https://lcz.me/topic/1967">1967</a> 和本地 campaign 記錄（<code>out/campaign_0902_mirror/</code>、<code>out/dflash3/campaign/</code>、<code>out/dflash3/campaign_v4/</code>），並且把投機與否分開算。</p>
</blockquote>
<h3>8.1 真實 agent 流量（同一台機器、同一類工作、兩邊都開投機）</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th></th>
<th>NInfer MTP3 era</th>
<th>NInfer DFlash2 K=7 era</th>
<th>Strata <code>--spec 4</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>期間 / 樣本</td>
<td>09-04 → 09-07，12,479 req</td>
<td>09-07 → 09-08，5,879 req</td>
<td>10-01 → 10-02，282 個 agent request（prompt ≥30K）</td>
</tr>
<tr>
<td>prompt 中位</td>
<td>72,062</td>
<td>72,492</td>
<td>167,244</td>
</tr>
<tr>
<td>cache 命中</td>
<td>79.8%（加權）/ 97–99%（per req）</td>
<td>82.3% / 97–99%</td>
<td>98.9%（per req）</td>
</tr>
<tr>
<td><strong>decode 中位</strong></td>
<td><strong>143.6</strong></td>
<td><strong>183.4</strong></td>
<td><strong>155.1</strong></td>
</tr>
<tr>
<td>decode p95 / max</td>
<td>192.1 / 342.9</td>
<td>282 / 436.9</td>
<td>191.9 / 216.7</td>
</tr>
<tr>
<td>acceptance（加權）</td>
<td>60.7%</td>
<td>33.0%</td>
<td>77.5%</td>
</tr>
<tr>
<td>tokens/round</td>
<td>2.82</td>
<td>3.31</td>
<td>3.07</td>
</tr>
<tr>
<td>並發</td>
<td>C=3（真 batching）</td>
<td>C=3</td>
<td>C=1（一次一個 request）</td>
</tr>
</tbody>
</table>
<p dir="auto">口徑相同時 Strata 155.1 介於 NInfer 兩代之間：優於 MTP3（+8.0%），不及 DFlash2（−15.4%）。</p>
<blockquote>
<p dir="auto">但 NInfer 那兩栏是 C=3 真 batching，Strata 是單 request 一條 lane。所以這裡比的是單條 lane 的 per-request 速度，不是吞吐。</p>
</blockquote>
<p dir="auto">另外 Strata 的 prompt 中位數（167K）比 NInfer（72K）大得多，樣本也小得多（282 對 12,479）。這一點我要講清楚，不然數字會誤導。</p>
<h3>8.2 無投機口徑（prompt 長度對齊）</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>prompt</th>
<th style="text-align:right">Strata（無投機等价，下限）</th>
<th style="text-align:right">NInfer MTP0（09-02 本地 run）</th>
</tr>
</thead>
<tbody>
<tr>
<td>8K</td>
<td style="text-align:right">61.1</td>
<td style="text-align:right">69.3</td>
</tr>
<tr>
<td>64K</td>
<td style="text-align:right">69.8</td>
<td style="text-align:right">63.7</td>
</tr>
<tr>
<td>128K</td>
<td style="text-align:right">62.0</td>
<td style="text-align:right">58.5</td>
</tr>
<tr>
<td>256K</td>
<td style="text-align:right">55.5</td>
<td style="text-align:right">50.3</td>
</tr>
</tbody>
</table>
<p dir="auto">Strata 那一列不是我直接量的。引擎在 native (IQ) pack 上拒絕 <code>--spec &lt; 2</code>（<code>generate.cpp:1738-1743</code>、<code>generate.cpp:3611</code>），所以 Strata 沒有真正的 MTP0 數字。它由 log 中每個 request 的投機統計推算：rounds = 生成 token − 被接受 draft，round rate = rounds ÷ decode 時間。因為 verify window 比單 token 前推更贵（<code>suffix_drafter_test.cpp:3</code>：每 token 約多 10 ms），這個數是下限。</p>
<blockquote>
<p dir="auto">口徑對齊後兩邊基本相同，Strata 在 64K/128K/256K 略勝。原本「NInfer decode 快 1.6 倍」是口徑不對齊造成的。</p>
</blockquote>
<h3>8.3 Prefill（不受投機影響）</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>prompt</th>
<th style="text-align:right">Strata</th>
<th style="text-align:right">NInfer（post 1462 solo prefill，本機）</th>
<th style="text-align:right">NInfer（09-02 本地 MTP0 run）</th>
</tr>
</thead>
<tbody>
<tr>
<td>4K / 8K</td>
<td style="text-align:right">2,857（4,096）</td>
<td style="text-align:right">—</td>
<td style="text-align:right">8,621（7,680）</td>
</tr>
<tr>
<td>32K / 47K</td>
<td style="text-align:right">4,187（32,768）</td>
<td style="text-align:right">6,004（47k）</td>
<td style="text-align:right">5,316（64,512）</td>
</tr>
<tr>
<td>105K / 128K</td>
<td style="text-align:right">4,257（128,000）</td>
<td style="text-align:right">4,096（105k）</td>
<td style="text-align:right">3,635（130,048）</td>
</tr>
<tr>
<td>143K / 157K</td>
<td style="text-align:right">—</td>
<td style="text-align:right">3,403 / 3,174</td>
<td style="text-align:right">—</td>
</tr>
<tr>
<td>210K / 256K</td>
<td style="text-align:right">4,079（256,000）</td>
<td style="text-align:right">2,587（210k）</td>
<td style="text-align:right">2,224（260,096）</td>
</tr>
</tbody>
</table>
<p dir="auto">小 prompt 的差距（3–6 倍）是真實的：Strata 的 prefill 受 PCIe expert streaming 限制（probe 52 GB/s、<code>pcie_frac 0.55</code>）。但到 105K 以上兩者已經接近甚至反轉（Strata 4,257 對 NInfer 4,096；256K 4,079 對 2,224）。</p>
<p dir="auto">TTFT 也一樣：NInfer 09-02 run 在 128K/256K 是 35.8 / 117.0 s，Strata 是 30.3 / 63.2 s。只有 8K 時 NInfer 更快（0.90 s 對 1.5 s）。</p>
<h3>8.4 DFlash</h3>
<p dir="auto">Strata 沒有 DFlash 等价。它的投機是 MTP window 加 suffix lookup（<code>--suffix-draft 3</code>、<code>--mtp-max-t</code>）。NInfer 的 DFlash2 是 5 層 draft（約 1.6B 參數），每 round draft 7 token 再 verify；本機實測 K=7 C=1 corpus 198.7 tok/s、acceptance 36.6%、每 round 3.31 token（post 1967）。Strata 的 MTP+lookup 每 round 3.07 token（真實流量加權），量級接近 MTP3（2.82），達不到 DFlash2 的 3.31–6.5。</p>
<p dir="auto">架構上的分別：NInfer 支持 C=1–8 真 batching 與 context cache（prefix reuse、anchors、host KV tier）；Strata 的 serve 一次只處理一個 request，跨對話重用要靠 parking，而 parking 只支持單 GPU。NInfer 跑不了 IQ2_XS（expert 文件 34 GB 超出 32 GiB VRAM，且沒有 CPU expert tier）——這裡是引擎對引擎，不是同一個 model。</p>
<hr />
<h2>9. 投機窗口：<code>--spec 4</code> 對 <code>--spec 8</code>（實測 A/B）</h2>
<blockquote>
<p dir="auto">同一台機器、同一個配置、同一方法，只改 <code>--spec</code>。<br />
<code>--spec 8</code> 贏在每 round 的 token 數，輸在每秒的 round 數——淨結果是 decode 慢 2–8%。</p>
</blockquote>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>prompt</th>
<th style="text-align:right">spec 4 decode</th>
<th style="text-align:right">spec 8 decode</th>
<th style="text-align:right">Δ</th>
<th style="text-align:right">tokens/round（4 → 8）</th>
<th style="text-align:right">round/s（4 → 8）</th>
</tr>
</thead>
<tbody>
<tr>
<td>4K</td>
<td style="text-align:right"><strong>148.9</strong></td>
<td style="text-align:right">145.2</td>
<td style="text-align:right">−2.5%</td>
<td style="text-align:right">2.44 → 3.01</td>
<td style="text-align:right">61.1 → 48.2</td>
</tr>
<tr>
<td>32K</td>
<td style="text-align:right"><strong>165.0</strong></td>
<td style="text-align:right">151.3</td>
<td style="text-align:right"><strong>−8.3%</strong></td>
<td style="text-align:right">2.53 → 2.84</td>
<td style="text-align:right">65.1 → 53.2</td>
</tr>
<tr>
<td>128K</td>
<td style="text-align:right"><strong>146.0</strong></td>
<td style="text-align:right">142.8</td>
<td style="text-align:right">−2.2%</td>
<td style="text-align:right">2.53 → 2.88</td>
<td style="text-align:right">57.6 → 49.6</td>
</tr>
<tr>
<td>256K</td>
<td style="text-align:right"><strong>127.8</strong></td>
<td style="text-align:right">124.0</td>
<td style="text-align:right">−3.0%</td>
<td style="text-align:right">2.35 → 2.81</td>
<td style="text-align:right">54.4 → 44.1</td>
</tr>
</tbody>
</table>
<blockquote>
<p dir="auto">兩邊都是 3 runs 取中位數、同一配置（424K + parking 26,624 MiB / 4 slots / 1,024 MiB floor）、同一 <code>--spec-min-p 0.5</code>。<br />
4K 的第一輪是冷 cache（prefill 536 / 544 tok/s），中位數不受它影響。</p>
</blockquote>
<h3>為什麼輸</h3>
<p dir="auto">接受率下降：spec 4 是 <strong>65–72%</strong>，spec 8 是 <strong>46–65%</strong>。窗口越深，條件接受率越低——第 4 個 draft 之後的 token 不值得 verify。</p>
<blockquote>
<p dir="auto">spec 8 每 round 多產出 0.4–0.6 個 token，但每秒少做 12–17 個 round。<br />
多出來的 draft 要付 verify 時間，換回的 accepted token 抵不上成本。</p>
</blockquote>
<p dir="auto">這個結果跟引擎自己的 cost model 吻合。<code>controller.hpp</code> 的常數（2026-09-23 三場測量）在 0.86 prior 下算出 optimum 是 <strong>k=3 drafts（window 4）</strong>，也就是 <code>--spec 4</code>；用 <code>draft_policy_test.cpp</code> 那條實測 cost 曲線（19.0 + 10.5·(t−1) ms）算，optimum 是 k=2–3。而 log 顯示 spec 4 實際使用的窗口是 <strong>2.2 drafts/round</strong>——policy 自己選的就是 optimum。spec 8 把 cap 抬到 8，policy 開始 over-draft。</p>
<blockquote>
<p dir="auto"><code>--spec</code> 的硬上限是 8（<code>kVerifyMaxT</code>）。<code>--spec 4</code> 實際 effective cap 是 6（<code>--suffix-draft 3</code> 加 2），MTP window 上限 4；<code>--spec 8</code> 是 cap 8、MTP window 8。</p>
</blockquote>
<p dir="auto">所以：<strong><code>--spec 4</code> 是這台機器的最佳值，<code>--spec 8</code> 沒有數據支持。</strong> 想再往上只有靠 lookup window，而 policy 已經逐 case 自己選。</p>
<hr />
<h2>10. 沒測和沒做完的</h2>
<ul>
<li><strong>IQ3</strong>（<code>ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF</code>）的速度 A/B（5090-only 與 5090+5080 K=36 兩個 config）還沒跑。文件已下載完成，四份都跟 HF API 逐 byte 核對：IQ3_S 54,817,524,224 / 28,800,138,432；IQ3_XXS 47,039,860,096 / 28,800,138,432。</li>
<li><strong>YaRN 延伸的 quality 我沒測</strong>。1.5–4.0× factor 完全沒有 needle 或 perplexity 測試。這篇所有長 context 數字是速度與容量，不是 accuracy。</li>
<li>沒試的 candidates：<code>--kv k8v4</code>（816 對 1,056 B/cell，不能與 <code>--kv-resident</code> 並用）、<code>--kv-resident</code> 的 cell 數、<code>--expert-cache-per-layer</code>（參考測量的 2.97% → 21.4% hits at 8K）、<code>--prefill CHUNK</code>（auto = 8192）、<code>--ple-io mmap|ram</code>、<code>--pool-workers</code> / <code>--no-host-worker</code>，以及 MTP knobs（<code>--mtp-max-t</code>、<code>--spec-min-p</code>、<code>--suffix-draft</code>；<code>--spec</code> 已測，見 §9）。</li>
<li><code>--shared-expert-arena</code>（Linux-only）沒試。</li>
</ul>
<hr />
<h2>11. 複現</h2>
<p dir="auto">Phase 1–5：<code>benchmark.py --targets 4096,32768,128000,256000 --runs 3</code>，每個 config 一份 <code>config-used.json</code>、<code>metrics.json</code>、<code>summary.json</code>、<code>results.json</code>、raw per-request JSON 與 <code>startup.txt</code>。</p>
<p dir="auto">Phase 6：改 <code>--max-context</code> 與 <code>--rope-scaling yarn --rope-scale &lt;factor&gt;</code>，boot 後發送 3–4 條接近上限的獨立對話，看引擎 log 的 <code>conversation cache:</code> 記錄（<code>parked=N bytes=B evictions=E</code>、<code>skip parking (physical RAM admission; need X MiB plus Y MiB floor)</code>）與 <code>/metrics</code> 的 <code>conversation_cache_mib / slots / min_free_mib</code>。准入檢查用的「free」跟 <code>FreePhysicalMemory</code> 是同一口徑，差額可直接核對。</p>
<p dir="auto">Phase 8（§9）：同一 config 跑兩次，只改 <code>--spec</code>，artifacts 在 <code>2026-10-02-spec8/</code> 與 <code>2026-10-02-spec4/</code>。</p>
<p dir="auto">Artifacts：<code>2026-10-01-5090-only/</code>、<code>-5090-only-4targets/</code>、<code>-5090plus5080/</code>、<code>-5090plus5080-remotecache/</code>、<code>-layersplit-K36/</code>、<code>-layersplit-K36-256k/</code>、<code>-layersplit-K36-256k-r3/</code>、<code>-3gpu-K28-42/</code>、<code>-memctl-B3/</code>、<code>-kvq4-B3-256k/</code>、<code>-mmapexperts-B3-256k/</code>、<code>-residentexperts-A-256k/</code>。Phase 6 沒有 artifact 目錄（即時執行，僅有引擎 log）。</p>
<hr />
<h2>12. 參考</h2>
<ul>
<li>前三篇（同一台機器，NInfer）：<a href="https://lcz.me/topic/1228">1228</a>、<a href="https://lcz.me/topic/1462">1462</a>、<a href="https://lcz.me/topic/1967">1967</a></li>
<li>Strata：<a href="https://github.com/Niko1221/Strata" rel="nofollow ugc">https://github.com/Niko1221/Strata</a></li>
</ul>
]]></description><link>https://lcz.me/topic/2038</link><generator>RSS for Node</generator><lastBuildDate>Mon, 12 Oct 2026 13:30:10 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/2038.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 01 Oct 2026 21:14:31 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to [實測IV] Strata / Qwen3.8 Flash IQ2_XS 單卡跑到 424K 155t/s — parking 能留幾條對話：含三個不利發現 on Sat, 10 Oct 2026 04:04:10 GMT]]></title><description><![CDATA[<p dir="auto">能上IQ3_S 肯定用它了，基本上我只考虑IQ4 XS，还有UNSLOTH UD Q4 XL，这几个的KLD PPL最漂亮。</p>
]]></description><link>https://lcz.me/post/23683</link><guid isPermaLink="true">https://lcz.me/post/23683</guid><dc:creator><![CDATA[stxpnet]]></dc:creator><pubDate>Sat, 10 Oct 2026 04:04:10 GMT</pubDate></item><item><title><![CDATA[Reply to [實測IV] Strata / Qwen3.8 Flash IQ2_XS 單卡跑到 424K 155t/s — parking 能留幾條對話：含三個不利發現 on Fri, 09 Oct 2026 13:11:57 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/stxpnet" aria-label="Profile: stxpnet">@<bdi>stxpnet</bdi></a> 我在dsh上跑了上跑了一周(1/10 -6/10)高強度的用也沒發生也沒發生循環問題</p>
<p dir="auto">現在用IQ3_S也沒問題</p>
<h2>IQ3_S 在 DSH 上的實際平均速度</h2>
<p dir="auto">資料來源：<a rel="nofollow ugc">strata-iq3_s-5090.log</a>，涵蓋 <strong>2026-10-06 16:09 → 2026-10-09 12:52</strong>（2.85 天），<strong>11,241 個 request、12,502,938 個 generated tokens、26.56 小時的 decode 時間</strong>。</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>指標</th>
<th style="text-align:right">值</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>decode（加權平均，總 token ÷ 總時間）</strong></td>
<td style="text-align:right"><strong>130.8 tok/s</strong></td>
</tr>
<tr>
<td>decode 中位數</td>
<td style="text-align:right">129.4 tok/s</td>
</tr>
<tr>
<td>decode 算術平均（每 request）</td>
<td style="text-align:right">128.4 tok/s</td>
</tr>
<tr>
<td>p10 / p90</td>
<td style="text-align:right">109.7 / 146.2 tok/s</td>
</tr>
<tr>
<td>min / max</td>
<td style="text-align:right">7.8 / 237.2 tok/s</td>
</tr>
<tr>
<td>prefill（加權平均）</td>
<td style="text-align:right">2,832 tok/s</td>
</tr>
<tr>
<td><strong>含 prefill 的端到端</strong></td>
<td style="text-align:right"><strong>113.6 tok/s</strong></td>
</tr>
<tr>
<td>平均每 request</td>
<td style="text-align:right">1,112 generated tokens，prompt 129,900 tokens</td>
</tr>
<tr>
<td>prefix reuse</td>
<td style="text-align:right">97.2% 的 prompt tokens</td>
</tr>
</tbody>
</table>
<p dir="auto">按 context 大小（加權 decode）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>prompt tokens</th>
<th style="text-align:right">n</th>
<th style="text-align:right">decode</th>
</tr>
</thead>
<tbody>
<tr>
<td>60K–100K</td>
<td style="text-align:right">2,383</td>
<td style="text-align:right">131.4</td>
</tr>
<tr>
<td>100K–140K</td>
<td style="text-align:right">3,298</td>
<td style="text-align:right">130.6</td>
</tr>
<tr>
<td>140K–170K</td>
<td style="text-align:right">2,568</td>
<td style="text-align:right">131.9</td>
</tr>
<tr>
<td>170K–300K</td>
<td style="text-align:right">2,439</td>
<td style="text-align:right"><strong>127.1</strong></td>
</tr>
</tbody>
</table>
<p dir="auto">幾乎平的 —— 到 170K 以上才掉 3.3%。</p>
<h2>跟 IQ2_XS 同一張卡、同樣真實流量的對比</h2>
<p dir="auto"><a rel="nofollow ugc">strata-iq2_xs-5090-maxslot.log</a>（10-04 → 10-07，10,153 requests、8,780,547 tokens）：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th></th>
<th style="text-align:right">IQ2_XS</th>
<th style="text-align:right">IQ3_S</th>
<th style="text-align:right">差</th>
</tr>
</thead>
<tbody>
<tr>
<td>decode 加權</td>
<td style="text-align:right"><strong>167.8</strong></td>
<td style="text-align:right"><strong>130.8</strong></td>
<td style="text-align:right"><strong>−22.0%</strong></td>
</tr>
<tr>
<td>decode 中位</td>
<td style="text-align:right">168.4</td>
<td style="text-align:right">129.4</td>
<td style="text-align:right">−23.2%</td>
</tr>
<tr>
<td>p10 / p90</td>
<td style="text-align:right">143.4 / 193.8</td>
<td style="text-align:right">109.7 / 146.2</td>
<td style="text-align:right"></td>
</tr>
<tr>
<td>含 prefill</td>
<td style="text-align:right">136.4</td>
<td style="text-align:right">113.6</td>
<td style="text-align:right">−16.7%</td>
</tr>
<tr>
<td>prefill</td>
<td style="text-align:right">2,407</td>
<td style="text-align:right">2,832</td>
<td style="text-align:right"><strong>+17.7%（IQ3_S 較快）</strong></td>
</tr>
<tr>
<td>prefix reuse</td>
<td style="text-align:right">97.9%</td>
<td style="text-align:right">97.2%</td>
<td style="text-align:right"></td>
</tr>
</tbody>
</table>
<h2>一個跟我之前 benchmark 不一致的地方（要講清楚）</h2>
<p dir="auto">我之前那輪受控測試（4,096 token 隨機 prompt、greedy、128 tokens）量到 IQ3_S 比 IQ2_XS 慢 <strong>34.4%</strong>。真實使用只有 <strong>22.0%</strong>。原因是 benchmark 用隨機 token 檔 + greedy，draft acceptance 很低（50 of 92）；真實文字好預測得多，加上 97% 的 prefix reuse 讓 expert hit rate 不同。所以<strong>真實懲罰比 benchmark 小</strong>，兩個數字我都留著。</p>
<h2>這組數字的限制</h2>
<ul>
<li>log 是 engine 的 serve log，18081 就是 DSH 的 backend，所以這些是 DSH 打的 request；但我<strong>無法把 DSH 跟其他打同一個 port 的 client（例如 chat 網頁）分開</strong>。</li>
<li>DSH 自己的 <a rel="nofollow ugc">dsh-token-usage\index.json</a> 是<strong>舊的</strong>（<code>writtenAt</code> 2026-08-20，而且完全沒有 strata 那列），所以無法交叉驗證。</li>
<li>serve log 的行<strong>沒有時間戳</strong>，所以做不出每日分解。</li>
<li>這個窗口包含 10-06 16:09 那個 18085 實驗（短暫共存）和 10-07 16:18 用 bat 啟動的那次 —— 都算在 11,241 個 request 裡。</li>
</ul>
<blockquote>
<p dir="auto">4/10 加ram了(64GB -&gt; 192GB) 中間速度(3600-4800 MT/s)有浮動不太準 現在穩定在4800 MT/s</p>
</blockquote>
<p dir="auto"><img src="https://upload.lcz.me/uploads/87f66640-baac-462e-bb52-fbe50fb67de7.jpeg" alt="image.jpeg" class="img-markdown  img-fluid" /></p>
]]></description><link>https://lcz.me/post/23591</link><guid isPermaLink="true">https://lcz.me/post/23591</guid><dc:creator><![CDATA[sky]]></dc:creator><pubDate>Fri, 09 Oct 2026 13:11:57 GMT</pubDate></item><item><title><![CDATA[Reply to [實測IV] Strata / Qwen3.8 Flash IQ2_XS 單卡跑到 424K 155t/s — parking 能留幾條對話：含三個不利發現 on Tue, 06 Oct 2026 02:36:38 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/stxpnet" aria-label="Profile: stxpnet">@<bdi>stxpnet</bdi></a> 所以跑分和实际开发还是完全不同的。</p>
]]></description><link>https://lcz.me/post/22721</link><guid isPermaLink="true">https://lcz.me/post/22721</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Tue, 06 Oct 2026 02:36:38 GMT</pubDate></item><item><title><![CDATA[Reply to [實測IV] Strata / Qwen3.8 Flash IQ2_XS 單卡跑到 424K 155t/s — parking 能留幾條對話：含三個不利發現 on Sun, 04 Oct 2026 05:19:16 GMT]]></title><description><![CDATA[<p dir="auto">IQ3_S循环也很厉害，暂时没有找到解决方案， 要跑实际真实的项目。</p>
]]></description><link>https://lcz.me/post/22254</link><guid isPermaLink="true">https://lcz.me/post/22254</guid><dc:creator><![CDATA[stxpnet]]></dc:creator><pubDate>Sun, 04 Oct 2026 05:19:16 GMT</pubDate></item><item><title><![CDATA[Reply to [實測IV] Strata / Qwen3.8 Flash IQ2_XS 單卡跑到 424K 155t/s — parking 能留幾條對話：含三個不利發現 on Sat, 03 Oct 2026 14:41:27 GMT]]></title><description><![CDATA[<p dir="auto">Q2量化是不是太严重了，IQ3_S就差不多了。</p>
]]></description><link>https://lcz.me/post/22134</link><guid isPermaLink="true">https://lcz.me/post/22134</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Sat, 03 Oct 2026 14:41:27 GMT</pubDate></item></channel></rss>