Files
xserv/docs/TO-BE-FIXED.md
Gahow Wang 986a289616 fix: 12 bug fixes from comprehensive review — 51 tok/s verified on RTX 5090
P0 fixes (blocking usability):
- FIX-01: thread-local cuBLAS handle (was creating/destroying per matmul)
- FIX-16: EOS token no longer leaks into API responses
- FIX-17: max_seq_len configurable via --max-seq-len (default 2048, was hardcoded 256)
- FIX-18: max_tokens clamped to available seq space, prompt overflow returns 400

P1 fixes (bugs & performance):
- FIX-07: CachingAllocator wired into all hot paths (to_device, embedding, rope, concat)
- FIX-08: CudaDeviceProp buffer increased to 32KB for CUDA 12.9 safety
- FIX-09: tokenizer byte_fallback graceful degradation (was panic)
- FIX-19: causal mask uses -INFINITY instead of -1e9 (BF16 supports inf)
- FIX-20: LayerNorm rewritten to numerically stable two-pass algorithm
- FIX-21: min block size guard (32 threads) for LayerNorm/RMSNorm launches

P2 fixes (improvements):
- FIX-22: Option<GpuKVCache> + take() eliminates dummy KV cache allocations
- FIX-23: RoPE cache no longer artificially capped at 8192 positions

Verified on dash5 (RTX 5090): 51 tok/s batch=1, 74 tok/s 2-concurrent, 1.7-3.3x HF transformers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-23 14:13:43 +08:00

