perf 黑客图

我的 Linux 系统发送的数据包大小分布是什么?

./perf-stat-hist net:net_dev_xmit len 10

跟踪 net:net_dev_xmit,4 的幂,最大 16384,持续 10 秒…

        范围:计数分布
        0              : 0        |                                      |
        1 -> 3 : 0 | |
        4 -> 15 : 0 | |
       16 -> 63 : 6 |# |
       64 -> 255 : 385 |#####################################|
      256 -> 1023 : 133 |############## |
     1024 -> 4095 : 155 |################ |
     4096 -> 16383:0 | |
    16384 -> : 0 | |

伟大的!所以大约一半在 64 到 255 字节之间,其余的在 256 到 4095 字节之间。
请求的 read() 系统调用大小如何?

time ./perf-stat-hist syscalls:sys_enter_read count 10

跟踪系统调用:sys_enter_read,4 的幂,最大 1048576,持续 10 秒…

        范围:计数分布
        0              : 0        |                                      |
        1 -> 3 : 1361 |# |
        4 -> 15 : 2 |# |
       16 -> 63 : 8 |# |
       64 -> 255 : 60 |# |
      256 -> 1023 : 1933859 |#####################################|
     1024 -> 4095 : 59 |# |
     4096 -> 16383 : 146 |# |
    16384 -> 65535 : 21 |# |
    65536 -> 262143 : 554007 |########### |
   262144 -> 1048575:0 | |
  1048576 -> : 0 | |

真正的 0m10.056s
用户 0m0.012s
系统 0m0.008s
整洁的!最常见的是 256 - 1023 字节范围。
这次我添加了一个time命令,以表明从内核中提取这些信息的成本很低。
我正在使用的脚本 perf-stat-hist 演示了一种自定义分发功能,该功能对于 SystemTap、ktap 和 DTrace 等更高级的跟踪器来说是必不可少的。 但是,我没有使用这些。
我在 3.2 内核上使用 Linux perf_events。 又名 perf 命令。
做内核直方图。
库存、标准、性能事件。
通过用户空间
是的,对于当前版本的 perf_events(3.16 和更早版本),这应该是不可能的。 perf_events 可以进行内核跟踪点计数,但除此之外的任何事情都需要将数据转储到用户空间进行后处理,如下所示:

# perf record -e 'syscalls:sys_enter_read' -a sleep 5
[ perf record: Woken up 25 times to write data ]
[ perf record: Captured and wrote 132.355 MB perf.data (~5782677 samples) ]

现在我有两个问题。 这个 perf.data 文件有超过 500 万个条目,这将花费一些 CPU 来处理。 读多少CPU? 让我们使用 perf 脚本将其转储到 /dev/null:

window1# time perf script > /dev/null
...hang...
window2# top
...hang...

两扇窗户都结冰了。 现在我有四个问题。

当 top 最终运行时,我可以看到问题所在:

# top
top - 23:21:58 up 25 days,  2:56,  2 users,  load average: 1.68, 1.42, 1.09
Tasks: 142 total,   2 running, 136 sleeping,   0 stopped,   4 zombie
Cpu(s): 18.9%us, 54.1%sy,  0.0%ni, 27.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   3839240k total,  3813020k used,    26220k free,      448k buffers
Swap:        0k total,        0k used,        0k free,   167712k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
27328 root      20   0 3437m 3.3g  68m R  100 88.8   0:06.02 perf
   34 root      20   0     0    0    0 S   26  0.0   0:45.04 kswapd0   
26289 root      20   0     0    0    0 S   10  0.0   0:00.04 kworker/u4:0
26290 root      20   0 17344  712  340 R    5  0.0   0:00.90 top        
[...]

perf 不仅吃掉了一个 CPU,而且还耗尽了这个系统上的内存。
perf_events 确实具有出色的体系结构,可以将数据从内核传递到用户级程序,从而最大限度地减少开销和 CPU 成本。 我正在测试的是一个极端情况。 在许多其他情况下,性能报告和性能脚本周期可以正常工作,并且开销可以忽略不计。 使用该循环的 perf-stat-hist 脚本只会将 perf 脚本输出分桶并打印报告:一个简单的程序。
我可以通过直接读取二进制 perf.data 文件来进一步减少开销,或者更好的是,调用 perf_event_open() 和 mmap() 来读取二进制缓冲区,并通过文件系统处理数据而无需访问。 但还有另一种方式…
黑客图
这是基于perf stat,它执行有效的内核计数。我在上一篇文章中简要介绍了基本性能计数功能。
perf stat允许您使用不同的过滤器多次检测相同的跟踪点。诀窍是为每个直方图桶使用跟踪点和过滤器对。例如:

# perf stat -e syscalls:sys_enter_read --filter 'count < 1024' \
    -e 系统调用:sys_enter_read --filter 'count >= 1024 && count < 1048576' \
    -e 系统调用:sys_enter_read --filter 'count > 1048576' -a sleep 5

 “系统范围”的性能计数器统计信息:

         1,522,160 次系统调用:sys_enter_read [100.00%]
           401,805 系统调用:sys_enter_read [100.00%]
                18 个系统调用:sys_enter_read                     

       5.001822069 秒时间过去

这表明有 1,522,160 个 read() 系统调用请求小于 1 KB,401,805 个请求在 1 KB 和 1 MB 之间,18 个请求超过 1 MB。
这就是我在 perf-stat-hist 中使用的方法。多次跟踪同一个跟踪点确实会产生额外的开销,因此这种方法并不理想,并且在使用十几个跟踪点(存储桶)时,我的目标可能会减慢 50%。这是一个黑客。
至于我正在使用的变量,在这种情况下是“计数”:那些来自跟踪点。请参阅我之前关于perf Counting的帖子的结尾,以及 /sys/…/format 文件的内容。
理想的
理想的是perf stat提供直方图选项。例如:

perf stat -e syscalls:sys_enter_read --hist “pow2 count”

对于计数变量的 2 次方直方图。
我认为 perf_events 将来很可能会获得这种能力,尤其是由于最近的内核发展(很快就会有更多信息)。所以我的 perf-stat-hist 解决方法的寿命有限。
有关 perf_events 的更多信息,请参阅我的perf_events 示例页面和perf_events wiki。

转载翻译自: https://www.brendangregg.com