循环展开&优化

时间:2012-04-09 21:56:18

标签: c optimization

鉴于代码:

for (int i = 0; i < n; ++i) 
{ 
  A(i) ; 
  B(i) ; 
  C(i) ; 
}

优化版本:

for (int i = 0; i < (n - 2); i+=3) 
{ 
  A(i) 
  A(i+1) 
  A(i+2) 
  B(i) 
  B(i+1) 
  B(i+2) 
  C(i) 
  C(i+1) 
  C(i+2)
}

我不清楚:哪个更好?我看不到任何使用其他版本的速度更快的东西。我在这里错过了什么吗?

我所看到的是每条指令都取决于之前的指令,这意味着 我需要等待上一条指令完成才能在...之后启动一条指令。

谢谢

5 个答案:

答案 0 :(得分:9)

在语言的高级视图中,您不会看到优化。速度增强来自编译器对你所拥有的功能。

在第一种情况下,它类似于:

LOCATION_FLAG;
DO_SOMETHING;
TEST FOR LOOP COMPLETION;//Jumps to LOCATION_FLAG if false

在第二个中它就像:

LOCATION_FLAG;
DO_SOMETHING;
DO_SOMETHING;
DO_SOMETHING;
TEST FOR LOOP COMPLETION;//Jumps to LOCATION_FLAG if false

在后一种情况下,您可以看到测试和跳转的开销仅为每3个指令。在第一个中,每1个指令1个;所以它经常发生。

因此,如果你有不变量,你可以依赖(mod 3的数组,使用你的例子),那么解开循环会更有效,因为底层程序集更直接地编写。

答案 1 :(得分:4)

循环展开用于减少跳跃次数和数量。分支指令可能会使循环更快但会增加二进制的大小。根据实施和平台,可能更快。

答案 2 :(得分:3)

那么,这段代码是“更好”还是“更差”完全取决于ABC的实现,您期望n的值,您正在使用哪个编译器以及您正在运行的硬件。

通常,循环展开的好处是减少了执行循环的开销(即,增加i并将其与n进行比较)。在这种情况下,可以减少3倍。

答案 3 :(得分:2)

只要函数A(),B()和C()不修改相同的数据集,第二个版本就会提供更多的并行化选项。

在第一个版本中,假设没有相互依赖性,三个函数可以同时运行。在第二个版本中,所有三个函数可以同时运行所有三个数据集,假设您有足够的执行单元来执行此操作,并且没有相互依赖性。

答案 4 :(得分:0)

一般来说,尝试“发明”优化并不是一个好主意,除非你有确凿的证据表明你会获得增加,因为很多时候你可能会最终引入降级。通常,获得此类证据的最佳方式是使用良好的分析器。我将使用分析器测试此代码的两个版本以查看差异。

此外,很多时候循环展开不是非常有用,如前所述,它在很大程度上取决于平台,编译器等。

您还可以使用编译器选项。一个有趣的gcc选项是“-floop-optimize”,你可以自动获得“-O,-O2,-O3和-Os”

编辑此外,请查看“-funroll-loops”编译器选项。