# PR #29431 完整报告

- 仓库：`sgl-project/sglang`
- 标题：Lightweight extract allocation logic from mem_cache/common.py to more clearly show nearly parallel variants
- 合并时间：2026-07-15 14:49
- 原文链接：http://prhub.com.cn/sgl-project/sglang/pull/29431

---

# 执行摘要

- 一句话：提取分配逻辑到新文件 allocation.py 和 allocation_sizing.py
- 推荐动作：推荐精读，该 PR 展示了大规模机械重构的实践：通过 AST 搬迁工具确保纯搬迁可重现，并用清晰的提交结构（prep + move + postpare）管理重构链。对关注代码组织和模块拆分的读者有参考价值。

# 功能与动机

将分配逻辑从 common.py 这个大杂烩中提取出来，使分配入口点和大小计算集中在专用模块中，便于理解和维护并行变体，为后续解耦做准备（PR body: 'Lightweight extraction of the allocation entry points ... out of the mem_cache/common.py junk drawer'）。

# 实现拆解

### 步骤 1. 创建 allocation.py
新建文件 `python/sglang/srt/mem_cache/allocation.py`，从 common.py 搬入 `write_cache_indices`、`get_last_loc`、`get_last_loc_torch`、`alloc_token_slots`、`_compute_dsv4_state_lens`、`alloc_paged_token_slots_extend`、`alloc_req_slots`、`_alloc_page_size` 等函数，保持逻辑完全一致。

### 步骤 2. 创建 allocation_sizing.py
新建文件 `python/sglang/srt/mem_cache/allocation_sizing.py`，搬入 `get_alloc_len_per_decode`、`get_alloc_reserve_per_decode`、`get_req_to_token_extra_context_len` 三个分配大小计算辅助函数。

### 步骤 3. 精简 common.py
从 common.py 中删除已搬迁的函数和不再需要的导入（如 `support_triton`、`is_pin_memory_available`、`maybe_write_dsv4_*` 等），仅保留剩余的工具函数（`kv_to_page_indices`、`free_swa_out_of_window_slots`、`release_kv_cache` 等）。

### 步骤 4. 更新消费方导入
更新所有引用这些函数的模块的 import 路径：
- `schedule_batch.py`：`alloc_for_decode`、`alloc_for_extend` 改从 `allocation` 导入，`get_alloc_reserve_per_decode` 改从 `allocation_sizing` 导入。
- `pool_configurator.py`：`get_alloc_len_per_decode` 改从 `allocation_sizing` 导入。
- `eagle_utils.py`：相关函数改从 `allocation` 和 `allocation_sizing` 导入。
- `dsv4_allocator.py`、`kv_cache_configurator.py`、`dflash_info_v2.py`：仅调整导入路径。

### 步骤 5. 后处理调整
使用已导入的 `get_server_args()` 替代 `get_global_server_args()`，更新调试工具 `pr_fix_toggle.py` 中的路径字符串指向 `allocation_sizing`，并降低 `get_global_server_args` 的 ratchet baseline 至 279。

无测试行为变更；测试文件仅更新导入路径。

关键文件：
- `python/sglang/srt/mem_cache/allocation.py`（模块 缓存层；类别 source；类型 core-logic；符号 write_cache_indices, get_last_loc, get_last_loc_torch, alloc_token_slots）: 新文件，核心分配入口点（write_cache_indices, get_last_loc, alloc_token_slots 等）搬迁至此，是 PR 最主要的新模块。
- `python/sglang/srt/mem_cache/allocation_sizing.py`（模块 缓存层；类别 source；类型 core-logic；符号 get_alloc_len_per_decode, get_alloc_reserve_per_decode, get_req_to_token_extra_context_len）: 新文件，集中存放分配大小计算逻辑，包括 spec decode 的 page-aligned 计算。
- `python/sglang/srt/mem_cache/common.py`（模块 缓存层；类别 source；类型 dependency-wiring；符号 write_cache_indices, get_last_loc, get_last_loc_torch, get_alloc_len_per_decode）: 精简后的 common.py 仅保留非分配工具函数，是提取操作的目标文件。
- `python/sglang/srt/managers/schedule_batch.py`（模块 调度器；类别 source；类型 dependency-wiring）: 主要消费方，导入从 common 改指向 allocation 和 allocation_sizing。
- `python/sglang/srt/speculative/eagle_utils.py`（模块 投机解码；类别 source；类型 dependency-wiring）: 投机解码模块，同时引用 allocation 和 allocation_sizing 中的函数。

关键符号：write_cache_indices, get_last_loc, get_last_loc_torch, alloc_token_slots, _compute_dsv4_state_lens, alloc_paged_token_slots_extend, alloc_req_slots, _alloc_page_size, get_alloc_len_per_decode, get_alloc_reserve_per_decode, get_req_to_token_extra_context_len


# 评论区精华

唯一 review 来自 gemini-code-assist[bot]：指出 `allocation.py` 中 `alloc_req_slots` 函数在 `tree_cache` 可能为 `None` 时调用 `supports_mamba()` 可能导致 `AttributeError`。但该问题在原始代码中已存在，非本次引入。作者未回应（或已通过合并解决）。

- tree_cache 为 None 时的潜在 AttributeError (correctness): 该问题在原始代码中已存在，本次搬迁未引入新风险；作者未予回应或已通过后续合并解决。

# 风险与影响

- 风险：本次变更为纯提取，无行为变更，风险极低。主要风险在于导入路径重写是否完全正确；PR 提交时作者通过了机械搬迁验证（byte-for-byte reproduce），且 CI 聚合测试（#28636）覆盖了主要路径，但未提供专门测试。
- 影响：对用户无影响。对开发者：模块职责划分更清晰，便于后续添加新的分配变体；所有消费方导入已更新为指向新模块。
- 风险标记：纯提取无行为变更 , 导入重写需验证

# 关联脉络

- PR #29432 Fix bookkeeping fields not encapsulated with real allocations in normal alloc, PD pre-alloc, DFlash and EAGLE: 同一作者在同一重构系列中提交的后续 PR，进一步封装记账字段，与本 PR 的模块划分紧密相关。