打开whisper.cpp的whisper_state结构体,你会看到六个int64_t计时字段和五个int32_t计数器,它们静静地躺在结构体的最顶部——比 KV cache、比 decoder 数组、比 mel 频谱数据都靠前。这个布局不是偶然的。在一个超过 9000 行的源码文件中,性能计时字段被放在whisper_state的第一行,这本身就是一个强烈的工程信号:对于一个高性能推理引擎来说,知道自己慢在哪里,比知道自己能做什么更重要。
但真正让我愣住的,不是这些字段的位置——而是whisper_decode_internal函数尾部那段看似平淡无奇的分支逻辑。当一次 decode 调用结束时,whisper.cpp 并没有简单地把耗时累加到一个统一的t_decode_us上,而是根据batch.n_tokens的数量,把同一个函数的耗时精确地分流到了三个完全不同的计时桶里:n_tokens == 1走t_decode_us(逐 token 生成),n_tokens < 16走t_batchd_us(小批量解码),n_tokens >= 16走t_prompt_us(prompt 处理)。同一个函数、同一段代码路径,仅凭输入 token 数量的不同,就被归入了三个截然不同的性能分类——这种设计的精细程