下面的代码从一个被解释为浮点数的零数组复制到另一个数组,并打印此操作的时间.正如我已经看到许多情况,其中无操作循环只是被编译器(包括
gcc)优化掉了,我在等待更改我的复制数组程序的某些时候,它将停止进行复制.
#include <iostream> #include <cstring> #include <sys/time.h> static inline long double currentTime() { timespec ts; clock_gettime(CLOCK_MONOTONIC,&ts); return ts.tv_sec+(long double)(ts.tv_nsec)*1e-9; } int main() { size_t W=20000,H=10000; float* data1=new float[W*H]; float* data2=new float[W*H]; memset(data1,W*H*sizeof(float)); memset(data2,W*H*sizeof(float)); long double time1=currentTime(); for(int q=0;q<16;++q) // take more time for(int k=0;k<W*H;++k) data2[k]=data1[k]; long double time2=currentTime(); std::cout << (time2-time1)*1e+3 << " ms\n"; delete[] data1; delete[] data2; }
我用g 4.8.1命令g main.cpp -o test -std = c 0x -O3 -lrt编译了这个.这个程序为我打印6952.17毫秒. (我不得不设置ulimit -s 2000000,以免崩溃.)
我还尝试使用新的自动VLA更改数组的创建,删除memset,但这不会改变g行为(除了更改时间几次).
似乎编译器可以证明这段代码不会做任何合理的事情,那么为什么不优化循环呢?
解决方法
无论如何,这不是不可能的(铿锵3.3版):
clang++ main.cpp -o test -std=c++0x -O3 -lrt
该程序为我打印0.000367毫秒……并查看汇编语言:
... callq clock_gettime movq 56(%rsp),%r14 movq 64(%rsp),%rbx leaq 56(%rsp),%rsi movl $1,%edi callq clock_gettime ...
而对于g:
... call clock_gettime fildq 32(%rsp) movl $16,%eax fildq 40(%rsp) fmull .LC0(%rip) faddp %st,%st(1) .p2align 4,10 .p2align 3 .L2: movl $1,%ecx xorl %edx,%edx jmp .L5 .p2align 4,10 .p2align 3 .L3: movq %rcx,%rdx movq %rsi,%rcx .L5: leaq 1(%rcx),%rsi movss 0(%rbp,%rdx,4),%xmm0 movss %xmm0,(%rbx,4) cmpq $200000001,%rsi jne .L3 subl $1,%eax jne .L2 fstpt 16(%rsp) leaq 32(%rsp),%rsi movl $1,%edi call clock_gettime ...
编辑(g v4.8.2 / clang v3.3)
消息代码 – 原始版本(1)
... size_t W=20000,H=10000; float* data1=new float[W*H]; float* data2=new float[W*H]; ...
... const size_t W=20000; const size_t H=10000; float data1[W*H]; float data2[W*H]; ...
现在未优化的情况是(1)g