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

7.2 KiB
Raw Blame History

xserv — To Be Fixed (2026-05-23 审查更新)

由全面审查产出的修复清单。每项修复有明确验收标准。 优先级: P0 (阻塞可用性) > P1 (严重bug/性能) > P2 (重要改进) > P3 (设计债务)


第一批P0 — 阻塞可用性

FIX-01: 全局 cuBLAS handle [P0-性能] 未修

问题: gemm.rsmatmul (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:218emit_token 先发 GenerateEvent::Token { text: "<|im_end|>" } 再发 Doneapi.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_tokensengine.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 stepcudaMalloc 调用次数应显著低于总分配次数
  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:88rmsnorm.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。

修复要求:

  • runningVec<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_qkvmerge_headsadd_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