Perf Stat与Perf Record的区别

7
我对于使用perf recordperf stat计数事件(如页面错误、缓存未命中等)的区别感到困惑。以下是我的两个问题,回答第一个问题可能也有助于回答第二个问题,但我将它们明确写出以防万一。
问题1: 我理解perf stat可以获得计数的“摘要”,但在使用-I选项时,会按指定的毫秒间隔获取计数。使用此选项时,它是否会对时间间隔内的计数进行求和,或者获取时间间隔内的平均值,还是其他什么?我假设它会进行求和。perf wiki中指出它被聚合,但我认为这可能意味着任何一种情况。
问题2: 为什么perf stat -e <event1> -I 1000 sleep 5不会给出与以下命令中每秒计数总和相同的计数:perf record -e <event1> -F 1000 sleep 5
例如,如果我将“页面错误”作为事件1,则在每个命令下面列出如下输出(我假设周期字段是perf record的perf.data文件中该事件的计数)。
PERF STAT
    perf stat -e page-faults -I 1000 sleep 5
    #           time             counts unit events
         1.000252928                 54      page-faults                                                 
         2.000498389      <not counted>      page-faults                                                 
         3.000569957      <not counted>      page-faults                                                 
         4.000659987      <not counted>      page-faults                                                 
         5.000837864                  2      page-faults

PERF记录

    perf record -e page-faults -F 1000 sleep 5
    [ perf record: Woken up 1 times to write data ]
    [ perf record: Captured and wrote 0.016 MB perf.data (6 samples) ]
    perf script -F period
             1
             1
             1
             5
            38
           164

我原本以为如果我将perf stat的计数相加,结果应该与perf record的计数总和相同。但是,如果我在perf record中使用-c选项,并给出1作为参数,我确实得到了一个接近的匹配。这只是因为页面故障数量相对较少的巧合吗?
到目前为止我使用的参考资料如下:
- brendangregg's perf blog - 上面提到的此页面上的perf record和stat链接,称为"perf wiki" - 我在这里查找了perf record实际记录和写入perf.data的时间和方式。
非常感谢您能提供任何见解。

聚合的意思是加总。perf stat中更长的-I间隔将提供更多计数,对于发生在稳定速率下(如“周期”)的任何事件都是如此。 - Peter Cordes
1个回答

10
首先,你使用sleeppage-faults的测试用例并不是一个理想的测试用例。在睡眠期间不应该有页面故障事件,因此你不能真正期望任何有趣的结果。为了更容易地推理,建议使用ref-cycles(硬件)事件和繁忙的工作负载,例如awk 'BEGIN { while(1){} }'

问题1:我理解perf stat获得计数的“摘要”,但当与-I选项一起使用时,它会在指定的毫秒间隔内获取计数。使用此选项时,它会对区间内的计数进行求和还是求平均值,或者完全不同的其他内容?我认为它会被求和。

是的。这些值只是简单相加。你可以通过测试来确认:
$ perf stat -e ref-cycles -I 1000 timeout 10s awk 'BEGIN { while(1){} }'
#           time             counts unit events
 1.000105072      2,563,666,664      ref-cycles                                                  
 2.000267991      2,577,462,550      ref-cycles                                                  
 3.000415395      2,577,211,936      ref-cycles                                                  
 4.000543311      2,577,240,458      ref-cycles                                                  
 5.000702131      2,577,525,002      ref-cycles                                                  
 6.000857663      2,577,156,088      ref-cycles                                                  

[ ... snip ... ]
[ Note that it may not be as nicely consistent on all systems due dynamic frequency scaling ]

$ perf stat -e ref-cycles -I 3000 timeout 10s awk 'BEGIN { while(1){} }' 
#           time             counts unit events
 3.000107921      7,736,108,718      ref-cycles                                                  
 6.000265186      7,732,065,900      ref-cycles                                                  
 9.000372029      7,728,302,192      ref-cycles     

