我看到相同C ++代码的性能降低15%,这些代码编译为完全相同的机器指令但位于不同对齐的地址上。当我的微小主循环从0x415220开始时,它比在0x415250时更快。我在Intel Core2 Duo上运行它。我在x86_64 Ubuntu上使用gcc 4.4.5。
任何人都可以解释减速原因以及如何强制gcc最佳地对齐循环吗?
以下是具有探查器注释的两种情况的反汇编:
415220 576 12.56% |XXXXXXXXXXXXXX 48 c1 eb 08 shr $0x8,%rbx 415224 110 2.40% |XX 0f b6 c3 movzbl %bl,%eax 415227 0.00% | 41 0f b6 04 00 movzbl (%r8,%rax,1),%eax 41522c 40 0.87% | 48 8b 04 c1 mov (%rcx,%rax,8),%rax 415230 806 17.58% |XXXXXXXXXXXXXXXXXXX 4c 63 f8 movslq %eax,%r15 415233 186 4.06% |XXXX 48 c1 e8 20 shr $0x20,%rax 415237 102 2.22% |XX 4c 01 f9 add %r15,%rcx 41523a 414 9.03% |XXXXXXXXXX a8 0f test $0xf,%al 41523c 680 14.83% |XXXXXXXXXXXXXXXX 74 45 je 415283 ::Run(char const*, char const*)+0x4b3> 41523e 0.00% | 41 89 c7 mov %eax,%r15d 415241 0.00% | 41 83 e7 01 and $0x1,%r15d 415245 0.00% | 41 83 ff 01 cmp $0x1,%r15d 415249 0.00% | 41 89 c7 mov %eax,%r15d
415250 679 13.05% |XXXXXXXXXXXXXXXX 48 c1 eb 08 shr $0x8,%rbx 415254 124 2.38% |XX 0f b6 c3 movzbl %bl,%eax 415257 0.00% | 41 0f b6 04 00 movzbl (%r8,%rax,1),%eax 41525c 43 0.83% |X 48 8b 04 c1 mov (%rcx,%rax,8),%rax 415260 828 15.91% |XXXXXXXXXXXXXXXXXXX 4c 63 f8 movslq %eax,%r15 415263 388 7.46% |XXXXXXXXX 48 c1 e8 20 shr $0x20,%rax 415267 141 2.71% |XXX 4c 01 f9 add %r15,%rcx 41526a 634 12.18% |XXXXXXXXXXXXXXX a8 0f test $0xf,%al 41526c 749 14.39% |XXXXXXXXXXXXXXXXXX 74 45 je 4152b3 ::Run(char const*, char const*)+0x4c3> 41526e 0.00% | 41 89 c7 mov %eax,%r15d 415271 0.00% | 41 83 e7 01 and $0x1,%r15d 415275 0.00% | 41 83 ff 01 cmp $0x1,%r15d 415279 0.00% | 41 89 c7 mov %eax,%r15d
答案 0 :(得分:4)
Gcc有一个 -falign-loops = n 选项,其中 n 是要跳过的最大字节数,如果省略,则默认设置为使用。 Gcc在 -O2 和 -O3 优化级别自动启用此功能。
答案 1 :(得分:2)
在具有循环流检测的英特尔CPU上,循环体代码对齐可以提高效率,尤其是在正常的展开水平下。 首次从顶部进入循环时,对齐会受到惩罚。 你没有在那里显示代码,在对齐的案例中会有一些荒谬的美化无操作指令。 gcc通常使用条件对齐,仅在需要有限数量的填充的情况下才应用对齐。当我查看一次时,影响这种行为的选项看起来并不是很有效。正如亚历山大所说,为-march或-mtune设置一个值非常重要,这样gcc就可以使用相关的对齐设置。 我使用的所有编译器都无法在某些情况下对齐循环体,并且似乎无法控制它。