ARM Cortex-A72 CPU循环执行周期远超预期的原因排查
同迭代指令依赖链与F0端口独占的叠加约束
你仅统计了端口资源的吞吐量上限,忽略了单次迭代内的写后读(RAW)依赖链长度,叠加F0端口是唯一支持ASIMD乘法操作的端口这一硬件限制,所有乘法指令必须在F0端口顺序执行:2条mul指令各占2个F0周期,4条smull/smlal指令各占1个F0周期,合计占满F0端口8个周期。而mul->smull->uzp2之间存在严格的数据依赖,后续指令必须等待前序乘法的结果输出才能发射,进一步把执行下限拉高到8周期以上,叠加uzp2和str的操作延迟,理论执行下限已经高于你预期的8周期。ASIMD Load-to-Use互锁惩罚
Cortex-A72硬件上存在ASIMD寄存器加载后直接用于算术运算的额外惩罚:从L1缓存加载数据到ASIMD寄存器后,若下一个周期就将其作为ASIMD算术指令的源操作数,会产生1~2周期的流水线停顿。你的代码中ldr q3/ldr q4之后直接紧跟mul指令使用加载结果,没有插入无关指令填补延迟间隙,带来了额外的停顿开销。L1数据缓存带宽限制
Cortex-A72的L1数据缓存每个周期最多支持1次128bit的load或store操作,你单次迭代包含2次128bit load、1次128bit store,合计需要3个缓存访问周期,这部分开销无法通过并行压缩,进一步抬高了执行周期下限。乱序调度窗口大小限制
Cortex-A72的乱序发射窗口容量有限,对于你的小循环场景,同一时间窗口内能够重排序的指令数量有限,无法完全将后续迭代的load、整数运算和当前迭代的乘法运算充分重叠,导致F0端口偶尔出现空闲,没法达到理论上的满负载状态。
你使用LD1/ST1指令后性能提升,正是因为这类向量加载/存储指令减少了指令总数,降低了前端解码、发射的压力,同时减少了独立load操作的次数,间接降低了load-use惩罚的影响,但受限于F0端口的核心瓶颈和依赖链延迟,仍然无法达到8周期的理论值。
内容的提问来源于stack exchange,提问作者swineone

