1. Overview
perf sched
使用了转储后再分析 (dump-and-post-process
) 的方式来分析内核调度器的各种事件。
而这往往带来一些问题,因为这些调度事件通常非常地频繁,可以达到每秒钟百万级, 进而导致 CPU
,内存和磁盘的在调度器事件记录上的严重开销。
我最近一直在用 eBPF/bcc
(包括 runqlat
) 来写内核调度器分析工具,使用 eBPF
特性在内核里直接对调度事件的分析处理,可以极大的减少这种事件记录的开销。
但是有一些性能分析场景里,我们可能想用 perf shed
命令去记录每一个调度事件, 尽管比起 ebpf
的方式,这会带来更大的开销。
想象一下这个场景,你有只有五分钟时间去分析一个有问题的云的虚拟机实例,在这个实例自动销毁之前,你想要为日后的各种分析去记录每个调度事件。
我们以记录一秒钟内的所有调度事件作为开始:
# perf sched record -- sleep 1
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.886 MB perf.data (13502 samples) ]
这个命令的结果是一秒钟记录了 1.9 Mb
的数据,其中包含了 13,502
个调度事件样本。
数据的大小和速度和系统的工作负载以及 CPU
数目的多少直接相关 (本例中正在一个 8 CPU
的服务器上 build
一个软件)。
事件记录如何被写入文件系统的过程已经被优化过了:为减少记录开销,perf
命令仅仅被唤醒一次,去读事件缓冲区里的数据,然后写到磁盘上。
因此这种方式下,仍旧会有非常显著的开销, 包括调度器事件的产生和文件系统的数据写入。
这些调度器事件包括,
# perf script --header
# ========
# captured on: Sun Feb 26 19:40:00 2017
# hostname : bgregg-xenial
# os release : 4.10-virtual
# perf version : 4.10
# arch : x86_64
# nrcpus online : 8
# nrcpus avail : 8
# cpudesc : Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz
# cpuid : GenuineIntel,6,62,4
# total memory : 15401700 kB
# cmdline : /usr/bin/perf sched record -- sleep 1
# event : name = sched:sched_switch, , id = { 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759...
# event : name = sched:sched_stat_wait, , id = { 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2...
# event : name = sched:sched_stat_sleep, , id = { 2768, 2769, 2770, 2771, 2772, 2773, 2774, ...
# event : name = sched:sched_stat_iowait, , id = { 2776, 2777, 2778, 2779, 2780, 2781, 2782,...
# event : name = sched:sched_stat_runtime, , id = { 2784, 2785, 2786, 2787, 2788, 2789, 2790...
# event : name = sched:sched_process_fork, , id = { 2792, 2793, 2794, 2795, 2796, 2797, 2798...
# event : name = sched:sched_wakeup, , id = { 2800, 2801, 2802, 2803, 2804, 2805, 2806, 2807...
# event : name = sched:sched_wakeup_new, , id = { 2808, 2809, 2810, 2811, 2812, 2813, 2814, ...
# event : name = sched:sched_migrate_task, , id = { 2816, 2817, 2818, 2819, 2820, 2821, 2822...
# HEADER_CPU_TOPOLOGY info available, use -I to display
# HEADER_NUMA_TOPOLOGY info available, use -I to display
# pmu mappings: breakpoint = 5, power = 7, software = 1, tracepoint = 2, msr = 6
# HEADER_CACHE info available, use -I to display
# missing features: HEADER_BRANCH_STACK HEADER_GROUP_DESC HEADER_AUXTRACE HEADER_STAT
# ========
#
perf 16984 [005] 991962.879966: sched:sched_wakeup: comm=perf pid=16999 prio=120 target_cpu=005
[...]
perf sched
可以用几种不同的方式记录调度事件,其 help
子命令总结如下:
# perf sched -h
Usage: perf sched [] {record|latency|map|replay|script|timehist}
-D, --dump-raw-trace dump raw trace in ASCII
-f, --force don't complain, do it
-i, --input input file name
-v, --verbose be more verbose (show symbol address, etc)
2. perf sched latency
其中,perf sched latency
可以给出每个任务 (task
) 的调度延迟,包括平均和最大延迟:
# perf sched latency
-----------------------------------------------------------------------------------------------------------------
Task | Runtime ms | Switches | Average delay ms | Maximum delay ms | Maximum delay at |
------------------------------------------------------------------------------