问题2:为什么perf stat -e <event1> -I 1000 sleep 5的结果跟每秒总数相加的结果不大一样,而这些结果都是关于以下命令的:perf record -e <event1> -F 1000 sleep 5perf stat -I使用的单位是毫秒,而perf record -F使用的单位是赫兹(HZ)(即每秒),所以与perf stat -I 1000对应的命令是perf record -F 1。实际上,对于我们更稳定的事件/工作负载,这看起来更好:
$ perf stat -e ref-cycles -I 1000 timeout 10s awk 'BEGIN { while(1){} }'
#           time             counts unit events
 1.000089518      2,578,694,534      ref-cycles                                                  
 2.000203872      2,579,866,250      ref-cycles                                                  
 3.000294300      2,579,857,852      ref-cycles                                                  
 4.000390273      2,579,964,842      ref-cycles                                                  
 5.000488375      2,577,955,536      ref-cycles                                                  
 6.000587028      2,577,176,316      ref-cycles                                                  
 7.000688250      2,577,334,786      ref-cycles                                                  
 8.000785388      2,577,581,500      ref-cycles                                                  
 9.000876466      2,577,511,326      ref-cycles                                                  
10.000977965      2,577,344,692      ref-cycles                                                  
10.001195845            466,674      ref-cycles    

$ perf record -e ref-cycles -F 1 timeout 10s awk 'BEGIN { while(1){} }'
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.008 MB perf.data (17 samples) ]

$ perf script -F time,period        
3369070.273722:          1 
3369070.273755:          1 
3369070.273911:       3757 
3369070.273916:    3015133 
3369070.274486:          1 
3369070.274556:          1 
3369070.274657:       1778 
3369070.274662:    2196921 
3369070.275523: 47192985748 
3369072.663696: 2578692405 
3369073.663547: 2579122382 
3369074.663609: 2580015300 
3369075.664085: 2579873741 
3369076.664433: 2578638211 
3369077.664379: 2578378119 
3369078.664175: 2578166440 
3369079.663896: 2579238122 

因此,你可以看到,即使对于perf record -F,结果最终也是稳定的。不幸的是,perf record的文档非常差。您可以通过查看底层系统调用man perf_event_open的文档来了解设置-c-F的含义:

sample_periodsample_freq “采样”事件是一种 每N个事件生成一个溢出通知的事件,其中N由 sample_period给出。 采样事件具有sample_period > 0。当 发生溢出时,在mmap缓冲区中记录请求的数据。 sample_type字段控制在每个上记录哪些数据 溢出。

如果想使用频率而不是周期,则可以使用sample_freq。这种情况下,您设置freq标志。内核将 调整采样周期以尝试实现所需速率。调整速度是计时器滴答声。

因此,虽然perf stat使用内部计时器每隔-i毫秒读取计数器的值,但perf record将事件溢出计数器设置为每-c个事件进行一次采样。这意味着它每隔N个事件(例如每隔N个页面错误或循环)进行一次采样。使用-F,它会尝试调节此溢出值以实现所需频率。它会尝试不同的值,并相应地调整它的值。对于稳定速率的计数器,这最终有效,但对于动态事件将得到不稳定的结果。

1
“cat /dev/urandom”很不寻常,因为它几乎花费所有的CPU时间在系统调用中。(这对于测试perf是否仅测量用户空间非常有用,例如cycles:u与cycles之间的区别)。“awk 'BEGIN { while(1){} }'”是一个用户空间的无限循环。 - Peter Cordes
@Zulan 谢谢你的回答。我知道-F是以赫兹为单位的,我应该澄清这一点。我想知道的是,如果我将所有记录样本加起来超过1秒,它们不会加起来等于-I 1000给出的同一秒钟的数字。根据您的回答,我认为这是因为我的测试用例很差。如果是这样的话,那么为什么perf record在睡眠操作期间记录任何页面错误。我可以理解如果我使用了-a选项,但我没有使用,那么怎么会有任何页面错误呢? - UniqueUsername
perf record 在睡眠期间不应报告任何事件,但在开始和结束时会有工作。另请参见 https://dev59.com/JVYM5IYBdhLWcg3wdABO - Zulan
1
@PeterCordes 的观点非常好。我的例子中包括内核,可能是由于 perf_event_paranoid=-1 - Zulan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接