使用`perf-stat`获得准确的时间测量

问题描述 投票:0回答:1

我尝试用几种语言编写简单的“hello,world”程序。我在这个领域是n00b,并且perf-stat手册没有通过缺乏示例来轻松完成。

为此,我以高优先级运行perf-stat以避免上下文切换。所以我想出了类似的东西:

sudo chrt -f 99 perf stat -e cs -e cpu-clock ./hello_c

但是,我为同一个程序得到的结果差别很大。例如,相同的C编译可执行文件的结果可以是:

     0      cs                        #    0.000 K/sec                  
  0.42 msec cpu-clock                 #    0.612 CPUs utilized          

0.000694107 seconds time elapsed
0.000713000 seconds user
0.000000000 seconds sys

要么

     0      cs                        #    0.000 K/sec                  
  0.58 msec cpu-clock                 #    0.620 CPUs utilized          

0.000936635 seconds time elapsed
0.000000000 seconds user
0.000940000 seconds sys

我在这个特殊的例子中存在不兼容的0.242528 msec,即使上下文中的上下文切换都等于0

有什么我想念的东西,我需要做一些计算吗?或者不可能获得更接近的结果?有没有其他选择来解决这个问题然后平均n次执行?

linux-kernel benchmarking scheduler perf
1个回答
3
投票

当您反复测试看似相同的代码时,有多种原因可以看到变化。我已经介绍了another answer的一些原因,并且值得记住这些。

但是,根据经验和发挥概率,我们可以预先消除许多这些。剩下的是从冷启动开始对短程序进行相对较大偏差的最可能原因:

  1. CPU省电和频率缩放功能。
  2. 实际运行时行为差异,即每次运行程序时在运行时库,VM,OS或其他支持基础结构中执行的不同代码。
  3. 一些缓存效果,或代码或数据对齐效果因运行而异。

您可以使用普通的perf stat将这三种效果分开,而不会覆盖事件列表,例如:

$ perf stat true

 Performance counter stats for 'true':

          0.258367      task-clock (msec)         #    0.427 CPUs utilized          
                 0      context-switches          #    0.000 K/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
                41      page-faults               #    0.159 M/sec                  
           664,570      cycles                    #    2.572 GHz                    
           486,817      instructions              #    0.73  insn per cycle         
            92,503      branches                  #  358.029 M/sec                  
             3,978      branch-misses             #    4.30% of all branches        

       0.000605076 seconds time elapsed

首先看看2.572 GHz线。这显示了有效的CPU频率,通过将真实的CPU周期数除以task-clock值(程序花费的CPU时间)来计算。如果这种情况因运行而异,那么挂钟时间性能偏差部分或完全由此变化解释,最可能的原因是(1)以上,即CPU频率缩放,包括低于标称频率的缩放(省电) )及以上(涡轮增压或类似功能)。

禁用频率缩放的细节取决于硬件,但是在大多数现代Linux发行版上工作的常见问题是cpupower -c all frequency-set -g performance,以抑制低于标称的缩放。

禁用turbo boost更复杂,可能取决于硬件平台甚至特定CPU,但对于最近的x86,一些选项包括:

  • 0写入/sys/devices/system/cpu/intel_pstate/no_turbo(仅限英特尔)
  • 为你系统中的每个wrmsr -p${core} 0x1a0 0x4000850089做一个${core}(虽然每个插槽上的一个可能在某些/大多数/所有芯片上都足够了吗?)。 (仅限英特尔)
  • 调整/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq值以设置最大频率。
  • 使用userspace调控器和/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed设置固定频率。

另一种选择是简单地重复运行测试,并希望CPU快速达到稳定状态。 perf stat使用--repeat=N选项内置支持:

   -r, --repeat=<n>
       repeat command and print average + stddev (max: 100). 0 means forever.

假设您观察到频率始终相同(在1%左右),或者您已经修复了频率问题,但仍存在一些差异。

接下来,检查instructions线。这是您的计划总体工作量的粗略指标。如果它在相同的方向上变化并且与运行时方差的相似方差相似,那么您就会遇到类型(2)的问题:某些运行比其他运行更多。不知道你的程序是什么,很难说更多,但你可以使用像straceperf record + perf annotate这样的工具来追踪它。

如果instructions没有变化,并且频率是固定的,但运行时间不同,则会出现类型(3)或“其他”的问题。您需要查看更多性能计数器,以查看与较慢运行相关的计数器:您是否有更多缓存未命中?更多上下文切换?更多的分支误预测?名单还在继续。一旦你发现什么减慢了你,你可以尝试隔离导致它的代码。您还可以转向另一个方向:使用传统的分析来确定慢速运行时代码的哪个部分会变慢。

祝好运!

© www.soinside.com 2019 - 2024. All rights reserved.