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