应该循环多少次?

时间:2010-06-20 20:33:56

标签: optimization assembly dependencies

我正在学习循环展开以避免因依赖性而导致的停顿。我在互联网和文献中发现了很多例子,但我没有找到关于算法如何用于获得优化代码的解释(当然,如果有一个这样的算法)。特别是,我不知道如何确定循环展开的次数。可以事先计算出来吗?

4 个答案:

答案 0 :(得分:1)

您在编写编译器吗?否则你真的不应该自己循环展开。你最有可能信任编译器为你做适当的循环展开,它发现它适用。

答案 1 :(得分:1)

经验法则是你放松以便:

  • 操作在“自然”边界上完成4,8,16,32 .. bytes
  • 你没有引入过多的注册压力(即你没有开始将寄存器杂志放到内存中)
  • 你不会一遍又一遍地重复完全相同的指令序列

基本上只要您可以投入更多资源就可以展开,而当您无法衡量任何性能提升时就会停止。

答案 2 :(得分:1)

有时,展开循环(对于Core2和up处理器)甚至是有意义的,因为它们确实有一个“循环流检测器”(它们称之为LSD)。 请在英特尔优化指南中查阅。

如果代码确实适合(非常小的)队列,那么处理器不需要从L1-Instruction-Cache获取/解码指令,这可以提供一些性能。

答案 3 :(得分:0)

我想补充一下我的回复,因为虽然TorbjörnGyllebring的答案很好,但它并不完整IMO

由于展开,有不同的改进:

算法改进 - 例如您的指令集允许处理四个而不是一个字节。 Torbjörn完美地回答了这个问题。

当循环体很小时,

减少循环开销,循环开销(通常,增量+比较+跳转)会消耗大量时间。

total cost = N * (loop body + loop overhead)

展开一次,你得到

total cost = N/2 * (2 * loop body + loop overhead)  
           = N * loop body + N / 2 * loop overhead

如果循环开销与循环体相比较小,则展开将不会以增加代码大小为代价获得增益。示例:当循环体为10x循环开销时,展开最多可使您获得5%的改进。

更好的配对 - 在具有多个流水线的架构(或准配对,例如寄存器重命名和微码生成)上,展开可以提供更好的配对机会。同样,只有当环体很小时它们才会引人注目,但公式不能像上面那样简单。

展开并非无害 - 请记住,即使在“好”情况下展开也几乎会使循环的代码大小翻倍。这可能会从缓存中清除其他代码或数据。在现代桌面体系结构中,代码大小问题足够严重,因此经验法则是全局优化代码大小,并优化速度仅限本地热点。