我的 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