[hellogcc] Re: [hellogcc] Re: [hellogcc] Re: [hellogcc] 请问下以下gcc -O0 和 -O1的代码运行时间不同的原因

  • From: Kito Cheng <kito@xxxxxxxxx>
  • To: hellogcc@xxxxxxxxxxxxx
  • Date: Tue, 30 Jul 2013 11:54:15 +0800

�@�拥倪B�m�y��在有 Hardware Prefetcher 下�K�]有�k法真的�y出你�A期中的�Y果

在前面的循�h中 Prefetcher 已��暖好�C了 �K且部份�Y料也存在 Cache 中

�е箩崦娲嫒」����^大的部份反而�绦��r�g�^短的�F象

��然上面提到的部份只是一��可能的原因,
���H上��需要考量到 Out-of-order execution 及 branch prediction 等等不同�C制的交互作用
因此�绦兴俣入y以由程式�绦械闹噶��的��硗��y

另外附上在我�C器上�绦械��r�g:
(Intel(R) Core(TM) i7-2620M)
 1, 47570681, 1
 2, 34476895, 2
 3, 32805033, 4
 4, 32431996, 8
 5, 32569370, 16
 6, 30123933, 32
 7, 19037866, 64
 8, 8754664, 128
 9, 3824499, 256
10, 1959867, 512
11, 1053159, 1024



Ref:
[1] Software and Hardware-Based Prefetching
http://www.ecs.umass.edu/ece/andras/courses/ECE668/Mylectures/Prefetching-lecture.ppt
[2] http://www.tomshardware.tw/305,review-305-7.html


2013/7/30 秦�� <love.infly@xxxxxxxxx>

