c - 为什么同一个 C 程序有时会快得多

标签 c linux performance memory-management profiling

好吧,这将是一个没有细节的问题,因为我不知道如何解释得更好。对不起。我有一个内存密集型 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/

相关文章:

c - 如何计算 (a*b*c*d/e)%m f a,b,c,d,e 的阶数是 10^18?

从 Infix 转换为 Postfix 并评估 Postfix 表示法

c - 是否可以在编译时获取枚举成员的值?

linux - 共享内存 IPC 如何适应进程的内存布局?

asp.net - Server.Transfer 和 Response.Redirect 哪一个更好

c - 显示结构

linux - 可以从不同目录启动同一进程的多个副本的 shell 脚本

python - Neo4j 协议(protocol)错误 : Server closed connection

python - 在 Python 的巨大列表中搜索(数字)字符串的匹配项

c++ - STL 容器性能概述