AI芯片算子融合为何反而变慢?寄存器压力怎么控?
扫描二维码
随时随地手机看文章
少一次回写、少一次读回,按理说融合应更快,可很多内核一融合反而掉速,问题常不在算子数学,而在活跃状态被拉得太长。AI芯片做编译优化时,最容易高估的不是融合收益,而是寄存器和片上暂存能否接住融合后的活跃值。
算子融合的第一层收益很明确:中间张量不落片外,访存带宽下降,调度开销也少。但每多拼进一个算子,输入、输出、临时变量、索引和部分和的生命周期都会延长。原本在单核内只需短暂存在的值,融合后可能跨多个阶段同时活跃,寄存器分配压力会迅速上升,最终逼得编译器把一部分值溢写到局部存储甚至更远处。
一旦溢写发生,融合节省的带宽就会被自己制造的新访存重新吃回去。更糟的是,溢写通常伴随更多地址计算、更多同步点和更复杂的调度依赖,看起来只是多了几次 store 和 load,实际却会把流水线占用率整体拖低。某些内核最终并不是算得慢,而是大量周期都花在给融合后过长的活跃集腾位置。
寄存器压力还会以更隐蔽的方式伤吞吐。很多加速器的并行度和寄存器占用直接挂钩,单个线程块、warp 或 tile 若拿走太多寄存器,可同时驻留的并发单元数就会下降。于是即便每个实例的局部访存减少了,整体机器却失去了靠更多并发隐藏延迟的能力,最终 wall time 反而更长。
对AI芯片编译器来说,最难的是给融合划出“够深但不过深”的边界。激活、偏置和简单归一化往往很适合靠近主算子融合,可涉及大范围归约、复杂索引变换或需要额外 workspace 的步骤,就未必适合强行塞进同一内核。真正高效的策略常常不是一味加深,而是在收益开始被寄存器和指令压力抵消前主动收手。
局部回退拆分通常比整体否定融合更有效。比如保留前后端容易复用的数据路径,只把最吃寄存器的那一小段拆出去单跑,或改变计算次序缩短某些中间值的存活时间。这样既能保住主要访存收益,又不至于让内核因为活跃集爆炸而全面失速。
分析融合失速时,别只看总访存量下降了多少,还要看寄存器占用、溢写字节数、并发驻留数和指令缓存命中变化。只要这些指标一起看,就能很快分清是带宽真的省下来了,还是寄存器先被压穿了。
代码体积也是常被忽略的副作用。融合层次一深,生成内核里的分支、地址计算和谓词控制都会增长,前端取指与解码压力也跟着上来。再叠加谓词执行和向量重排,部分后端即便算子数减少,也会因发射效率下降而失掉本该到手的并行度,这类退化在长链融合里尤其明显。某些场景哪怕没发生明显溢写,也会因为指令流过重而把理论收益磨掉一截。调试时若只看算子级统计,还常会把前端发射受限误认成带宽问题。
所以,融合反而变慢,往往不是优化方向错了,而是活跃值生命周期没有被管住。把融合边界围着寄存器压力来画,编译收益才不会在执行阶段被吐回去。





