Document long-context limits and host OOM at near-262K input

This commit is contained in:
2026-09-18 00:03:19 +08:00
parent 48a1c9d7c4
commit f1a8964072
16 changed files with 1054 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
# 长上下文测试:64K / 128K 通过,接近 262K 存在主机 OOM
2026-09-17 开始测试,2026-09-18 完成恢复。方案见 [测试方案](context262k-plan.md)。
**不能将当前配置的 262144 上限视为稳定可用容量。**
64K、128K 的 eager 和 CUDA Graph 两组均通过本轮单请求合成检索。
接近 260K 时,eager 虽然完成全部检索并答对,主机已发生 OOM、杀掉音频服务;
CUDA Graph 在第一份 260K 文档的首次请求中进一步触发 OOM,vLLM 被杀,请求未完成。
本轮已停止后续 260K 请求,不调整参数继续追测。
## 方法与实际长度
- 两组都启用前缀缓存、相同 Mamba 修正;MTP=2、BF16 KV、GPU memory=0.80。
- 每档两份不同合成项目预算档案,在约 5%、50%、95% token 位置放入唯一项目记录。
- 每份查询前、中、后位置,再重复前部问题。共计划每组 24 次主请求;串行执行。
- 输出预算 2048temperature=0、seed=42、reasoning_effort=low;思考与正文共用预算。
- 固定输入在两组间复用,记录文档及完整问题哈希;新的文档前缀避免与预检请求复用。
- 使用服务端 `/tokenize`,显式 `chat_template_kwargs.reasoning_effort=low`
正式完成请求的 usage 与预检逐条一致。
- 实际输入分别为 6550865510、131038131040、259963259965 tokens。
最大输入加预留输出为 262013,低于 262144;不是发送 262144 输入后再额外申请输出。
- 资源采样约每 5 秒一次;不清 OS 页缓存,两种模式按 eager → graph 执行,顺序不随机化。
## 请求结果
| 输入档位 | eager 首试检索 | CUDA Graph 首试检索 | 稳定性结论 |
|---|---|---|---|
| 约 64K | 8/8 正确 | 8/8 正确 | 本轮通过 |
| 约 128K | 8/8 正确 | 8/8 正确 | 本轮通过 |
| 约 260K | 8/8 正确,但主机 OOM | 首个请求 OOM 中断,后续未执行 | 两组都不通过 |
完成的 40 次主请求均正常 stop,没有答案重试或预算截断;图版本第 41 个主请求未完成。
已完成请求中未记录 KV 缓存抢占。这不排除主机内存不足,二者不是同一判据。
## 延迟
首 token 包含思考。首次读入列保留两份文档的实测值;复用列取 6 次后续查询的中位数。
| 输入档位 | eager 首次首 token(秒) | graph 首次首 token(秒) | eager / graph 复用首 token(秒) |
|---|---:|---:|---:|
| 约 64K | 30.66 / 31.04 | 31.38 / 31.20 | 1.64 / 1.63 |
| 约 128K | 64.90 / 63.08 | 64.67 / 63.28 | 1.77 / 1.77 |
| 约 260K | 168.29 / 137.20 | 未完成 | 1.82 / 无结果 |
eager 的 260K 首次完整回答耗时约 170.50 / 139.25 秒;复用后中位数约 3.82 秒。
该耗时记录来自发生过主机 OOM 的阶段,不能作为稳定性能承诺。
260K 后续请求每次实际 prefix hit 为 257600 tokens。
CUDA Graph 对本轮 64K/128K 预填充未显示明显加速,不能把此前短回答约 4.4% 的收益外推到超长输入。
## 主机 OOM 证据与影响
- eager 阶段采样最低 MemAvailable 约 0.139 GiB23:28:31 的内核日志记录杀掉 4 个
`wireplumber` / `pipewire` 进程。模型继续回答不代表系统没有受影响。
- graph 阶段采样最低 MemAvailable 约 0.077 GiB23:50:12 的内核日志记录杀掉 21 个进程,
包括 vLLM、用户管理、D-Bus、桌面门户和音频进程。容器监控记录 `OOMKilled=true`
- 图请求输出流中断,测试客户端报 `Incomplete response or missing usage`,并触发恢复。
- 两阶段 swap 存量最高都仅约 0.40 GiB;swap 不大量增长不能证明没有内存风险。
- 以上是主机内存耗尽证据,不是已定位到具体 CUDA 内核的缺陷,也不是输出 2048 tokens 太小。
原保护条件要求“低于 4 GiB 持续约 30 秒且同期换页超过 512 MiB”,并检查容器 OOM。
它遗漏了主机进程先被杀的情况,导致 eager 的资源风险未被及时判失败。
该监控覆盖不足已记录;最终稳定性判定以内核日志为准,不能只看 Docker 健康或答案正确率。
改进版监控位于 `experiments/context262k/monitor.py`:加入 `/proc/vmstat` 的主机 OOM 计数,
并在低于 2 GiB 持续约 5 秒时停止测试容器,不再依赖显著 swap 增长。
这是本次事故后的改进,仅做语法检查;没有为验证保护而再次制造低内存场景。
原监控保存在 `monitor-original.py`,两者均是尽力保护,不能保证拦截采样间发生的瞬时 OOM。
## 复现记录与限制
- `scripts/context-benchmark.py`:确定性生成、服务端计数预检、流式检索测试。
- `scripts/summarize-context.py`:按档位汇总,首试和重试分开;请求完成不等于主机稳定。
- `docs/results/context262k/`:正式输入清单、请求结果、资源采样、内核 OOM 事件提取。
- 初次脚本预检曾误用 Transformers 的 BatchEncoding 长度,已改成 `return_dict=False`
另一次预检请求答对但发现思考模板导致 12-token 计数差异,已修正。两者不混入正式对照。
- 本轮只测试简短合成检索;未验证长答案生成、真实复杂推理、并发满长、长期运行或多模态。
当前证据支持优先在 128K 以内使用和继续验证。要争取接近 262K 的稳定容量,需另行留出更多主机内存并复测,
例如评估降低 KV 缓存预算;本轮没有以调整配置后的结果替代原配置的失败。
## 恢复状态(2026-09-18 00:02Asia/Shanghai
- 已恢复 `local/qwen38-flash-spark:prefix-eager-0bfc7a15`,容器 healthy,重启策略 `unless-stopped`
- 恢复后的算术、中文与工具调用 smoke test 全部通过,可用内存约 18 GiB。
- 已重新启动被 OOM 杀掉的用户管理服务,并确认 D-Bus、音频和用户桌面门户服务 active。
系统及当前用户的 failed units 均为 0;这不等于核验过远程桌面应用的会话内容。
- 默认 Compose 与测试前完全一致,仍配置 262144 上限;本轮没有擅自缩短服务上限。
该上限在当前资源设置下不代表稳定容量,建议业务侧优先限制在 128K 范围内。
- 所有长上下文测试已停止;没有继续使用失败图配置,也没有再次制造内存压力验证新监控。