我有四个嵌套for循环,如下所示:
const size_t nMax = 300 ; double acc = 0 ;
for( size_t i=0 ; i<nMax ; i++ ) {
for( size_t j=0 ; j<nMax ; j++ ) {
for( size_t k=0 ; k<nMax ; k++ ) {
for( size_t l=k ; l<nMax ; l++ ) {
acc += 1.0 ;
}
}
}
}
printf( "Accumulator is %f\n", acc ) ;
使用gcc
(版本5.4.0)和-O3
进行编译,代码在5.188秒内完成。现在,如果我重新排序循环
const size_t nMax = 300 ; double acc = 0 ;
for( size_t k=0 ; k<nMax ; k++ ) {
for( size_t l=k ; l<nMax ; l++ ) {
for( size_t i=0 ; i<nMax ; i++ ) {
for( size_t j=0 ; j<nMax ; j++ ) {
acc += 1.0 ;
}
}
}
}
printf( "Accumulator is %f\n", acc ) ;
再次使用-O3
进行编译,代码运行时间为3.500秒。我不确定为什么会这样:我在第二个代码段得到它,l
上的循环检查外部循环的值,开始条件nMax * nMax
次的频率低于第一个代码段,但似乎不太可能(?)这会产生如此显着的性能损失。
使用-O2
进行编译会使两个代码在相同的时间内执行(大约5.2秒),因此我设法追踪-ftree-vectorize
作为可与{{1}一起使用的标记恢复性能差异。
为什么-O2
可以优化第二个代码段而不是第一个?
修改
使用-ftree-vectorize
添加了代码的汇编版本。我对汇编程序一无所知,所以不能真正声称理解很多。这是第一个(慢)段:
gcc -O2 -ftree-vectorize
和第二个(快速)版本:
.file "code_one.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC2:
.string "Accumulator is %f\n"
.section .text.unlikely,"ax",@progbits
.LCOLDB3:
.section .text.startup,"ax",@progbits
.LHOTB3:
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB38:
.cfi_startproc
pxor %xmm0, %xmm0
xorl %ecx, %ecx
movapd .LC1(%rip), %xmm1
.L2:
movq %rcx, %rsi
.L8:
movhpd .LC0(%rip), %xmm0
xorl %edx, %edx
.p2align 4,,10
.p2align 3
.L6:
movl $300, %eax
.p2align 4,,10
.p2align 3
.L3:
subq $1, %rax
addpd %xmm1, %xmm0
jne .L3
addl $1, %edx
cmpl $150, %edx
jne .L6
movdqa %xmm0, %xmm2
addq $1, %rsi
cmpq $300, %rsi
psrldq $8, %xmm2
addpd %xmm2, %xmm0
jne .L8
addq $1, %rcx
cmpq $300, %rcx
jne .L2
subq $8, %rsp
.cfi_def_cfa_offset 16
movl $.LC2, %esi
movl $1, %edi
movl $1, %eax
call __printf_chk
xorl %eax, %eax
addq $8, %rsp
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE38:
.size main, .-main
.section .text.unlikely
.LCOLDE3:
.section .text.startup
.LHOTE3:
.section .rodata.cst8,"aM",@progbits,8
.align 8
.LC0:
.long 0
.long 0
.section .rodata.cst16,"aM",@progbits,16
.align 16
.LC1:
.long 0
.long 1072693248
.long 0
.long 1072693248
.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609"
.section .note.GNU-stack,"",@progbits