把 supergemma4-26B 当 llama-server 常驻服务用的时候,我撞上了一个硬钉子:16K 上下文稳定,一到 20K 就 HTTP 500,报错是 vk::Queue::submit: ErrorDeviceLost。这篇记录完整的排查过程,以及最终救命的参数——-ub 物理批次切块。
环境:Intel Arc 140T(共享显存已调至 90%,预算 ~21.6GB)/ 23.5GB 内存 / llama.cpp b10621 / supergemma4-26B(15.6GB)。2026-09-02 实测。
核心发现:KV 预分配是启动预占、运行仍爆的根源
不显式指定 -c 时,llama-server 按 n_ctx≈228608 启动一次性预分配 KV(日志 n_ctx_slot = 262144)。KV q8 每 token 约 22.5KB → 预占 ~6.4GB;加上权重 15.6GB,启动完成进程已 ~21.6GB,贴着 90% 预算上限。
但「预占」只覆盖 KV,不覆盖 Flash Attention 的 prefill 临时工作区——后者按请求实际长度运行时分配。20K 一次灌入时临时区达数 GB,此时预算已满 → 驱动任何新分配失败 → 连 createComputePipeline 都报 ErrorOutOfDeviceMemory。这就是「q8 了还差 3-4G」的根源。
关键参数表(b10621 验证)
| 参数 | 作用 | 本机实测 |
|---|---|---|
| -ub N(默认 512) | 物理批次,决定 prefill 切块大小 | -ub 128/256 分块 → 20K 稳定;-ub 4096 不分块 → 必崩 |
| -b N(默认 2048) | 逻辑批次上限 | -b 65536 无收益,real 切块仍由 -ub 决定 |
| -c N | 上下文 / KV 预分配上限 | -c 65536 省 ~4.5GB KV,给 prefill 临时区留余量 |
| --n-cpu-moe N | 前 N 层 MoE 专家权重放 CPU | 省显存,但生成降速 ~30%,不建议 |
| --no-mmap | 关 CPU 侧 mmap | 需双横线(-no-mmap 报 invalid argument) |
| -fa on | Flash Attention | 必须,否则输出全进 reasoning_content |
| -rea off | 关闭思考块 | 必须,否则 content 为空 |
| -ctk/-ctv q8_0 | KV 量化省一半内存 | 开启 |
| --dynamic-kv-cache | KV 动态增长 | 本版本不存在,invalid argument |
不分块(-ub 4096)单次 20K:全部失败
| 组合 | 20K 结果 |
|---|---|
| -ub 4096 -fa on | ❌ ErrorDeviceLost |
| + --no-mmap | ❌ 连接重置 / 崩 |
| + --no-mmap + -c 65536(KV 缩 64K) | ❌ 进程崩溃 |
| + GGML_VK_PREFER_HOST_MEMORY=1 | ❌ 进程崩溃 |
| + --n-cpu-moe 12 | ❌ 连接重置(attention 仍全量 GPU) |
结论:Intel 核显 Vulkan 后端的 device-local 内存管理在大 ubatch prefill 时不稳定(驱动级 bug,社区 issue #18808 / #18946 同型),非参数可解。20K 必须 -ub ≤ 256 分块。
分块实测(20K,prompt=19827,-rea off)
| 配置 | prefill | generation | wall(20K) | 结论 |
|---|---|---|---|---|
| -ub 256(含 -fa on) | 69.3 t/s | 11.1 t/s | 286 s | ✅ 推荐 |
| -ub 128 | 65.0 t/s | 9.8 t/s | 305 s | ✅ 稳定但略慢 |
| -ub 64k(-b 65536) | — | — | — | 无收益,不采用 |
| -c 65536 + --n-cpu-moe 4 | — | — | — | 速度无差异,仅省显存 |
生成 11.1 t/s(20K 长上下文预热后略低于 short 的 21.4 t/s,属长上下文 attention 开销)。30K 亦通过,且命中前缀缓存 cached=19670。
-ub / -c 上限扫描:为什么小批次反而能跑
两种内存维度要区分:-ub 控制「并发瞬时峰值」(临时激活 buffer),-c 控制「常驻容量」(KV 缓存),两者挤占同一 21.6GB 预算。
| 配置 | 测试长度 | -ub | 结果 | prefill (t/s) |
|---|---|---|---|---|
| -c 65536 | 32K (31727) | 256 | ✅ | 47.4 |
| -c 65536 | 32K (31727) | 288 | ✅ | 46.9 |
| -c 65536 | 32K (31727) | 320 | ❌ 500/崩 | — |
| -c 65536 | 32K (31727) | 384 | ❌ 500/崩 | — |
| -c 65536 | 32K (31727) | 512 | ❌ 500/崩 | — |
| -c 32768 | 16K (15827) | 256 | ✅ | 81.7 |
| -c 32768 | 16K (15827) | 512 | ✅ | 84.0 |
| -c 32768 | 16K (15827) | 1024 | ❌ 500/崩 | — |
结论:缩 -c 省 KV 确能提升 -ub 上限。32K 的 -ub 稳定上限 ≈ 288-320 之间,-ub 1024 在此 iGPU 上必崩。
最终定型配置
| 目标 | 最佳配置 | prefill |
|---|---|---|
| 32K 上下文 | -c 65536 -ub 256 | 47 t/s |
| 16K + 高填充 | -c 32768 -ub 512 | 84 t/s |
省内存三大杠杆(可叠加):① -c 缩 KV;② -ctk/-ctv q8_0 减半;③ -ub 调小控 FA 临时区。调优只动 -ub,-b 保持默认或 ≥-ub 即可(-b 只有设 ≤-ub 时才生效,变小块更慢)。
--n-cpu-moe 实测:固定开销,不建议
| --n-cpu-moe | prefill (t/s) | gen (t/s) | 相对基线 |
|---|---|---|---|
| 0(全 GPU 基线) | ~116 | 19.2~19.4 | 100% |
| 4(前 4 层 → CPU) | ~112 | 13.5~13.6 | ~70% |
| 8(前 8 层 → CPU) | ~100 | 12.9~13.3 | ~68% |
| 12(前 12 层 → CPU) | ~100 | 12.8~13.3 | ~68% |
只要开了 --n-cpu-moe(哪怕只卸 4 层),生成速度就从 ~19 t/s 掉到 ~13 t/s;卸到 12 层几乎无进一步下降。原因是 CPU 卸载引入固定管线同步开销,一旦启动,所有层都受此瓶颈约束。Intel iGPU(UMA)下尤其伤——GPU↔CPU 共享内存控制器,同步开销远大于独显 PCIe。对你 20K 长上下文的场景,仅省显存、对预填充无帮助、生成反而降速 30%,不建议使用。
-ub 256 分块,-c 65536 缩 KV,q8 量化,-fa on + -rea off 拉满。