【发布时间】:2015-11-30 23:19:33
【问题描述】:
page 推荐“循环展开”作为优化:
可以通过减少迭代次数来减少循环开销 复制循环体。
示例:
在下面的代码片段中,可以复制循环体 一次,迭代次数可以从100次减少到50次。
for (i = 0; i < 100; i++) g ();下面是循环展开后的代码片段。
for (i = 0; i < 100; i += 2) { g (); g (); }
在 GCC 5.2 中,除非您使用 -funroll-loops(在 -O2 或 -O3 中未启用),否则不会启用循环展开。我检查了组件,看看是否有显着差异。
g++ -std=c++14 -O3 -funroll-loops -c -Wall -pedantic -pthread main.cpp && objdump -d main.o
版本 1:
0: ba 64 00 00 00 mov $0x64,%edx
5: 0f 1f 00 nopl (%rax)
8: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # e <main+0xe>
e: 83 c0 01 add $0x1,%eax
# ... etc ...
a1: 83 c1 01 add $0x1,%ecx
a4: 83 ea 0a sub $0xa,%edx
a7: 89 0d 00 00 00 00 mov %ecx,0x0(%rip) # ad <main+0xad>
ad: 0f 85 55 ff ff ff jne 8 <main+0x8>
b3: 31 c0 xor %eax,%eax
b5: c3 retq
版本 2:
0: ba 32 00 00 00 mov $0x32,%edx
5: 0f 1f 00 nopl (%rax)
8: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # e <main+0xe>
e: 83 c0 01 add $0x1,%eax
11: 89 05 00 00 00 00 mov %eax,0x0(%rip) # 17 <main+0x17>
17: 8b 0d 00 00 00 00 mov 0x0(%rip),%ecx # 1d <main+0x1d>
1d: 83 c1 01 add $0x1,%ecx
# ... etc ...
143: 83 c7 01 add $0x1,%edi
146: 83 ea 0a sub $0xa,%edx
149: 89 3d 00 00 00 00 mov %edi,0x0(%rip) # 14f <main+0x14f>
14f: 0f 85 b3 fe ff ff jne 8 <main+0x8>
155: 31 c0 xor %eax,%eax
157: c3 retq
版本 2 产生 更多 次迭代。我错过了什么?
【问题讨论】:
-
是否愿意发布该代码的源代码以获得更好的答案?
-
IMO,最好把它留给编译器来展开循环。甚至英特尔都表示最好保持循环展开。 software.intel.com/en-us/articles/avoid-manual-loop-unrolling
-
我认为这个例子是为了展示这个想法。像本例那样花费开发时间优化代码是非常昂贵的。
-
示例 2 如何产生更多的迭代?循环计数器加 2,因此循环执行次数减半。编译器可能复制了循环中的代码,但没有增加迭代次数。 迭代和循环代码内容的巨大区别.
-
唯一的方法是分析你的代码。循环展开可能会有所帮助,因为它减少了跳转次数,或者可能会因为较大的循环体不再全部在缓存中而造成伤害。
标签: c++ optimization g++ compiler-optimization loop-unrolling