我正在进行一些时间和效率testing,并遇到一些意想不到的行为。 我发现我的程序实际上跑得更快,如果我运行其他后台进程挂100%的所有系统CPU核心。 这是一个简化的示例程序:
#define _XOPEN_SOURCE 600 #include <stdlib.h> #include <stdio.h> #include <time.h> void vadd(const float *u, const float *v, float *y, int n) { int i; for (i = 0; i < n; i++) { y[i] = u[i] + v[i]; } } int main(int argc, char *argv[]) { int i, its = 100000, n = 16384; float *a, *b, *c; clock_t start, end; double cpu_time; /* Make sure alignment is the same on each run. */ posix_memalign((void**)&a, 16, sizeof(float) * n); posix_memalign((void**)&b, 16, sizeof(float) * n); posix_memalign((void**)&c, 16, sizeof(float) * n); /* Some arbitrary initialization */ for (i = 0; i < n; i++) { a[i] = i; b[i] = 4; c[i] = 0; } /* Now the real work */ start = clock(); for (i = 0; i < its; i++) { vadd(a, b, c, n); } end = clock(); cpu_time = ((double) (end - start)) / CLOCKS_PER_SEC; printf("Done, cpu time: %f\n", cpu_time); return 0; }
我正在运行一个(相当老的)奔腾4 2.8GHz的超线程打开,它显示为/ proc / cpuinfo中的两个处理器。
与系统输出相对空闲:
$ ./test Done, cpu time: 11.450000
现在加载所有核心:
$ md5sum /dev/zero& ./test; killall md5sum Done, cpu time: 8.930000
这个结果是一致的。 我猜测我已经通过减less程序移动到另一个CPU的时间来改善caching效率,但是这只是一个黑暗的镜头。 任何人都可以证实或驳斥这一点?
第二个问题:我很惊讶地发现,cpu_time可能因运行而异。 上面使用的方法是从GNU C手册中拿出来的 ,我认为使用clock()
可以保护我免受使用CPU的其他进程所引起的时序波动的影响。 显然基于上述结果,情况并非如此。 所以我的第二个问题是, clock()
方法真的是衡量性能的正确方法吗?
更新:我已经看过有关CPU频率调节调节器的意见,我不认为这是发生在这里。 我试图通过watch grep \"cpu MHz\" /proc/cpuinfo
(如这里所build议的)实时监视CPU速度,并且在程序运行时我没有看到频率改变。 我应该也包括在我的post中,我正在运行一个相当老的内核:2.6.25。
更新2:我开始使用下面的脚本来处理启动的md5sum进程的数量。 即使当我启动比逻辑CPU更多的进程时,也比单独运行要快。
更新3:如果我在BIOS中closures超线程,这种奇怪的行为将消失,运行总是需要大约11秒的CPU时间。 看起来超线程与它有关。
更新4:我刚刚在双核四核英特尔至强@ 2.5GHz上运行,并没有看到任何上述奇怪的行为。 这个“问题”可能相当具体到我的特定硬件设置。
#!/bin/bash declare -i num=$1 for (( num; num; num-- )); do md5sum /dev/zero & done time ./test killall md5sum
–
$ ./run_test.sh 5 Done, cpu time: 9.070000 real 0m27.738s user 0m9.021s sys 0m0.052s $ ./run_test.sh 2 Done, cpu time: 9.240000 real 0m15.297s user 0m9.169s sys 0m0.080s $ ./run_test.sh 0 Done, cpu time: 11.040000 real 0m11.041s user 0m11.041s sys 0m0.004s
所以我的第二个问题是,clock()方法真的是衡量性能的正确方法吗?
你可能更喜欢使用clock_gettime(2)和朋友。 也读时间(7)
细节可以是硬件(即CPU +主板)和内核专用。
clock()
运行在一个内核上的单个进程应该返回该进程花费的运行时间。 这包括核心实际正在执行的时间以及内核正在等待从缓存/内存中获取指令和数据,等待另一条指令所需的一条指令的结果等的时间。基本上,对于这种情况, clock()
返回“执行时间加上很多微小的差距”。
对于超线程,2个“逻辑CPU”共享相同的内核。 核心使用一个进程中所有那些微小的差距来执行另一个进程,核心在更少的时间内(因为等待的时间更少)做更多的全部工作。 在这种情况下clock()
函数应该测量什么?
例如,如果两个进程都在同一个内核上运行10秒钟, clock()
应该说这两个进程每次使用10秒钟,或者clock()
应该说两个进程都使用了10秒钟的一半?
我的理论是在你的系统clock()
返回“核心时间消耗/进程消耗核心的时间”。 在一个进程运行10秒的情况下, clock()
返回“10秒”,并且这些进程中的两个共享内核,他们可能运行16秒而不是20秒(由于核心在“间隙” clock()
返回“每个进程16/2 = 8秒”; 使得看起来好像进程运行速度提高了2秒(即使花了16秒而不是10秒)。