好吧,这将是一个没有细节的问题,因为我不知道如何解释得更好。对不起。我有一个内存密集型 C 程序(很多指针)。我有一个源代码,它是我用 gcc -O2 编译的。我在 Ubuntu Linux 上。在程序开始和结束时,会调用 clock() 来测量耗时。此外,我正在使用时间命令来检查时间。问题是同一个程序有时在不改变任何东西的情况下快(或慢)20% 以上。
$ date; time ./cudd-example-8queens
pon jun 20 00:49:05 CEST 2016
CPU TIME = 6.46
real 0m6.475s
user 0m6.405s
sys 0m0.067s
$ date; time ./cudd-example-8queens
pon jun 20 00:49:16 CEST 2016
CPU TIME = 8.03
real 0m8.051s
user 0m7.995s
sys 0m0.048s
$ date; time ./cudd-example-8queens
pon jun 20 00:49:33 CEST 2016
CPU TIME = 6.48
real 0m6.490s
user 0m6.445s
sys 0m0.040s
$ date; time ./cudd-example-8queens
pon jun 20 00:49:42 CEST 2016
CPU TIME = 6.45
real 0m6.469s
user 0m6.424s
sys 0m0.040s
$ date; time ./cudd-example-8queens
pon jun 20 00:49:56 CEST 2016
CPU TIME = 8.04
real 0m8.058s
user 0m7.982s
sys 0m0.068s
我的问题是:如何解释这种差异,即这额外的 1.5 秒(有时会变得更糟)花在哪里了?它一定是有内存访问权限的东西,但是如何检查呢?
编辑:我已经安装了 perf,这里有两个结果(我更新了它们以显示从 cpupower 获得的信息)。关于目标,我正在比较科学算法,这对我来说很重要,例如。一个比另一个快 10%。
$ date; cpupower -c all frequency-info -f; perf stat -B ./cudd-example-8queens
pon jun 20 12:39:21 CEST 2016
analyzing CPU 0:
1300000
analyzing CPU 1:
1300000
analyzing CPU 2:
1300000
analyzing CPU 3:
1300000
clock() TIME = 6.70
clock_gettime() TIME = 6.70
Performance counter stats for './cudd-example-8queens':
6705,796274 task-clock (msec) # 0,999 CPUs utilized
104 context-switches # 0,016 K/sec
3 cpu-migrations # 0,000 K/sec
30861 page-faults # 0,005 M/sec
17295862806 cycles # 2,579 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
7361712951 instructions # 0,43 insns per cycle
1228059232 branches # 183,134 M/sec
64491733 branch-misses # 5,25% of all branches
6,709414218 seconds time elapsed
$ date; cpupower -c all frequency-info -f; perf stat -B ./cudd-example-8queens
pon jun 20 12:39:30 CEST 2016
analyzing CPU 0:
1300000
analyzing CPU 1:
1300000
analyzing CPU 2:
1300000
analyzing CPU 3:
1300000
clock() TIME = 8.43
clock_gettime() TIME = 8.43
Performance counter stats for './cudd-example-8queens':
8441,824238 task-clock (msec) # 0,999 CPUs utilized
145 context-switches # 0,017 K/sec
3 cpu-migrations # 0,000 K/sec
30863 page-faults # 0,004 M/sec
13958245339 cycles # 1,653 GHz
<not supported> stalled-cycles-frontend
<not supported> stalled-cycles-backend
7360082448 instructions # 0,53 insns per cycle
1227803521 branches # 145,443 M/sec
64517871 branch-misses # 5,25% of all branches
8,446645648 seconds time elapsed
EDIT2:我的英特尔 NUC 有英特尔酷睿 i5-4250U CPU。因此,使用“cpupower frequency-set”的建议很有希望,但不幸的是它没有任何帮助。此外,我使用“clock()”和“clock_gettime(CLOCK_PROCESS_CPUTIME_ID)”得到了完全相同的结果,并且这些结果也由 perf 的“task-clock (msec)”确认。
最佳答案
现代 CPU 具有动态变化的频率,您不仅应始终测量挂钟时间(天文时间),还应测量 CPU 周期数。 perf stat
(实际上,perf stat -e task-clock,cycles,instructions
就足够了)显示程序运行时的 CPU 核心频率 cycles
,如果有 cpu-clock/task-clock 事件来测量 wall time(周期除以时间得到 GHz):
#### cycles # 1,653 GHz
#### cycles # 2,579 GHz
这是英特尔睿频加速 (2),https://en.wikipedia.org/wiki/Intel_Turbo_Boost (AMD 有 https://en.wikipedia.org/wiki/AMD_Turbo_Core )。两者都非常快,所以当 cpupower -c all frequency-info
运行时,实际频率很低(1.3);但是当您的程序负载很高时,CPU 会在 几微秒 内将其频率调整到更高的水平。
有时可以在 BIOS 中将其关闭以获得更统一的测量值:http://www.intel.com/content/www/us/en/support/processors/000005641.html
How is Intel® Turbo Boost Technology enabled or disabled? - Intel® Turbo Boost Technology is typically enabled by default. You can only disable and enable the technology through a switch in the BIOS. There are no other user controllable settings.
或者您可以尝试一些神奇的 MSR 写入(不要将随机值写入随机 msr regs,它可能会破坏某些东西,或者挂起 PC):https://askubuntu.com/questions/619875/disabling-intel-turbo-boost-in-ubuntu Maythux 的回答:“wrmsr -pC 0x1a0 0x4000850089
”
perf stat
中的其他行:7361-7360 百万条指令,1228-1227 百万条分支 6400 万条分支错误预测表明程序是相同的并且执行了相同的代码(没有外部随机)。您也可以尝试 perf stat -d
(更好的方法是从 stat -d
中选择一些工作的硬件事件并在 perf stat -e cpu-clock 中手动列出它们,....
) 检查运行之间的缓存事件差异。
关于c - 为什么同一个 C 程序有时会快得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37912758/