【发布时间】:2026-01-10 15:05:01
【问题描述】:
我有一个简单的代码,它对数组中的元素求和并返回它们:
// Called with jump == 0
int performance(int jump, int *array, int size) {
int currentIndex = 0;
int total = 0;
// For i in 1...500_000_000
for (int i = 0; i < 500000000; i++) {
currentIndex = (currentIndex + jump) % size;
total += array[currentIndex];
}
return total;
}
我注意到一个奇怪的行为:% size 的存在对性能有非常大的影响(约慢 10 倍),即使 jump 是 0,所以它不断地访问相同的数组元素 (0)。只需删除 % size 就能大大提高性能。
我原以为这只是产生这种差异的模计算,但现在说我用 total += array[currentIndex] % size; 替换我的 sum 行(因此也计算模)性能差异几乎不明显。
我在 arm64 机器上使用 -O3 和 clang 编译它。
这可能是什么原因造成的?
【问题讨论】:
-
你的反汇编是什么样子的?
-
@old_timer 你可以在这里找到这两个文件:gist.github.com/PopFlamingo/abe364eabcadc78576ea9c1b2d642b1e
-
@old_timer 我在这里用 -Os 编译了它们,但性能差异是一样的
-
外部链接在这里几乎没用,如果它不符合问题(在*站点/服务器上),那么它基本上不存在。除法是一项非常昂贵的操作,模数可能会或可能不会增加更多,无论是库还是指令,所以这并不令人惊讶,但反汇编可能会显示出比除法/模数更多的成本。
-
您应该计算
jump %= size,然后计算i=min(i+jump,i+jump-size),所有变量均无符号,以获得更好的模数吞吐量。
标签: c performance assembly arm64