4

有人可以先解释一下展开循环(在 C/C++ 中)在什么时候成为有用的优化?

其次,与第一个问题相关,在什么时候不应该进一步展开展开?是否应该始终将展开操作拆分为 2 的幂的批次?或者它是否与您的 CPU 可以执行多少计算有关?一个比率是缓存行大小的乘数?ETC

例如,如果我有一个从 0 到 99 的 for 循环会更好/我如何确定哪个(除了反复试验)- 是否有科学方法:

  • 每个循环 0 到 49 和两个“操作”
  • 每个循环 0 到 24 和四个“操作”
  • 每个循环 0 到 19 和五个“操作”
  • 每个循环 0 到 9 和 10 个“操作”
4

1 回答 1

6

如果不提及Duff 的 Device,我不能让有关循环展开的问题长时间得不到解答。此实现与经典版本略有不同,但仍然有效。

假设您正在对一块内存应用掩码:

while (n-- > 0) {
    *ptr++ &= mask;
}

然后,可以像这样展开:

switch (n % 4) do {
case 0: *ptr++ &= mask;
case 3: *ptr++ &= mask;
case 2: *ptr++ &= mask;
case 1: *ptr++ &= mask;
} while ((n -= 4) > 0);

如果迭代跳转的成本占循环迭代内完成的工作成本的很大一部分,则循环展开很有用。一个好的优化编译器可以在足够的优化级别为您解决这个问题。如果您的编译器无法做到这一点,您只需要自己展开。

正如评论中提到的,一旦跳转的计算成本与展开的循环体的计算相比不再显着,就不需要展开。极端情况下,循环展开可能会导致指令缓存抖动,从而损害性能(类似于过度使用函数内联)。

于 2013-06-22T01:05:51.263 回答