使用模运算做数组索引出现10倍性能损耗问题咨询
性能差异核心原因分析
- 下标位置的模运算阻断了编译器优化,拉长了执行依赖链
当% size放在下标计算逻辑中时:- 编译器单独编译函数时,无法假设运行时传入的
jump恒为0、size非零,因此无法将currentIndex优化为恒定值0 - 数组访存的地址完全依赖模运算的输出结果,CPU必须等模运算执行完成才能发起内存读取请求,即使L1缓存命中也需要额外等待多个周期,流水线无法做超标量重排优化,执行效率极低
- 移除
% size后,currentIndex恒等于初始值0,编译器可以直接将array[0]预加载到寄存器中,后续5亿次循环全部为寄存器操作,不需要重复访存,速度自然提升10倍以上
- 编译器单独编译函数时,无法假设运行时传入的
- 取值后的模运算没有访存依赖,开销可忽略
当你把模运算挪到数组取值之后total += array[currentIndex] % size时:- 此时
currentIndex没有模运算逻辑,编译器可以直接确定其恒定为0,会将array[0]的值提前加载到寄存器 - 后续循环的模运算仅针对寄存器内的固定值执行,没有访存依赖,arm64架构下的模运算仅需3-4个单周期指令即可完成,流水线可以满负荷执行,所以整体性能差异几乎感知不到
- 此时
- 补充验证方法
你可以给函数加上static修饰,同时在同一编译单元内调用且显式传入jump=0的常量,开启全程序优化(LTO),此时编译器可以感知到jump恒为0,会自动优化掉% size的开销,两者性能差异会消失。
内容的提问来源于stack exchange,提问作者Pop Flamingo
相关产品推荐
相关产品推荐

