# nanovllm 状态泄漏调试计划 **Task**: 修复连续请求之间的状态泄漏,使 RULER 32K 测试准确率从 ~80% 提升到 100% **Created**: 2026-01-20 **Updated**: 2026-01-21 **Status**: `in_progress` **Reference**: [docs/ruler_32k_chunked_offload_issue.md](docs/ruler_32k_chunked_offload_issue.md) --- ## Root Cause Summary **已确认问题**: 连续请求之间的状态泄漏 - **证据**: 单样本测试(每次重新初始化 LLM)准确率 100%,批量测试准确率 ~80% - **差异**: 20% 的错误率来自状态泄漏 --- ## 调试规范 (MUST FOLLOW) ### 1. 并行工作流(多 GPU + 异步 Task + 标志文件) ``` ┌─────────────────────────────────────────────────────────────┐ │ GPU 0: 异步 Task - 当前版本测试 (v1) │ │ → 结果: /tmp/nanovllm_test_v1.json │ │ → 标志: /tmp/nanovllm_test_v1.done │ ├─────────────────────────────────────────────────────────────┤ │ GPU 1: 主 Agent - 调试/修复代码 │ │ → 状态对比验证 │ │ → 修改代码 │ ├─────────────────────────────────────────────────────────────┤ │ GPU 2: 异步 Task - 新版本测试 (v2, 修复后) │ │ → 结果: /tmp/nanovllm_test_v2.json │ │ → 标志: /tmp/nanovllm_test_v2.done │ ├─────────────────────────────────────────────────────────────┤ │ 主 Agent: 检查标志文件,读取结果,决定下一步 │ └─────────────────────────────────────────────────────────────┘ ``` **标志文件约定**: - 结果文件: `/tmp/nanovllm_test_.json` - 完成标志: `/tmp/nanovllm_test_.done` ### 2. 验证测试命令 ```bash # 批量测试 niah_single_1 (100 samples) - 作为验证手段 CUDA_VISIBLE_DEVICES=X PYTHONPATH=/home/zijie/Code/nano-vllm:$PYTHONPATH \ python tests/test_ruler.py --task niah_single_1 --enable-offload --json-output /tmp/result.json # 完成后写标志文件 echo "done" > /tmp/nanovllm_test_done.flag ``` ### 3. Phase 完成后报告 每个 Phase 完成后: 1. **更新 `progress.md`** - 记录测试结果和发现 2. **向用户报告** - 总结本 phase 的结果 3. **等待用户确认** - 不要自动开始下一个 phase --- ## 问题优先级(已更新) | 优先级 | 问题 | 文件位置 | 状态 | |--------|------|----------|------| | **P0** | CPU cache 未清除 | `offload_engine.py:reset()` | 需要验证 | | **P0** | Ring buffer slot 状态 | `offload_engine.py` | 需要验证 | | **P1** | Sparse policy 状态 | `sparse/policy.py` | 待检查 | | **P2** | HybridManager 跟踪变量 | `hybrid_manager.py` | 待检查 | --- ## Phase 0: 状态分析 **Status**: `completed` **Objective**: 分析代码中的状态管理逻辑 ### 发现 #### OffloadEngine.reset() 分析 **文件**: `nanovllm/kvcache/offload_engine.py:247-274` | 组件 | reset() 是否清除 | |------|-----------------| | GPU ring buffer (k/v_cache_gpu) | Yes | | Decode buffers (decode_k/v_buffer) | Yes | | Prefill buffers (prefill_k/v_buffer) | Yes | | Pending events | Yes | | **CPU cache (k/v_cache_cpu)** | **No** | | Ring buffer slot 状态 | 需要验证 | #### HybridKVCacheManager.deallocate() 分析 **文件**: `nanovllm/kvcache/hybrid_manager.py:206-237` - 释放 logical blocks - 释放 CPU blocks - 调用 `offload_engine.reset()` - 只在 sequence 完成时调用 #### LLMEngine.generate() 分析 **文件**: `nanovllm/engine/llm_engine.py:84-142` - 调用 `Observer.complete_reset()` 重置性能观察器 - **没有显式调用 KV cache 重置** --- ## Phase 1: 状态一致性验证 **Status**: `in_progress` **Objective**: 对比 fresh-llm 模式和 batch 模式下的初始状态,找出差异 ### 验证思路 ``` fresh-llm 模式: 每个 request 新建 LLM → 状态必定干净 → 100% 准确 batch 模式: 复用 LLM 实例 → 状态可能残留 → ~80% 准确 差异 = 泄漏源 ``` ### Tasks - [ ] 1.1 添加状态 dump 函数到代码中 - [ ] 1.2 运行 fresh-llm 模式,记录某个 sample (如 #40) 开始时的状态 - [ ] 1.3 运行 batch 模式,记录同一个 sample 开始时的状态 - [ ] 1.4 对比两个状态,找出差异项 ### 需要检查的状态 | 组件 | 状态 | fresh-llm | batch | 差异? | |------|------|-----------|-------|-------| | OffloadEngine | k_cache_cpu.sum() | - | - | - | | OffloadEngine | v_cache_cpu.sum() | - | - | - | | OffloadEngine | k_cache_gpu.sum() | - | - | - | | OffloadEngine | v_cache_gpu.sum() | - | - | - | | OffloadEngine | decode_k_buffer.sum() | - | - | - | | OffloadEngine | prefill_k_buffer.sum() | - | - | - | | HybridManager | len(prefilled_blocks) | - | - | - | | HybridManager | len(free_logical_ids) | - | - | - | ### 预期结果 找到具体哪些状态在 batch 模式下不为零(或不同),这些就是泄漏源。 --- ## Phase 2: 修复泄漏源 **Status**: `pending` **Objective**: 根据 Phase 1 的发现,修复具体的泄漏点 ### Tasks - [ ] 2.1 根据 Phase 1 确定的差异项,添加对应的清除逻辑 - [ ] 2.2 运行验证测试 --- ## Phase 3: 验证修复效果 **Status**: `pending` **Objective**: 确认修复后准确率达到 100% ### Tasks - [ ] 3.1 运行 batch 模式测试 (niah_single_1) - [ ] 3.2 对比修复前后准确率 - [ ] 3.3 运行其他 task (multikey) 验证 ### Target | Task | 修复前 | 修复后目标 | |------|--------|-----------| | niah_single_1 (batch) | ~80% | 100% | | niah_single_1 (fresh-llm) | 100% | 100% (baseline) | | multikey_1 | ~94% | 100% | | multikey_2 | ~94% | 100% | | multikey_3 | ~56% | >90% | --- ## Errors Encountered | Error | Phase | Attempt | Resolution | |-------|-------|---------|------------| | (待记录) | - | - | - | --- ## Decision Log | Decision | Reason | Phase | |----------|--------|-------| | 使用状态一致性对比验证 | 直接对比差异,不需要逐个猜测泄漏源 | 1 | | 使用 fresh-llm 作为 baseline | 确认单样本测试 100% 通过 | 0 | --- ## Files to Modify | File | Modification | Phase | |------|--------------|-------| | `nanovllm/kvcache/offload_engine.py` | 在 reset() 添加 CPU cache 清零 | 1 | | `nanovllm/kvcache/offload_engine.py` | 添加 slot 状态重置 | 2 | | `nanovllm/kvcache/sparse/policy.py` | 添加 reset() 如需要 | 3 | --- ## References - [docs/ruler_32k_chunked_offload_issue.md](docs/ruler_32k_chunked_offload_issue.md) - 问题背景 - [docs/architecture_guide.md](docs/architecture_guide.md) - 架构参考 - [findings.md](findings.md) - 代码分析发现 - [progress.md](progress.md) - 进度日志