那么,这将是一个没有细节的问题,因为我不知道如何更好地解释。 抱歉。 我有一个内存密集的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.5s(有时甚至更糟糕)花在哪里? 它必须是内存访问的东西,但如何检查?
编辑:我已经安装了perf,这里有两个结果(我已经更新他们也显示从cpupower获得的信息)。 关于目标,我比较科学的algorithm,对我来说比较重要的是,例如,比其他人快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频率设置”的build议是有希望的,但不幸的是它没有任何帮助。 此外,使用“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时钟/任务时钟事件来测量壁时间(周期划分到时间得到GHz):
#### cycles # 1,653 GHz #### cycles # 2,579 GHz
这是Intel Turbo Boost(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
英特尔®睿频加速技术如何启用或禁用? – 英特尔®睿频加速技术通常默认启用。 您只能通过BIOS中的开关禁用和启用该技术。 没有其他用户可控的设置。
或者你可以尝试一些神奇的MSR写作(不要写随机值到随机msr regs,它可能会打破某些东西,或挂电脑): https : //askubuntu.com/questions/619875/disabling-intel-turbo-boost-在 uthth回答由Maythux:“ wrmsr -pC 0x1a0 0x4000850089
”
来自perf stat
其他行:7361-7360百万条指令,1228-1227百万条分支64百万分支错误预测表明程序是相同的并且执行了相同的代码(没有外部随机)。 您也可以尝试perf stat -d
(最好是从stat -d
选择一些正在运行的硬件事件,并在perf stat -e cpu-clock,....
手动列出)来检查缓存事件之间的差异。
操作系统同时运行多个任务并进行管理,从一个任务切换到另一个任务。 因此,不是每次更改代码的时间,而是执行程序之间的操作系统调用的其他程序。