KDA 性能工程方法:从 Profile、噪声控制到可信 PR
KDA(Kernel Development Agents)如果只理解成“让 Agent 自动写 CUDA/Triton kernel”,其实低估了它的目标。
对于 CosyVoice、Qwen3-Omni、dots.tts 一类多阶段生成系统,更有价值的形态是:
让 Agent 完成一轮可验证的性能工程闭环:Profile → 归因 → 提出可证伪假设 → 干预实验 → 正确性验证 → E2E 复现 → PR。
这套方法比单纯追求某个 kernel 的 microbenchmark 更重要,因为多阶段 serving 中最常见的问题并不是“算得慢”,而是 CPU dispatch、stage queue、shape churn、batch formation、数据通路或同步把 GPU 饿住。
1. 第一原则:先测占比,再决定优化对象
Section titled “1. 第一原则:先测占比,再决定优化对象”多阶段系统应先拆 runtime:
T_e2e├── T_preprocess├── T_AR / Thinker├── T_DiT / Talker├── T_vocoder / Code2Wav├── T_queue├── T_transport└── T_host_dispatch / syncAgent 在动代码前至少应该回答:
- 当前 critical path 是哪个 stage?
- stage 内是 GPU compute 慢,还是 host 没把 GPU 喂饱?
- queue-to-terminal 时间有多少是真 compute,有多少是排队?
- kernel launch gap、CPU thread saturation、CUDA Graph replay hit rate 是否异常?
- 优化目标是 TTFT、TTFA、ITL、RTF、吞吐还是尾延迟?
例如看到 GPU utilization 很低时,不应该自动得出“kernel 需要优化”。可能的因果链反而是:
CPU dispatch 饱和 ↓kernel launch 间隔变大 ↓GPU 出现 bubble ↓GPU utilization 低这时去改 GEMM kernel 往往没有意义。
2. Profile 不是截图,而是因果归因的起点
Section titled “2. Profile 不是截图,而是因果归因的起点”一个好的 profile 应该同时覆盖:
- GPU kernel / CUDA API;
- stage queue 与 admission;
- scheduler thread;
- CPU preprocessing;
- transport / relay;
- batch size 与 shape 分布;
- graph capture / replay 命中;
- request-level TTFT / TTFA / ITL / E2E。
真正有用的问题通常是:
“为什么这个时间花在这里?”
而不是:
“哪个函数在 profiler 里颜色最深?”
Qwen3-Omni 的公开优化工作已经展示了很多这种归因方式:有的瓶颈最终落在 host dispatch,有的落在 Thinker→Talker 的小消息通路,有的落在 Code2Wav 的同步 D2H,而不是单一大 kernel。
3. A/A 先于 A/B:先知道噪声底有多大
Section titled “3. A/A 先于 A/B:先知道噪声底有多大”多阶段 serving 的 benchmark 很容易受以下因素影响:
- GPU boost / thermal state;
- CPU 抢占;
- batch composition;
- request arrival timing;
- allocator / cache warmup;
- colocated process 干扰;
- CUDA Graph shape 命中差异。
因此在宣称“+5%”之前,应该先做 A/A:
A/A↓同一版本、同一配置重复测↓估计 noise floor
A/B↓只有 effect size 明显超过 noise floor 才 claim建议至少采用:
- counter-balanced 顺序:
AB / BA / BA / AB; - fresh server 或严格一致的 warmup;
- 相同数据集、并发度、sampling contract;
- 记录每轮而不是只报平均值;
- 对高噪声 cell 明确标记“not promotion-capable”。
如果 A/A 自己能抖 8%,那么一个 +3% 的 A/B 不应该被包装成性能收益。
4. Isolated 与 E2E 必须分开报
Section titled “4. Isolated 与 E2E 必须分开报”这是性能工程中最容易被忽略的原则。
一个优化可能在局部完全成立:
某 stage replay +4%某 vocoder batch +3×某 kernel 数量 -160但端到端可能几乎不变。
原因就是 Amdahl 定律与 pipeline critical path:
因此报告应至少分成两层:
Mechanism / isolated evidence
Section titled “Mechanism / isolated evidence”回答:
- 优化机制是否真的发生?
- kernel 数量是否减少?
- graph replay 是否命中?
- stage latency / throughput 是否改善?
End-to-end evidence
Section titled “End-to-end evidence”回答:
- request throughput 是否改善?
- TTFT / TTFA / ITL 是否改善?
- p95 / p99 RTF 是否改善?
- 是否把压力推给了下游 stage?
公开的 Qwen3-Omni predictor GQA 工作就是一个很好的例子:局部 replay 有稳定的几个百分点提升,同时明确报告 E2E 基本落在噪声带内。这样的“E2E-neutral”结果同样有价值,因为它证明了机制成立,但当前不在系统 critical path。
5. CUDA Graph 优化的关键不是“开 graph”,而是 shape contract
Section titled “5. CUDA Graph 优化的关键不是“开 graph”,而是 shape contract”很多 serving 系统已经支持 CUDA Graph,但真实 replay hit rate 仍然很低。
原因通常不是 graph 本身慢,而是:
真实请求 shape ↓不断变化的 batch / chunk / sequence length ↓和 captured keys 对不上 ↓频繁 eager fallback所以应该先测:
- 每种 batch size 的出现频率;
- 每种 sequence/chunk shape 的出现频率;
- capture key coverage;
- replay hit / miss reason;
- eager fallback 的 host overhead。
优化方向往往是:
真实 workload ↓设计 bucket / chunk policy ↓让 scheduler 输出靠近 captured shape ↓提高 replay hit rate而不是无限增加 captured graph 数量。
Qwen3-Omni Code2Wav 的 chunk-aligned dispatch 就是这一思想的典型实现:先把每次处理工作量规整成固定 chunk,再让 batch bucket × frame bucket 真正可复用 CUDA Graph。
6. Batching 的前提:请求必须能在同一个 shape contract 上相遇
Section titled “6. Batching 的前提:请求必须能在同一个 shape contract 上相遇”“并发很高”并不自动意味着 batching 有效。
典型失败模式:
request A backlog = 10 framesrequest B backlog = 17 framesrequest C backlog = 31 frames ↓shape 全不同 ↓几乎无法形成高效 batch常见解决方式有两类:
Padding-aware batching
Section titled “Padding-aware batching”适合允许变长输入的 stage:
相近长度请求 ↓padding waste gate ↓pad 到同一 shape ↓batched forwardCosyVoice3 HiFT batching 属于这一类。
Chunk-aligned batching
Section titled “Chunk-aligned batching”适合 streaming window:
variable backlog ↓每轮只消费固定 chunk ↓uniform windows ↓batched graph replayQwen3-Omni Code2Wav 属于这一类。
因此一个成熟 Agent 不应该只调 max_batch_size,而应该一起研究:
- batch wait;
- bucket size;
- padding waste;
- chunk size;
- graph key;
- admission policy。
7. compile 与 TensorRT:默认值不能只由最快结果决定
Section titled “7. compile 与 TensorRT:默认值不能只由最快结果决定”一个后端即使 isolated benchmark 更快,也不一定适合作为默认路径。
决策至少应该考虑:
| 维度 | 问题 |
|---|---|
| 性能 | isolated / E2E 提升多少? |
| 稳定性 | 动态 shape / fallback 是否可靠? |
| 正确性 | 输出、WER、音质是否保持? |
| 环境 | 是否需要额外 TensorRT / engine 构建依赖? |
| 启动成本 | compile/capture/build 时间有多大? |
| 可维护性 | 模型升级后是否容易失效? |
所以更合理的流程是:
eager / compile / TensorRT ↓同一 paired benchmark contract ↓correctness + quality gate ↓再决定 default / opt-in而不是“最快的那个直接默认开启”。
8. 正确性 gate 必须和性能 gate 同级
Section titled “8. 正确性 gate 必须和性能 gate 同级”对生成模型,正确性不能只看“没有 crash”。
根据修改层级,应选择不同 gate:
LLM / AR
Section titled “LLM / AR”- token 序列;
- output token count;
- deterministic sampling parity;
- cache 生命周期。
- WER / CER;
- 长音频是否截断;
- chunk seam 是否丢词;
- timestamp / segment ordering。
- waveform / codec token;
- WER 反向验证;
- speaker / audio quality 指标;
- chunk ordering 与 terminal semantics。
Streaming
Section titled “Streaming”除了 TTFA,还必须测:
- inter-chunk latency(ITL);
- message count / ordering;
- terminal flush;
- abort / disconnect behavior。
有些 overlap 优化会降低线程阻塞,却把一个 chunk 延迟到下一个 production interval;如果只看 throughput,就会错过真实用户体验退化。
9. 复现实验要控制 host 环境,而不只是 GPU 型号
Section titled “9. 复现实验要控制 host 环境,而不只是 GPU 型号”多阶段 serving 中 CPU 是正式性能资源。
因此“同样是 H100”远远不够,还应记录:
- CPU affinity / isolation;
- NUMA;
- colocated process;
- PyTorch / CUDA / driver;
- model revision;
- scheduler 配置;
- graph/compile 开关;
- warmup;
- random seed / sampling mode。
如果目标问题本身就是 host dispatch 饱和,那么没有 CPU 隔离的 A/B 很容易被系统噪声污染。
对于需要做默认值决策的优化,最好要求至少一次独立环境复现,而不是只在开发者自己的机器上通过。
10. KDA Harness 应该做什么
Section titled “10. KDA Harness 应该做什么”一个面向 Agent 的性能 harness 最重要的不是“能跑 benchmark”,而是把实验纪律固化下来。
建议至少包含:
Experiment Spec├── base / candidate SHA├── hardware + software manifest├── workload / dataset├── concurrency cells├── warmup policy├── A/A noise gate├── paired A/B order├── isolated metrics├── E2E metrics├── correctness / quality gate└── artifact retentionAgent 的 judge 应该能拒绝:
- 没有 baseline 的“性能提升”;
- effect 小于 noise floor 的 claim;
- 只报 isolated、不报 E2E 的系统优化;
- 只报吞吐、不报 latency tail 的 serving 改动;
- 性能提升但 WER / correctness 退化的方案;
- benchmark contract 不一致的前后对比。
这样 Agent 才是在做 performance engineering,而不是 benchmark hill-climbing。
11. 推荐的 Agent 工作流
Section titled “11. 推荐的 Agent 工作流”可以把整套流程压缩成:
1. Profile ↓2. Attribute critical path ↓3. Write falsifiable hypothesis ↓4. Establish A/A noise floor ↓5. Make the smallest intervention ↓6. Run isolated mechanism test ↓7. Run paired E2E A/B ↓8. Run correctness / WER / quality gate ↓9. Reproduce on isolated environment ↓10. Merge only if evidence clears gate这里最重要的是第 3 步:假设必须可证伪。
例如好的假设是:
“CUDA Graph replay 低是因为 scheduler 常产生未捕获的 batch size;补齐对应 bucket 后 replay hit rate 应显著上升,同时 host launch overhead 下降。”
而不是:
“试试 CUDA Graph,也许会更快。”
12. 与 SGLang-Omni 公开工作的对应
Section titled “12. 与 SGLang-Omni 公开工作的对应”这套方法并不是抽象原则,在 SGLang-Omni 的公开工作中已经反复出现:
- CosyVoice3 Optimization Roadmap #1652:按 stage 拆 Runtime、AR、DiT、Vocoder 与 scheduler;
- CosyVoice3 Vocoder acceleration #1844:Flow/HiFT batching、padding waste 与 scheduler co-design;
- Qwen3-Omni Serving Optimization Tracker #1022:把 Thinker、pipeline handoff、Talker、Code2Wav 分轨推进;
- Qwen3-Omni Perf RFC #1018:强调 measurement contract、negative results 与 correctness gate;
- ASR Refactor #1267:说明当 abstraction boundary 本身错误时,应先重构 mechanism/policy 边界,再谈性能自动化。
它们共同指向同一个方向:
Agentic Performance Engineering 的核心不是自动生成代码,而是自动生成可信证据。