在什么情况下“unroll-loops”不会使结果代码更快?

时间:2013-06-17 23:00:00

标签: c

取自GCC手册:

-funroll-loops
           Unroll loops whose number of iterations can be determined at compile time or upon entry to the loop.
           -funroll-loops implies -frerun-cse-after-loop.  This option makes code larger, and may or may not make it
           run faster.

根据我的理解,unroll循环将删除结果代码中的分支指令,我认为它对CPU管道更健康。

但为什么它“可能不会让它跑得更快”?

6 个答案:

答案 0 :(得分:5)

首先,它可能没有任何区别;如果您的条件是“简单”并且执行多次,则分支预测器应该快速拾取并始终正确预测分支直到循环结束,使“滚动”代码的运行速度几乎与展开的代码一样快。

此外,在非流水线CPU上,分支的成本非常小,因此这种优化可能不相关,代码大小考虑可能更重要(例如,在编译微控制器时 - 请记住gcc目标范围从AVR微型到超级计算机)。

另一种展开无法加速循环的情况是循环体比循环本身慢得多 - 例如,你在body循环中有一个系统调用,与系统调用相比,循环开销可以忽略不计。

至于何时可能使代码运行速度变慢,使代码变大可能会降低代码速度 - 如果您的代码不再适合缓存/内存页面/ ...您将拥有缓存/页面/。 ..故障,处理器必须等待内存在执行代码之前获取代码。

答案 1 :(得分:1)

到目前为止,答案非常好,但我还要添加一个尚未涉及的内容:吃掉分支预测器插槽。如果你的循环包含一个分支,并且它没有展开,它只消耗一个分支预测器槽,因此它不会驱逐cpu在外部循环,姐妹循环或调用者中做出的其他预测。但是,如果通过展开多次复制循环体,则每个副本将包含一个消耗预测器槽的单独分支。这种性能损失很容易被忽视,因为与缓存逐出问题一样,它在循环性能的大多数隔离的人工测量中都不可见。相反,它会表现为损害其他代码的性能。

作为一个很好的例子,x86上最快的strlen(甚至比我见过的最好的asm更好)是一个疯狂展开的循环,只是这样做:

if (!s[0]) return s-s0;
if (!s[1]) return s-s0+1;
if (!s[2]) return s-s0+2;
/* ... */
if (!s[31]) return s-s0+31;

然而,这将撕裂分支预测器时隙,因此出于实际目的,某种矢量化方法更可取。

答案 2 :(得分:1)

我不认为用条件退出填充展开的循环是很常见的。这打破了展开允许的大多数指令调度。更常见的是事先检查循环在进入展开部分之前至少剩余n次迭代。

为了实现这一点,编译器可以生成精细的前同步码和后同步码以对齐循环数据以获得更好的矢量化或更好的指令调度,并处理剩余的迭代,这些迭代不会均匀地分配到循环的展开部分。

可能结果(最坏的情况)循环只运行零次或一次,或者在特殊情况下运行两次。然后只会执行循环的一小部分,但是会执行许多额外的测试来实现。更差;对齐前同步码可能意味着不同的分支条件在不同的调用中发生,导致额外的分支误预测停顿。

这些都是为了在大量迭代中取消,但对于短循环,这不会发生。

除此之外,您还拥有增加的代码大小,其中所有这些展开的循环共同有助于降低icache效率。

有些架构使用内部缓冲区的特殊情况非常短的循环,甚至没有引用缓存。

现代体系结构具有相当广泛的指令重新排序,即使在内存访问时也是如此,这意味着即使在最好的情况下,编译器对循环的重新排序也可能没有额外的好处。

答案 3 :(得分:0)

例如,展开的函数体大于缓存。从记忆中读取的速度显然较慢。

答案 4 :(得分:0)

假设您有一个包含25条指令的循环并且迭代1000次。处理25,000条指令所需的额外资源可以很好地覆盖分支引起的痛苦。

同样重要的是要注意,许多种类的循环分支都非常无痛,因为CPU在简单情况下已经非常擅长分支预测。例如,8次迭代可能更有效地展开,但即使50次也可能更好地留给CPU。请注意,编译器可能更好地猜测哪个优于您。

答案 5 :(得分:-1)

展开循环应始终使代码更快。在更快的代码和更大的代码占用空间之间进行权衡。执行了大量次数的紧循环(在循环体中执行的相对少量的代码)可以通过删除所有循环开销并允许流水线操作来完成展开而受益。经历多次迭代的循环可以展开大量的额外代码 - 更快但可能无法接受的更大的占用空间。在体内进行大量循环的循环可能无法从展开中获益 - 与其他所有东西相比,循环开销变得很小。