与Jam(循环合并))
MLIR的Unrolling(循环展开)与Jam(循环合并)从一次性能调优的“翻车”说起去年调一个AI推理引擎的卷积算子,手写了一个循环展开的pass,信心满满地跑benchmark——结果延迟反而涨了15%。当时盯着MLIR的IR dump看了三个小时,发现循环展开后寄存器压力爆了,L1 cache miss率从2%飙到18%。后来同事路过看了一眼,说:“你试试先做循环合并,再展开。”改了一行pass顺序,性能直接翻倍。那次之后我才真正理解:Unrolling和Jam不是两个孤立的变换,它们像一对双胞胎,配合不好就是灾难,配合好了就是性能核弹。循环展开:别让“展开因子”成为玄学MLIR里做循环展开,最直接的是用loop.unroll操作。但很多人上来就写unroll(factor=4),然后祈祷性能提升——这是典型的“调参工程师”思维。// 别这样写:无脑展开4倍 scf.for %i = 0 to 1024 step 1 { %a = load %A[%i] %b = load %B[%i] %c = add %a, %b store %c, %C[%i] }展开成4倍后,每个迭代体里塞了4组load/add/store。看起来并行度高了,但如果你跑在ARM Cortex-A53这种弱乱序执行的核上,4个load同时发射,内存带宽直接打满,后续的add