215 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# xserv — To Be Fixed (2026-05-23 审查更新)
> 由全面审查产出的修复清单。每项修复有明确验收标准。
> 优先级: P0 (阻塞可用性) > P1 (严重bug/性能) > P2 (重要改进) > P3 (设计债务)
---
## 第一批P0 — 阻塞可用性
### FIX-01: 全局 cuBLAS handle [P0-性能] ❌未修
**问题**: `gemm.rs``matmul` (line 146) 和 `batched_matmul` (line 224) 每次调用都 `CublasContext::new()` 创建+销毁 handle。Qwen3-8B 一次 forward ~252 次 matmul。
**修复要求**:
- 使用 thread-local 单例 cuBLAS handle
- handle 生命周期覆盖整个进程
- `matmul` / `batched_matmul` 函数体内不再有 `CublasContext::new()`
**验收标准**:
1. `grep -n "CublasContext::new" crates/xserv-kernels/src/gemm.rs` 只出现 1 次thread_local 初始化处)
2. 编译通过,现有 gemm_test 全部通过
---
### FIX-16: EOS token 泄漏到 API 响应 [P0-功能] ❌新发现
**问题**: `engine.rs:218``emit_token` 先发 `GenerateEvent::Token { text: "<|im_end|>" }` 再发 `Done``api.rs:110-111` 把所有 Token text 拼到 content 里,导致最终响应包含 `<|im_end|>` 乱码。
**修复要求**:
- `emit_token` 中,当 token 是 EOS 时,不发送 Token event或发送空 text直接发 Done
- 或者: API 层收到 Done 时丢弃最后一个 token 的 text如果 finish_reason == "stop"
**验收标准**:
1. 发送请求,响应 content 不包含 `<|im_end|>` 或其他 special token 文本
2. streaming 模式下最后一个 content chunk 不是 EOS 文本
3. 编译通过
---
### FIX-17: max_seq_len 硬编码 256 [P0-功能] ❌新发现
**问题**: `engine.rs:53` 硬编码 `let max_seq_len = 256`,超过就 KV cache panic。
**修复要求**:
- `Engine::load` 接受 `max_seq_len` 参数(或从 config 读取,上限为 config.max_seq_len()
- `main.rs` 中通过命令行参数或环境变量传入,默认值改为 2048
- 同步更新 RoPE cache 上限(当前 `qwen3.rs:45` 限制 8192应与 max_seq_len 一致)
**验收标准**:
1. `grep -n "let max_seq_len = 256" crates/xserv-server/` 返回 0 行
2. 启动 server 时 `--max-seq-len 4096` 可用
3. 编译通过
---
### FIX-18: max_tokens 无上限校验 [P0-功能] ❌新发现
**问题**: API 不校验 `max_tokens`,客户端可发 `max_tokens: 1000000` 导致 KV cache panic。
**修复要求**:
- `api.rs` 中 clamp `max_tokens``engine.max_seq_len - prompt_tokens.len()`
- 如果 prompt 已超过 max_seq_len返回 400 错误
**验收标准**:
1. 发送 `max_tokens: 999999`,不 panic正常生成到 seq_len 上限
2. 发送超长 prompt> max_seq_len返回 HTTP 400
3. 编译通过
---
## 第二批P1 — 严重 bug/性能
### FIX-07: 使用 CachingAllocator [P1-性能] ❌未修
**问题**: `CachingAllocator` 已实现(`allocator.rs`)但从未使用。所有 GPU 分配直接 `cudaMalloc`
**修复要求**:
- `Tensor::empty` 对 GPU device 使用 `cached_alloc` 而非 `GpuBuffer::alloc`
- `GpuBuffer::Drop` 调用 `cached_dealloc` 归还到池(而非 `cudaFree`
- 或者更简单:在 `GpuBuffer::alloc` 内部接入 caching allocator全局透明替换
**验收标准**:
1. 连续运行 10 次 decode step`cudaMalloc` 调用次数应显著低于总分配次数
2. 编译通过,现有测试通过
3. 推理结果与修复前一致
---
### FIX-08: CudaDeviceProp FFI 安全性 [P1-Bug] ❌未修
**问题**: `ffi.rs:31``_pad: [u8; 4096]` 猜测 `cudaDeviceProp` struct 大小CUDA 12.9 可能更大。
**修复要求**:
- 增大 pad 到 `[u8; 8192]` 或使用 `cudaDeviceGetAttribute` 替代 name 查询
- 可参考 `device.rs` 中已有的 `cudaDeviceGetAttribute` 用法
**验收标准**:
1. `device_info()` 返回正确的 device name
2. 编译通过
---
### FIX-09: Tokenizer byte_fallback panic [P1-Bug] ❌未修
**问题**: `bpe.rs:176-182` 中 Qwen3 tokenizer 遇到不在 vocab 的单字节时 panic。
**修复要求**:
-`byte_fallback == true` 且单字节不在 vocab 时,查找 `<0xNN>` 格式 token
- 如果 `<0xNN>` 也不存在,返回 unk_token_id而非 panic
**验收标准**:
1. 包含所有 256 个字节值的字符串可以 encode 不 panic
2. 编译通过
---
### FIX-19: 因果掩码 -1e9 应改为 -inf [P1-Bug] ❌新发现
**问题**: `csrc/attention/causal_mask.cu:31``-1e9f` 代替 `-inf`,注释说 "BF16 没有 -inf" 但这是错误的。
**修复要求**:
- BF16 路径改为 `__float2bfloat16(-INFINITY)`
- F32 路径改为 `-INFINITY`(如果还没有的话)
**验收标准**:
1. causal mask 中被遮蔽的值为 `-inf`(而非 `-1e9`
2. 编译通过attention test 通过
---
### FIX-20: LayerNorm 数值稳定性 [P1-Bug] ❌新发现
**问题**: `csrc/normalization/layernorm.cu:19-25` 注释写 "Welford online" 但实际用 `E[x²] - E[x]²`,大均值小方差时会灾难性抵消。
**修复要求**:
- 改为真正的 two-pass 或 Welford online 算法
- pass 1: 求 mean; pass 2: 求 variance = E[(x-mean)²]
**验收标准**:
1. 对 mean=1e6, std=1e-3 的输入layernorm 输出与 PyTorch 一致relative error < 1e-3
2. 编译通过现有测试通过
---
### FIX-21: LayerNorm/RMSNorm 最小 block size [P1-Bug] ❌新发现
**问题**: `layernorm.cu:88` `rmsnorm.cu` hidden_size < 32 的输入会崩溃block_reduce 需要至少一个完整 warp)。
**修复要求**:
- launch `block = max(min(hidden_size, 1024), 32)`
**验收标准**:
1. hidden_size=16 layernorm/rmsnorm 不崩溃
2. 编译通过
---
## 第三批P2 — 重要改进
### FIX-22: Engine dummy KV cache 分配 [P2-性能] ❌新发现
**问题**: `engine.rs:142-148` 每次 batched decode `std::mem::replace` 创建 dummy `GpuKVCache::new(..., 1, ...)` 来绕过 borrow checker每步分配 `num_layers * 2` GPU buffer
**修复要求**:
- `running` `Vec<Sequence>` 改为存储方式让 KV cache 可以独立借出
- 或使用 `Option<GpuKVCache>` + `.take()` / `.insert()` 避免 dummy 分配
**验收标准**:
1. batched decode 路径不再分配 dummy KV cache
2. 编译通过功能不变
---
### FIX-23: RoPE cache 硬限 8192 [P2-功能] ❌新发现
**问题**: `qwen3.rs:45` `config.max_seq_len().min(8192)` 人为截断
**修复要求**:
- 去掉 `.min(8192)`或改为与 engine max_seq_len 一致
- 确保 RoPE cache 覆盖实际使用的 max_seq_len
**验收标准**:
1. RoPE cache 长度 >= engine max_seq_len
2. 编译通过
---
### FIX-15: GPT-2 消除 CPU round-trip [P3-性能] ❌未修
**问题**: GPT-2 `split_qkv``merge_heads``add_bias` 全在 CPU 做。优先级低GPT-2 不是主力模型)。
---
## 修复依赖图和执行顺序
```
第一批 P0 (可并行):
FIX-01 (cuBLAS handle) ← 独立
FIX-16 (EOS 泄漏) ← 独立
FIX-17 (max_seq_len) ← 独立FIX-23 依赖此
FIX-18 (max_tokens 校验) ← 依赖 FIX-17需要知道 max_seq_len
第二批 P1 (可并行):
FIX-07 (caching allocator) ← 独立
FIX-08 (CudaDeviceProp) ← 独立
FIX-09 (byte_fallback) ← 独立
FIX-19 (causal mask -inf) ← 独立
FIX-20 (layernorm 稳定性) ← 独立
FIX-21 (min block size) ← 独立
第三批 P2:
FIX-22 (dummy KV cache) ← 独立
FIX-23 (RoPE cache) ← 依赖 FIX-17
```