我正在学习循环展开以避免因依赖性而导致的停顿。我在互联网和文献中发现了很多例子,但我没有找到关于算法如何用于获得优化代码的解释(当然,如果有一个这样的算法)。特别是,我不知道如何确定循环展开的次数。可以事先计算出来吗?
答案 0 :(得分:1)
您在编写编译器吗?否则你真的不应该自己循环展开。你最有可能信任编译器为你做适当的循环展开,它发现它适用。
答案 1 :(得分:1)
经验法则是你放松以便:
基本上只要您可以投入更多资源就可以展开,而当您无法衡量任何性能提升时就会停止。
答案 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%的改进。
更好的配对 - 在具有多个流水线的架构(或准配对,例如寄存器重命名和微码生成)上,展开可以提供更好的配对机会。同样,只有当环体很小时它们才会引人注目,但公式不能像上面那样简单。
展开并非无害 - 请记住,即使在“好”情况下展开也几乎会使循环的代码大小翻倍。这可能会从缓存中清除其他代码或数据。在现代桌面体系结构中,代码大小问题足够严重,因此经验法则是全局优化代码大小,并优化速度仅限本地热点。