> Hi, 吴伟
>
> 之前自己的问题是集中于两个汇编代码不同带来的性能不同的原因。
>
> 主要是O0代码在SIZE次循环和SIZE/2次循环的开销是2:1,但是O1代码的开销接近1:1
> 。自己手动改.s的对比结果可以看出来,O0性能差距的原因基本就是在多出来的几个movq上。但是自己不明白原因,所以提问。
>
>
>
> 对于你说的测试结果不一致,我又在自己电脑上做了一次。另外在别人的虚拟机上也简单测了下,和我的结果是一样的。以下是我在本机做的1000次的运行,这个貌似牵扯的比较多,从CPU型号到Gcc版本都会影响结果。
>
> =====================================
>
> 我用的如下代码运行了1000遍,每次输出基本没有差距(正负1%左右)。所以整体也符合之前的情况,我的机器环境是Xubuntu13.04,
> gcc 版本 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1) ,CPU 是Intel(R) Core(TM)
> i3-2100 CPU @ 3.10GHz。
>
> O0情况下依然是K=1,K=2和K=4的情况下都是1/2递减的。
> O1情况下1/2递减现象消失了,K=1只是稍微多耗时一点, 这个应该确实是循环数不同计算量不同的原因。
>
> 代码如下:
>
> #include <stdio.h>
> #include <time.h>
> #include <stdint.h>
> #define SIZE 64*1024*1024
> #define MAX_K 1024
> int32_t arr [SIZE];
> struct timespec ts;
>
> int main(int argc, char *argv[])
> {
>     long i,j= 0;
>     long start;
>     long start_sec;
>     int count = 1;
> // init the arr;
>     for (i = 0; i < SIZE; ++i){
>         arr[i] = 0;
>     }
>     for (j = 1; j <= MAX_K; count++, j*= 2){
>         clock_gettime(CLOCK_REALTIME, &ts);
>         start = ts.tv_nsec;
>         start_sec = ts.tv_sec;
>         for (i = 0; i< SIZE; i+=j){
>             arr[i] *=3;
>         }
>         clock_gettime(CLOCK_REALTIME, &ts);
>         printf ("%d, %ld, %ld\n",
> count,(ts.tv_sec-start_sec)*1000000000+(ts.tv_nsec -start), j);
>     }
>     return 0;
> }
>
>
> 另,我还又用下面的相同循环数的代码分别用O0~3运行了几次,结果是K=128之前一直都是递增的,特别的是O1之后,明显的可以看出,初期的几个递增就是2倍递增,比O0的结果更加符合期望结果,数据如下,
> **为什么K=128后的时间下降了,我也不清楚原因。**
>
> 1, 60962944, 1
> 2, 121961343, 2
> 3, 248836377, 4
> 4, 478276479, 8
> 5, 961089972, 16
> 6, 1371127716, 32
> 7, 1851929390, 64
> 8, 964310614, 128
> 9, 994438045, 256
> 10, 1030341734, 512
> 11, 1124689492, 1024
>
> 循环数相同的代码就是我贴在SO上的,如下:
>
> #include <stdio.h>
> #include <time.h>
> #include <stdint.h>
> #define SIZE 64*1024*1024
> int32_t arr [SIZE];
> struct timespec ts;
>
> int main(int argc, char *argv[])
> {
> long i,j= 0;
> long start;
> long start_sec;
> int count = 1;
> int k = 0;
>
> // init the arr;
> for (i = 0; i< 64*1024*1024;++i){
>     arr[i] = 0;
> }
>
> for (j = 1; j< 1025;){
>     clock_gettime(CLOCK_REALTIME, &ts);
>     start = ts.tv_nsec;
>     start_sec = ts.tv_sec;
>     for (i = 0, k = 0; i< 64*1024*1024; i++, k+=j){
>         k = k & (SIZE -1);
>         arr[k] *=3;
>         arr[k] =1;
>     }
>     clock_gettime(CLOCK_REALTIME, &ts);
>     printf ("%d, %ld, %ld\n",
> count,(ts.tv_sec-start_sec)*1000000000+(ts.tv_nsec -start), j);
>     count++;
>     j *= 2;
> }
> return 0;
> }
>
>
> 谢谢。
>
>
> 2013/7/29 Wei WU(吴伟) <wuwei.gucas@xxxxxxxxx>:
> > Hi 秦��:
> >
> > 我对于 CPU Caching
> >
> 不是很熟悉,没有看出来其中的原因。我自己运行了一下你贴在SO上的程序,得到的测试数据跟你的测试结果并不一致:在O1优化下j=2的时间是j=1的两倍,而在O0的情况下,两者的得分是类似的。
> >
> >
> 另外,一次运行的数据是不稳定的,确实有时候会出现j=2比j=1还快一点的情况。但是这可能是机器的噪音。建议运行多次(例如1000次)之后得到两者差值的平均,这样分析起来比较可靠。
> >
> > 现代CPU的性能分析是一件很困难的事情,如果你有了答案,强烈欢迎你贴在这个邮件列表中,大家共同学习 :-)
> >
> > 在 2013年7月29日下午4:51,秦�� <love.infly@xxxxxxxxx>写道:
> >
> >> c代码本身很简单
> >> for (i = 0; i< SIZE; i+=j){
> >>             arr[i] *=3;
> >> }
> >>
> >> 就是以一个步进值j遍历整个数组,对成员做*3操作。
> >>
> >> O0的代码,步进的值在-24(%rbp)中:
> >>
> >>     movq    $0, -32(%rbp)
> >>     jmp    .L5
> >> .L6:
> >>     movq    -32(%rbp), %rax
> >>     movl    arr(,%rax,4), %edx
> >>     movl    %edx, %eax
> >>     addl    %eax, %eax
> >>     addl    %eax, %edx
> >>     movq    -32(%rbp), %rax
> >>     movl    %edx, arr(,%rax,4)
> >>     movq    -24(%rbp), %rax
> >>     addq    %rax, -32(%rbp)
> >> .L5:
> >>     cmpq    $67108863, -32(%rbp)
> >>
> >> O1的代码,步进的值在 %rbx中:
> >>
> >>     movl    $0, %eax
> >> .L3:
> >>     movl    arr(,%rax,4), %ecx
> >>     leal    (%rcx,%rcx,2), %edx
> >>     movl    %edx, arr(,%rax,4)
> >>     addq    %rbx, %rax
> >>     cmpq    $67108863, %rax
> >>     jle    .L3
> >>
> >>
> >> 想问的问题是,在O0情况下,j = 1的时间是j=2时间的两倍,O1下,两者就基本接近了,甚至步进为1的还快点,为什么?
> >>
> >>
> >> 问题来源是:
> http://stackoverflow.com/questions/17914782/why-cache-doesnt-work-as-it-supposed-to-be/17915086#17915086
> >>
> >> 我自己改改O0的代码,变成如下:
> >>
> >>     movq    $0, -32(%rbp)
> >>     movl    $0, %eax
> >>     movq    -24(%rbp), %rbx
> >>     jmp .L5
> >> .L6:
> >>     movl    arr(,%rax,4), %edx
> >>     movl    %edx, %ecx
> >>     addl    %ecx, %ecx
> >>     addl    %ecx, %edx
> >>     movl    %edx, arr(,%rax,4)
> >>     addq    %rbx, %rax
> >> .L5:
> >>     cmpq    $67108863, %rax
> >>     jle .L6
> >>
> >> 就和O1差不多了。
> >>
> >> 但是不明白,循环里改掉了几个movq,怎么j = 1的速度就和j = 2的差不多了?原因是什么?
> >>
> >> 谢谢了。
> >
> >
> >
> >
> > --
> > 吴伟/Wei Wu
> > wuwei.gucas@xxxxxxxxx
>

Other related posts:

  • » [hellogcc] Re: [hellogcc] Re: [hellogcc] Re: [hellogcc] 请问下以下gcc -O0 和 -O1的代码运行时间不同的原因 - Kito Cheng