本文发布于Cylon的收藏册,转载请著名原文链接~

perf [1]

perf 是基于内核子系统的Linux的性能计数器,也被称为 perf_events,它提供了为所有事件进行性能分析的框架,perf 由两部分组成:

  • 内核系统调用,用于提供对这些性能数据的访问
  • 用户空间工具,用于提供收集,显示分析这些性能数据的用户空间程序

由于 perf 是内核的一部分,但要想使用 perf 还需要安装另外一部分,通常情况下安装的版本是Linux内核版本,如操作系统内核版本为 5.10 那么安装 linux-tool 后则为 5.10

1
2
3
4
$ apt-get install linux-perf

$ perf --version
perf version 5.10.149

各系统下的包名与安装

  • Ubuntu/Debian: linux-perf | linux-toolsapt-get install linux-perf
  • CentOS/Fedora: perf yum install -y perf

list - 列出可用事件描述符

使用 perf 子命令 list 可以列出所有的 perf 可测量事件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
perf list

List of pre-defined events (to be used in -e):

  branch-instructions OR branches                    [Hardware event]
  branch-misses                                      [Hardware event]
  cache-misses                                       [Hardware event]
  cache-references                                   [Hardware event]
  cpu-cycles OR cycles                               [Hardware event]
  instructions                                       [Hardware event]
  stalled-cycles-backend OR idle-cycles-backend      [Hardware event]
  stalled-cycles-frontend OR idle-cycles-frontend    [Hardware event]

  alignment-faults                                   [Software event]
  bpf-output                                         [Software event]
  context-switches OR cs                             [Software event]
  cpu-clock                                          [Software event]
  cpu-migrations OR migrations                       [Software event]
  dummy                                              [Software event]
  emulation-faults                                   [Software event]
  major-faults                                       [Software event]
  minor-faults                                       [Software event]
  page-faults OR faults                              [Software event]
  task-clock                                         [Software event]

  duration_time                                      [Tool event]

  L1-dcache-load-misses                              [Hardware cache event]
  L1-dcache-loads                                    [Hardware cache event]
  L1-dcache-prefetches                               [Hardware cache event]
  L1-icache-load-misses                              [Hardware cache event]
  L1-icache-loads                                    [Hardware cache event]
  branch-load-misses                                 [Hardware cache event]
  branch-loads                                       [Hardware cache event]
  dTLB-load-misses                                   [Hardware cache event]
  dTLB-loads                                         [Hardware cache event]
  iTLB-load-misses                                   [Hardware cache event]
  iTLB-loads                                         [Hardware cache event]

list 子命令后还可以加过滤器以查看对应类型的事件,示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# 列出TCP相关事件
$ perf list tcp

List of pre-defined events (to be used in -e):


  syscalls:sys_enter_getcpu                          [Tracepoint event]
  syscalls:sys_exit_getcpu                           [Tracepoint event]
  tcp:tcp_destroy_sock                               [Tracepoint event]
  tcp:tcp_probe                                      [Tracepoint event]
  tcp:tcp_rcv_space_adjust                           [Tracepoint event]
  tcp:tcp_receive_reset                              [Tracepoint event]
  tcp:tcp_retransmit_skb                             [Tracepoint event]
  tcp:tcp_retransmit_synack                          [Tracepoint event]
  tcp:tcp_send_reset                                 [Tracepoint event]

# 列出bpf相关事件
$ perf list bpf

List of pre-defined events (to be used in -e):

  bpf-output                                         [Software event]


  bpf_test_run:bpf_test_finish                       [Tracepoint event]
  bpf_trace:bpf_trace_printk                         [Tracepoint event]
  syscalls:sys_enter_bpf                             [Tracepoint event]
  syscalls:sys_exit_bpf                              [Tracepoint event]

# 列出硬件相关事件
$ perf list hardware

List of pre-defined events (to be used in -e):

  branch-instructions OR branches                    [Hardware event]
  branch-misses                                      [Hardware event]
  cache-misses                                       [Hardware event]
  cache-references                                   [Hardware event]
  cpu-cycles OR cycles                               [Hardware event]
  instructions                                       [Hardware event]
  stalled-cycles-backend OR idle-cycles-backend      [Hardware event]
  stalled-cycles-frontend OR idle-cycles-frontend    [Hardware event]

top - 查看系统实时信息

perf 的 top子命令可以查看CPU的实时信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ perf top
  23.69%  [kernel]          [k] mpt_put_msg_frame
  14.27%  [kernel]          [k] read_tsc
  13.34%  [kernel]          [k] asm_sysvec_apic_timer_interrupt
  11.72%  [kernel]          [k] vmware_sched_clock
   5.79%  perf_5.10         [.] 0x00000000002901f4
   5.11%  [kernel]          [k] delay_tsc
   4.87%  [kernel]          [k] native_read_msr
   4.57%  perf_5.10         [.] 0x0000000000284c2d
   3.13%  perf_5.10         [.] 0x0000000000284c1a
   3.09%  [kernel]          [k] native_write_msr
   2.07%  [kernel]          [k] s_show
   1.99%  [kernel]          [k] mpt_interrupt
   1.82%  perf_5.10         [.] 0x0000000000284d46
   1.69%  [kernel]          [k] asm_sysvec_call_function_single
   0.86%  [kernel]          [k] __es_tree_search.isra.0
   0.83%  [kernel]          [k] security_task_free
   0.78%  [vdso]            [.] 0x0000000000000698
   0.38%  perf_5.10         [.] 0x0000000000284d57

上面的信息的展示类似于 top 命令,从左右到信息为:

  • 第一列:与CPU使用率百分比占用的相关函数
  • 第二列:那个库或者进程使用的这个函数
  • 第三列:[k] 表示内核空间, [.] 表示用户空间
  • 第四列:符号或函数的名称

默认情况下 perf top 监控的是所有CPU,也可以使用子选项,例如下表(一些常用的命令参数)

Option describe
-a 监控所有CPU包含空闲值
-c 收集
-C 收集指定CPU的样本,后接CPU核心编号
-d 后接数字,将延迟几秒刷新
-e 指定特殊的事件,事件通过 perf list 查看
-F 控制采样的频率
-p 指定PID的进程的事件信息
-g 启用 显示调用图记录
-i 不继承模式,子任务将不继承计数器
-t 指定线程ID的事件信息
-u 指定user的事件信息

更多选项可以使用 perf top -h

stat - CPU相关统计

使用 perf 子命令 stat 可以对指定命令的CPU性能统计

1
perf stat <commond>

查看指定命令的CPU计数器统计信息

1
2
3
perf stat <command>
# 如果需要更详细信息可以跟 -d 选项
perf stat -d <command>

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ perf stat curl baidu.com

 Performance counter stats for 'curl baidu.com':

             31.09 msec task-clock                #    0.012 CPUs utilized          
                27      context-switches          #    0.868 K/sec                  
                 1      cpu-migrations            #    0.032 K/sec                  
               577      page-faults               #    0.019 M/sec                  
        41,691,320      cycles                    #    1.341 GHz                      (17.63%)
                 0      stalled-cycles-frontend                                     
                 0      stalled-cycles-backend    #    0.00% backend cycles idle    
                 0      instructions              #    0.00  insn per cycle           (82.37%)
     <not counted>      branches                                                      (0.00%)
     <not counted>      branch-misses                                                 (0.00%)

       2.646439514 seconds time elapsed

       0.026403000 seconds user
       0.013201000 seconds sys


Some events weren't counted. Try disabling the NMI watchdog:
	echo 0 > /proc/sys/kernel/nmi_watchdog
	perf stat ...
	echo 1 > /proc/sys/kernel/nmi_watchdog

查看指定PID的CPU计数器统计信息

统计命令将会直到 ctrl - c 结束

1
perf stat -p <PID> 

示例:例如统计一个进程的CPU使用情况

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
perf stat -p 477
^C
 Performance counter stats for process id '477':

            146.96 msec task-clock                #    0.034 CPUs utilized          
                88      context-switches          #    0.599 K/sec                  
                 8      cpu-migrations            #    0.054 K/sec                  
             4,991      page-faults               #    0.034 M/sec                  
       153,052,247      cycles                    #    1.041 GHz                      (36.77%)
                 0      stalled-cycles-frontend                                       (50.31%)
                 0      stalled-cycles-backend    #    0.00% backend cycles idle      (57.94%)
                 0      instructions              #    0.00  insn per cycle           (63.23%)
                 0      branches                  #    0.000 K/sec                    (49.69%)
                 0      branch-misses             #    0.00% of all branches          (42.06%)

       4.336415211 seconds time elapsed

只统计缓存信息

1
perf stat -e LLC-loads,LLC-load-misses,LLC-stores,LLC-prefetches
  • LLC last-level cache 是指内存分层结构中主内存之前的最后一级
  • LLC-loads:命中的指标
  • LLC-load-misses:未命中指标,显示这个周期内尚未处理的比率
  • LLC-stores
  • LLC-prefetches:事件发生在的 L2 硬件预取中

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 使用原始 PMC 计数器,例如,计算未暂停的核心周期: 

# 使用原始PMC计数器,例如,计数未改变的核心周期:
perf stat -e r003c -a sleep 5 

# 统计系统范围内每秒的系统调用: 
perf stat -e cycles -e cpu/event=0x0e,umask=0x01,inv,cmask=0x01/ -a sleep 5 

# 统计系统范围内每秒的系统调用:
perf stat -e raw_syscalls:sys_enter -I 1000 -a 

# 按类型计算指定PID的系统调用,直到Ctrl-C结束
perf stat -e 'syscalls:sys_enter_*' -p <PID> 

# 按类型统计整个系统范围内的系统调用,持续 5 秒: 
perf stat -e 'syscalls:sys_enter_*' -a sleep 5 

# 按类型计数整个系统的系统调用,持续5秒:
perf stat -e 'syscalls:sys_enter_*' -a sleep 5

# 记录指定PID进程的调度器事件直到Ctrl-C结束
perf stat -e 'sched:*' -p PID

# 记录指定PID进程的调度器事件,持续10s
perf stat -e 'sched:*' -p PID sleep 10

# 记录整个系统内的ext4事件,持续10s
perf stat -e 'ext4:*' -a sleep 10

# 统计整个系统的块设备 I/O 事件,持续10s
perf stat -e 'block:*' -a sleep 10

# 统计所有 vmscan 事件,每秒打印一份报告:
perf stat -e 'vmscan:*' -a -I 1000

record - 将CPU事件记录到文件

导出事件记录到文件

perf的子命令 record 是可以将事件记录到 perf.data,例如要CPU周期事件,可以使用record子命令并通过 tag -e 来指定事件名称

1
2
# 通过perf list 可以看出 CPU周期事件为 cpu-cycles OR cycles
perf record -e cycles sleep 10

通过查看文件的记录

结果将保存到 perf.data 文件中,如果需要查看 perf.data 需要使用子命令 report 查看,report 子命令默认查找当前目录下的 perf.data 文件,如果需要指定特定目录的需要使用tag -i

1
perf report -i ./perf.data

修改样本文件输出的结果格式

report 子命令也可以改变要显示的结果样式,例如想输出为标准输出,可以使用 --stdio

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ perf report --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 18  of event 'cycles'
# Event count (approx.): 440
#
# Overhead  Command  Shared Object      Symbol              
# ........  .......  .................  ....................
#
    90.91%  sleep    [kernel.kallsyms]  [k] native_write_msr
     9.09%  perf_5.  [kernel.kallsyms]  [k] native_write_msr


#
# (Tip: Order by the overhead of source file name and line number: perf report -s srcline)
#

如果想显示事件的编号以及对特定列排序可以使用下面域名

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ perf report -n --sort comm,symbol --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 18  of event 'cycles'
# Event count (approx.): 440
#
# Overhead       Samples  Command  Symbol                IPC   [IPC Coverage]
# ........  ............  .......  ....................  ....................
#
    90.91%             9  sleep    [k] native_write_msr  -      -            
     9.09%             9  perf_5.  [k] native_write_msr  -      -            


#
# (Tip: Show current config key-value pairs: perf config --list)
#

script - trace做了什么

perf 子命令 script 可以trace perf.data 中所有的事件;例如上面的 perf.data 最终两个事件展开为

perf script 子命令也是作为一个后期处理数据的一个命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ perf script 
       perf_5.10  2730 28762.537401:          1 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
       perf_5.10  2730 28762.537540:          1 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
       perf_5.10  2730 28762.537670:          1 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
       perf_5.10  2730 28762.537798:          2 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
       perf_5.10  2730 28762.537901:          3 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
       perf_5.10  2730 28762.538003:          4 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
       perf_5.10  2730 28762.538105:          6 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
       perf_5.10  2730 28762.538207:          9 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
       perf_5.10  2730 28762.538320:         13 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.542839:         26 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.543041:         26 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.543233:         26 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.543421:         30 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.543558:         35 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.543683:         41 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.543806:         53 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.543929:         70 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])
           sleep  2730 28772.544065:         93 cycles:  ffffffffbd46b466 native_write_msr+0x6 ([kernel.kallsyms])

输出显示文件的头信息,例如跟踪何时开始、持续了多长时间、CPU信息以及获取数据的命令。 事件列表在头信息之后。

显示trace的头信息

使用tag --header 可以显示文件的头信息,例如跟何时开始trace、持续的事件、CPU信息以及获取数据的命令。 事件列表在头信息之后。事件头信息是由 # ======== 包含著的信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# ========
# captured on    : Tue Dec  6 04:44:38 2022
# header version : 1
# data offset    : 256
# data size      : 11528
# feat offset    : 11784
# hostname : debian-template
# os release : 5.10.0-16-amd64
# perf version : 5.10.149
# arch : x86_64
# nrcpus online : 2
# nrcpus avail : 2
# cpudesc : AMD Ryzen 7 5800U with Radeon Graphics
# cpuid : AuthenticAMD,25,80,0
# total memory : 1996352 kB
# cmdline : /usr/bin/perf_5.10 record -e cycles sleep 10 
# event : name = cycles, , id = { 471, 472 }, size = 120, { sample_period, sample_freq } = 2250, sample_type = IP|TID|TIME|PERIOD, read_forma>
# CPU_TOPOLOGY info available, use -I to display
# NUMA_TOPOLOGY info available, use -I to display
# pmu mappings: software = 1, power = 9, uprobe = 7, cpu = 4, breakpoint = 5, tracepoint = 2, kprobe = 6, msr = 8
# CACHE info available, use -I to display
# time of first sample : 28762.537401
# time of last sample : 28772.544065
# sample duration :  10006.663 ms
# MEM_TOPOLOGY info available, use -I to display
# bpf_prog_info 3: bpf_prog_47dd357395126b0c addr 0xffffffffc00eb59c size 309
# bpf_prog_info 4: bpf_prog_6deef7357e7b4530 addr 0xffffffffc00f2168 size 54
# bpf_prog_info 5: bpf_prog_6deef7357e7b4530 addr 0xffffffffc00f40e0 size 54
# bpf_prog_info 6: bpf_prog_b73cbcf8b8c71a5b addr 0xffffffffc02591c8 size 307
# bpf_prog_info 7: bpf_prog_6deef7357e7b4530 addr 0xffffffffc025b584 size 54
# bpf_prog_info 8: bpf_prog_6deef7357e7b4530 addr 0xffffffffc025db10 size 54
# bpf_prog_info 9: bpf_prog_ee0e253c78993a24 addr 0xffffffffc0534640 size 255
# bpf_prog_info 10: bpf_prog_ce28cc67158d681f addr 0xffffffffc04947f0 size 447
# bpf_prog_info 11: bpf_prog_6deef7357e7b4530 addr 0xffffffffc052fe4c size 54
# bpf_prog_info 12: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0531224 size 54
# cpu pmu capabilities: max_precise=0
# missing features: TRACING_DATA BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID DIR_FORMAT COMPRESSED CLOCK_DATA 
# ========

导出16进制的原生数据

导出原生数据是ASIIC格式事件信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ perf script -D
0x100 [0x50]: event: 1
.
. ... raw event: size 80 bytes
.  0000:  01 00 00 00 01 00 50 00 ff ff ff ff 00 00 00 00  ......P.........
.  0010:  00 00 40 bd ff ff ff ff f7 1d c0 00 00 00 00 00  ..@.............
.  0020:  00 00 40 bd ff ff ff ff 5b 6b 65 72 6e 65 6c 2e  ..@.....[kernel.
.  0030:  6b 61 6c 6c 73 79 6d 73 5d 5f 74 65 78 74 00 00  kallsyms]_text..
.  0040:  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

0 0x100 [0x50]: PERF_RECORD_MMAP -1/0: [0xffffffffbd400000(0xc01df7) @ 0xffffffffbd400000]: x [kernel.kallsyms]_text

0x150 [0x78]: event: 1
.
. ... raw event: size 120 bytes
.  0000:  01 00 00 00 01 00 78 00 ff ff ff ff 00 00 00 00  ......x.........
.  0010:  00 10 0a c0 ff ff ff ff 00 00 04 00 00 00 00 00  ................
.  0020:  00 00 00 00 00 00 00 00 2f 6c 69 62 2f 6d 6f 64  ......../lib/mod
.  0030:  75 6c 65 73 2f 35 2e 31 30 2e 30 2d 31 36 2d 61  ules/5.10.0-16-a
.  0040:  6d 64 36 34 2f 6b 65 72 6e 65 6c 2f 64 72 69 76  md64/kernel/driv
.  0050:  65 72 73 2f 73 63 73 69 2f 73 63 73 69 5f 6d 6f  ers/scsi/scsi_mo
.  0060:  64 2e 6b 6f 00 00 00 00 00 00 00 00 00 00 00 00  d.ko............
.  0070:  00 00 00 00 00 00 00 00

trace - 更高性能的strace的替代品

trace是linux 3.7 增加的功能,可以用作strace命令的替代品,因为不需要用户-内核空间切换,所以性能将更快

1
 perf trace <command>

也可以使用tag -e 来指定仅对指定事件trace

1
perf trace -e read,write <command>

可以看到对应事件将只有 read 与 write

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ perf trace -e read,write ls
     0.000 (1					 nginx-1.22.0		       nginx_1.22.0.orig.tar.gz		 perf.data
1.c					 nginx_1.22.0-1.debian.tar.xz  nginx-1.22.0.tar.gz		 perf.data.old
deb-multimedia-keyring_2016.8.1_all.deb  nginx_1.22.0-1.dsc	       paping_1.5.5_x86-64_linux.tar.gz
 0.058 ms): ls/3126 read(fd: 3, buf: 0x7ffcd2548068, count: 832)                          = 832
     0.132 ( 0.034 ms): ls/3126 read(fd: 3, buf: 0x7ffcd2548048, count: 832)                          = 832
     0.232 ( 0.033 ms): ls/3126 read(fd: 3, buf: 0x7ffcd2548028, count: 832)                          = 832
     0.324 ( 0.032 ms): ls/3126 read(fd: 3, buf: 0x7ffcd2548008, count: 832)                          = 832
     0.416 ( 0.032 ms): ls/3126 read(fd: 3, buf: 0x7ffcd2547fc8, count: 832)                          = 832
     0.828 ( 0.048 ms): ls/3126 read(fd: 3, buf: 0x55c4bb555500, count: 1024)                         = 361
     0.907 ( 0.028 ms): ls/3126 read(fd: 3, buf: 0x55c4bb555500, count: 1024)                         = 0
     1.127 ( 0.060 ms): ls/3126 write(fd: 1, buf: 0x55c4bb555500, count: 65)                          = 65
     1.219 ( 0.385 ms): ls/3126 write(fd: 1, buf: 0x55c4bb555500, count: 75)                          = 75
     1.638 ( 0.049 ms): ls/3126 write(fd: 1, buf: 0x55c4bb555500, count: 100)                         = 100

probe - 动态追踪

perf probe子命令是可以动态的在linux内核中自定义追踪事件(追踪点),追踪点的运行时可以在被放置任何任何地方,并且每次通过该追踪点时,都可以记录其值。

如何使用 perf probe

查看可探测的函数

perf probe -F 可以找到可用的追踪点,如果模糊查找可以使用filter

1
perf probe -F -–filter dev*xmit*

probe参数

Option describe
-L 显示源代码
-x 可执行文件的名称或路径
-l 列出所有probe探测事件
-k 指定vmlinux文件
-a **`<[EVENT=]FUNC[@SRC][+OFF
EVENT 事件名称
FUNC 函数名
+OFF 函数入口的偏移量
%return 探针位置为函数返回处
SRC 源代码路径
RL 相对函数入口处的行号
AL 在文件内的绝对行号
ARG: 探测参数(局部变量名 或 kprobe-tracer 参数格式。
1
2
perf probe -x tst --add 'out=func%return $retval'
perf record -g -e probe_tst:out -aR ./tst

一些使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 添加一个追踪点到linux内核函数tcp_sendmsg()至入口
perf probe --add tcp_sendmsg

# 删除linux内核tcp_sendmsg()函数上的追踪点
perf probe -d tcp_sendmsg

# 列出现有的追踪点
perf probe -l

# 添加一个追踪点到linux内核函数tcp_sendmsg()返回部分
perf probe 'tcp_sendmsg%return'

通过probe检测内核函数

probe使用示例说明

  • 内核函数:tcp_sendmsg()

在内核函数上 tcp_sendmsg 添加一个事件

1
perf probe --add tcp_sendmsg

此时会存在一个追踪点,通过 perf probe -l 可以查看

trace此追踪点5s,记录堆栈信息

1
perf record -e probe:tcp_sendmsg -a -g -- sleep 5 

通过 report 子命令可以查看对应信息

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
$ perf report --stdio  -i perf.data
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 13  of event 'probe:tcp_sendmsg'
# Event count (approx.): 13
#
# Children      Self  Command  Shared Object     Symbol                            
# ........  ........  .......  ................  ..................................
#
   100.00%   100.00%  sshd     [kernel.vmlinux]  [k] tcp_sendmsg
            |          
            |--92.31%--0
            |          getnetbyaddr_r@@GLIBC_2.2.5
            |          entry_SYSCALL_64_after_hwframe
            |          do_syscall_64
            |          ksys_write
            |          vfs_write
            |          new_sync_write
            |          sock_write_iter
            |          sock_sendmsg
            |          tcp_sendmsg
            |          
             --7.69%--0x1b81475c085
                       getnetbyaddr_r@@GLIBC_2.2.5
                       entry_SYSCALL_64_after_hwframe
                       do_syscall_64
                       ksys_write
                       vfs_write
                       new_sync_write
                       sock_write_iter
                       sock_sendmsg
                       tcp_sendmsg

   100.00%     0.00%  sshd     libc-2.31.so      [.] getnetbyaddr_r@@GLIBC_2.2.5
            |
            ---getnetbyaddr_r@@GLIBC_2.2.5
               entry_SYSCALL_64_after_hwframe

删除对应跟踪点

1
perf probe -d <probe_name>

也可以通过内核函数的变量进行检查

查看内核函数参数,可以看到存在三个参数 size int类型, msg 结构体指针,sk 结构体指针

1
2
3
4
5
6
$ perf probe -V tcp_sendmsg 
Available variables at tcp_sendmsg
        @<tcp_sendmsg+0>
                size_t  size
                struct msghdr*  msg
                struct sock*    sk

使用 size 变量作为 tcp_sendmsg 探测点的探测器

1
perf probe --add 'tcp_sendmsg size'

通过probe检测用户空间程序 [2]

准备一段代码,即每次循环,打印该值并打印该值+5

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>

int func(int xxx)
{
    int zzz = xxx;

    printf("zzz: %d\n", zzz);
    return zzz+5;
}
int main(int argc, char* argv[])
{
    int i=0;
    for( i=0; i<10; i++)
        printf("yyy: %d\n", func(argc + i));

    return 0;
}

这里使用环境为 debian11,内核 5.10,需要注意的是,在新内核中版本中传参的命令与老内核有少许差别

运行编译后的程序可以看到结果

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ gcc -g -o tst tst.c && ./tst
zzz: 1
yyy: 6
zzz: 2
yyy: 7
zzz: 3
yyy: 8
zzz: 4
yyy: 9
zzz: 5
yyy: 10
zzz: 6
yyy: 11
zzz: 7
yyy: 12
zzz: 8
yyy: 13
zzz: 9
yyy: 14
zzz: 10
yyy: 15

这里编译时使用了 -g 选项,-g 是一个编译选项,即在源代码编译的过程中起作用,让gcc把更多调试信息(也就包括符号信息)收集起来并将存放到最终的可执行文件

接下来为程序创建一个追踪事件,

1
2
3
4
5
6
7
8
perf probe -x tst --add 'out=func%return $retval'
# 格式将严格遵循 <[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]>
# out=func%return %retval
# EVENT=FUNC%return ARG
# EVENT 探测事件名
# FUNC  函数名
# %return 在函数return处放置探针
# ARG 参数

此时可以执行这个程序,让probe可以追踪到数据

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ perf record -g -e probe_tst:out__return -aR ./tst
Lowering default frequency rate to 2750.
Please consider tweaking /proc/sys/kernel/perf_event_max_sample_rate.
zzz: 1
yyy: 6
zzz: 2
yyy: 7
zzz: 3
yyy: 8
zzz: 4
yyy: 9
zzz: 5
yyy: 10
zzz: 6
yyy: 11
zzz: 7
yyy: 12
zzz: 8
yyy: 13
zzz: 9
yyy: 14
zzz: 10
yyy: 15
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.163 MB perf.data (10 samples) ]

执行的结果保存在 perf.data

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$ perf report --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 10  of event 'probe_tst:out__return'
# Event count (approx.): 10
#
# Children      Self  Command  Shared Object     Symbol                
# ........  ........  .......  ................  ......................
#
   100.00%   100.00%  tst      tst               [.] main
            |
            ---0x5541d68949564100
               cancel_handler
               main

   100.00%     0.00%  tst      [unknown]         [.] 0x5541d68949564100
            |
            ---0x5541d68949564100
               cancel_handler
               main

   100.00%     0.00%  tst      libc-2.31.so      [.] cancel_handler
            |
            ---cancel_handler
               main

使用 script 子命令查看这个程序的trace记录,可以看到

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
perf script 
tst  2272 [000] 28276.947273: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0x6
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947282: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0x7
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947288: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0x8
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947294: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0x9
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947300: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0xa
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947306: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0xb
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947311: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0xc
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947317: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0xd
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947322: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0xe # 14
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

tst  2272 [000] 28276.947328: probe_tst:out__return: (55dc41f11135 <- 55dc41f11192) arg1=0xf # 15
            55dc41f11192 main+0x2e (/root/tst)
            7f67337bed0a cancel_handler+0x3a (/usr/lib/x86_64-linux-gnu/libc-2.31.so)
        5541d68949564100 [unknown] ([unknown])

可以通过上面看到,这里制作的探针在用户空间程序 tst.func 函数中,当他返回时,记录了要返回的值作为arg1,也就是每行返回的 0xf 这类16进制值,也可以看到每次命中该探针的部分

Troubleshooting

Uhhuh. NMI received for unknown reason

1
2
3
4
5
6
7
8
Message from syslogd@phab1 at Dec 26 19:16:16 ...
kernel:Uhhuh. NMI received for unknown reason 30 on CPU 0.

Message from syslogd@phab1 at Dec 26 19:16:16 ...
kernel:Do you have a strange power saving mode enabled?

Message from syslogd@phab1 at Dec 26 19:16:16 ...
kernel:Dazed and confused, but trying to continue

上述问题通常发生于虚拟化环境

Solve solution: disable c-state in bios

Failed to find the path for kernel: Invalid ELF file

1
2
Failed to find the path for kernel: Invalid ELF file
  Error: Failed to show vars.

这个错误通常使用 perf probe -V 时出现,这里需要内核支持 debug symbols,即使用公开发行版需要安装对应内核包

  • RHEL/CentOS:安装 kernel-debuginfo-commonkernel-debuginfo package
  • Debian/Ubuntu:安装 linux-image-<kernel_version>-amd64-dbg debian下保持需要至少5G空间 [3]

Failed to find source file path

1
2
3
$ perf probe -L tcp_sendmsg
Failed to find source file path.
  Error: Failed to show lines.

思路:可以通过 strace 命令看看为什么报错

原因:perf probe -L 将显示对应内核探测点的源代码,此时perf会寻找构建的内核目录,而操作系统发行版供应商对于系统都是通过包管理,包括内核,并未提供这些源码,此状态为正确的,如果非要解决,可以自行编译内核。

dmesg

dmesg 是来自内核的一个环形缓冲区,而通过 dmesg 命令可以看到来自该缓冲区的消息,而该消息也被称为 ”driver message“ 或 ”display message

示例1:对dmesg输出着色

1
$ dmesg -L

示例2:dmesg输出消息增加时间

1
$ dmesg -T

示例3:过滤相关级别信息

可以通过 --level 来进行过滤出不同级别的日志,可用级别有

  • emerg,
  • alert,
  • crit,
  • err,
  • warn,
  • notice,
  • info
  • debug
1
2
3
$ dmesg --level=err

$ dmesg --level=warn

示例4:过滤相关事件信息

dmesg 可以通过参数指定 --facility 来指定对应事件的日志,可用的设施有:

  • kern
  • user
  • mail
  • daemon
  • auth
  • lpr
  • news
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$  dmesg --facility=daemon
[    1.793879] systemd[1]: Inserted module 'autofs4'
[    1.807871] systemd[1]: systemd 247.3-7 running in system mode. (+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 +ZSTD +SECCOMP +BLKID +ELFUTILS +KMOD +IDN2 -IDN +PCRE2 default-hierarchy=unified)
[    1.807925] systemd[1]: Detected virtualization vmware.
[    1.807927] systemd[1]: Detected architecture x86-64.
[    1.808612] systemd[1]: Set hostname to <debian-template>.
[    1.881058] systemd[1]: Queued start job for default target Graphical Interface.
[    1.882132] systemd[1]: Created slice system-getty.slice.
[    1.882337] systemd[1]: Created slice system-modprobe.slice.
[    1.882724] systemd[1]: Created slice system-systemd\x2dfsck.slice.
[    1.882869] systemd[1]: Created slice User and Session Slice.
[    1.882902] systemd[1]: Started Dispatch Password Requests to Console Directory Watch.
[    1.882920] systemd[1]: Started Forward Password Requests to Wall Directory Watch.
[    1.883019] systemd[1]: Set up automount Arbitrary Executable File Formats File System Automount Point.
[    1.883036] systemd[1]: Reached target Local Encrypted Volumes.
[    1.883049] systemd[1]: Reached target Paths.
[    1.883054] systemd[1]: Reached target Remote File Systems.
[    1.883058] systemd[1]: Reached target Slices.
[    1.883080] systemd[1]: Reached target Swap.
[    1.883152] systemd[1]: Listening on Syslog Socket.
[    1.883193] systemd[1]: Listening on fsck to fsckd communication Socket.
[    1.883218] systemd[1]: Listening on initctl Compatibility Named Pipe.
[    1.883285] systemd[1]: Listening on Journal Audit Socket.
[    1.883322] systemd[1]: Listening on Journal Socket (/dev/log).
[    1.883364] systemd[1]: Listening on Journal Socket.
[    1.883422] systemd[1]: Listening on udev Control Socket.
[    1.883456] systemd[1]: Listening on udev Kernel Socket.
[    1.883961] systemd[1]: Mounting Huge Pages File System...

示例5:实时打印dmesg日志

1
$ dmesg --follow

示例6:显示dmesg原生信息

1
$ dmesg -r

示例7:dmesg信息重定向到syslog

dmesg本身只是一个用户空间命令,而 ”driver message“ 是内存中一个缓冲器,在Linux标识为 /dev/kmsg,而这个缓冲区是存在与内存中,如果需要将其重定向到syslog,可以通过参数 -S 实现,-s 则是设置这个环形buffer的大小

示例8:过滤硬件设备相关信息

1
2
3
4
5
6
7
8
9
# usb设备
$ dmesg | grep -i usb
# 还可以通过grep查看其它硬件设备相关信息
$ dmesg | grep -i dma
$ dmesg | grep -i scsi
$ dmesg | grep -i acpi
$ dmesg | grep -i memory
$ dmesg | grep -i tty
$ dmesg | grep sda

示例9:清空buffer

1
2
3
4
# 直接清空
dmesg -C
# 读取并清空
dmesg -c

vmstat

vmstat 命令是Linux虚拟内存统计信息的命令,带来的是与进程有关的信息,如processes, memory, paging, block IO

没有任何参数的vmstat

1
2
3
4
$ vmstat 
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 1246808  24308 507656    0    0     5     0   60  130  0  0 100  0  0

vmstat输出包含的字段

  • Procs – r: 等待运行的数量
  • Procs – b: 忙碌进程的数量
  • Memory – swpd: 已使用的虚拟内存
  • Memory – free: 空闲的虚拟内存
  • Memory – buff: 用作buffer的内存
  • Memory – cache: 用作cache的内存
  • Swap – si: 从磁盘交换至内存 (for every second)
  • Swap – so: 内存交换到磁盘 (for every second)
  • IO – bi (Blocks in). i.e 从设备接受到的块(for every second)
  • IO – bo (Blocks out). i.e 发送到设备的块 (for every second)
  • System – in (Interrupts per second) 每秒的中断
  • System – cs (Context switches) 上下文切换
  • CPU – us, sy, id, wa, st: CPU user time, system time, idle time, wait time

示例1:显示活动和非活动内存

1
2
3
4
$ vmstat -a
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free  inact active   si   so    bi    bo   in   cs us sy id wa st
 1  0      0 1247060 294352 314540    0    0     5     0   60  130  0  0 100  0  0

示例2:显示启动系统后所有fork系统调用

显示所有 fork、vfork 和 clone 系统调用计数

1
2
$ vmstat -f
         2889 forks

示例3:动态展示

展示结果将以 x 秒刷新,直到 crtl - c 退出

1
$ vmstat 2

也可以接俩个参数,一个是刷新时间,一个是刷新多少次,例如,2秒刷新一次,一共刷新10次,完成后退出命令

1
$ vmstat 2 10

示例4:打印时间

1
2
3
4
5
$ vmstat -t 1 2
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- -----timestamp-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st                 PST
 1  0      0 1247424  24396 507656    0    0     5     0   60  130  0  0 100  0  0 2022-12-10 08:10:03
 1  0      0 1247416  24396 507656    0    0     0     8  130  277  0  0 100  0  0 2022-12-10 08:10:04

示例5:显示slab相关信息

slab是一种内存管理机制,目的是为了更有效的分配内存对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
vmstat -m
Cache                       Num  Total   Size  Pages
nf_conntrack                102    102    320     51
ovl_inode                    94     94    688     47
ext4_groupinfo_1k           120    120    136     60
fuse_request                  0      0    152     53
fuse_inode                    0      0    832     39
ext4_groupinfo_4k           112    112    144     56
ext4_fc_dentry_update         0      0     80     51
ext4_inode_cache          13554  13554   1184     27
ext4_system_zone            204    204     40    102
ext4_io_end                 128    128     64     64
ext4_extent_status         3060   3060     40    102
jbd2_journal_handle         146    146     56     73
...

场景6:输出格式为表格形式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ vmstat -s
      1996352 K total memory
       216852 K used memory
       314636 K active memory
       294352 K inactive memory
      1247416 K free memory
        24428 K buffer memory
       507656 K swap cache
            0 K total swap
            0 K used swap
            0 K free swap
         3635 non-nice user cpu ticks
            2 nice user cpu ticks
         8204 system cpu ticks
      9759423 idle cpu ticks
          310 IO-wait cpu ticks
            0 IRQ cpu ticks
          320 softirq cpu ticks
            0 stolen cpu ticks
       498371 pages paged in
        45598 pages paged out
            0 pages swapped in
            0 pages swapped out
      5866212 interrupts
     12709713 CPU context switches
   1670639441 boot time
         2922 forks

场景7:磁盘相关信息

1
2
3
4
5
$ vmstat -d 1 20
disk- ------------reads------------ ------------writes----------- -----IO------
       total merged sectors      ms  total merged sectors      ms    cur    sec
sda     7835   2737  996742    2134   5719   2598   91620    6219      0      9
sda     7835   2737  996742    2134   5747   2598   91908    6230      0      9

场景8:输出格式增加宽度

1
2
3
4
5
6
vmstat -w 1 3
--procs-- -----------------------memory---------------------- ---swap-- -----io---- -system-- --------cpu--------
   r    b         swpd         free         buff        cache   si   so    bi    bo   in   cs  us  sy  id  wa  st
   0    0            0      1247440        24468       507656    0    0     5     0   60  130   0   0 100   0   0
   0    0            0      1247440        24468       507656    0    0     0     0  135  265   0   0 100   0   0
   0    0            0      1247440        24468       507656    0    0     0     0  126  262   0   0 100   0   0

场景9:输出单位格式化

1
2
vmstat -S k
vmstat: -S requires k, K, m or M (default is KiB)

mpstat

mpstat是统计CPU相关信息的命令

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install sysstat -y
  • RHEL/CentOS/Fedora:yum install -y sysstat
1
2
3
4
$ mpstat

08:22:07 AM  CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
08:22:07 AM  all    0.04    0.00    0.09    0.00    0.00    0.00    0.00    0.00    0.00   99.87

看懂 mpstat 输出结果

  • CPU:处理器编号. all为所有CPU在一段时间内的平均统计信息.
  • %usr:在用户级别(应用程序)执行时的CPU平均使用率。
  • %nice:具有良好级别的用户级别(应用程序)执行时的CPU平均使用率。
  • %sys:显示在内核级别执行时发生的CPU使用率。 这里不包括耗时的硬/软中断服务
  • %iowait:CPU 或 CPU 处于空闲状态期间系统有未完成的磁盘 I/O 请求。
  • %irq:一个或多个 CPU 在中断时,硬中断所花费的时间的百分比。
  • %soft: 一个或多个CPU用于中断时,软中断所花费的时间百分比。
  • %steal: 一个或多个虚拟CPU当在虚拟机管理器服务与另一个虚拟处理器时非自愿等待时间所花费的百分比
  • %guest:一个或多个CPU在运行一个虚拟处理器使用时间的百分比
  • %idle : 一个或多个CPU处于idle状态,并且系统没有尚未完成的磁盘 I/O 请求
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 显示所有信息
mpstat -A

# 按照独立核心展示
mpstat -P ALL

# 使用编号指定单独的CPU编号
mpstat -P 1

# 第一个参数表示刷新时间,第二个参数表示刷新次数
mpstat 2 10

# CPU利用率
mpstat -u %usr

# CPU中断信息
mpstat -I { SUM | CPU | SCPU | ALL }

pidstat

pidstatsysstat 包的一部分,可以统计单个进程并生成报告。用以通过 PID 来评估资源的使用率

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install sysstat -y
  • RHEL/CentOS/Fedora:yum install -y sysstat
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 显示所有进程
pidstat -p ALL

# 查看特定进程
pidstat -p 514

# 根据进程名称来查看
pidstat -C "mysql"

# 指定实时刷新
pidstat -p 23493 1

# 显示指定进程的I/O统计信息
pidstat -p <pid> -d

# 显示指定进程的活动分页统计信息
pidstat -p <pid> -r

# 显示结果时加上进程程序所在路径、参数等信息
pidstat -C java -l

# 第一个参数表示刷新时间,第二个参数表示刷新次数
pidstat 2 5

# 显示进程的子进程信息
# -T: CHILD, or TASKS, or ALL.
pidstat -p 1 -T CHILD

# 显示为依赖进程树格式
pidstat -t -C "ssh"

# 展示一个水平线上的性能
# option “r”  page faults and memory utilization
# option “d”  I/O statistics
# option “u”  CPU utilization
# 展示结果将按照 r d u 依次输出
pidstat -rud

iostat

iostatsysstat 包的一部分,可以通过命令来统计CPU使用率, I/O, (设备,分区), 网络文件系统等

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install sysstat -y
  • RHEL/CentOS/Fedora:yum install -y sysstat

iostat命令参数

  • -c: 显示CPU使用率
  • -d: 显示设备使用率
  • -k: 以kb为单位统计(每秒)
  • -m: 以mb为单位统计(每秒)
  • -x: 展示一些扩展的统计文件

iostat结果为两部分,avg-cpu 与 Device,均是指自开机以来的统计

avg-cpu部分:

  • %user:在用户级别(应用程序)执行时的CPU平均使用率。
  • %nice:具有良好级别的用户级别(应用程序)执行时的CPU平均使用率。
  • %system:显示在内核级别执行时发生的CPU使用率。 这里不包括耗时的硬/软中断服务
  • %iowait:CPU 或 CPU 处于空闲状态期间系统有未完成的磁盘 I/O 请求。
  • %steal: 一个或多个虚拟CPU当在虚拟机管理器服务与另一个虚拟处理器时非自愿等待时间所花费的百分比
  • %idle : 一个或多个CPU处于idle状态,并且系统没有尚未完成的磁盘 I/O 请求

Device部分:

  • tps - 表示每秒发送给设备的传输次数。
  • Blk_read/s (kB_read/s, MB_read/s) - 表示每秒从设备读取的数据量,以块(KB、MB)表示。
  • Blk_wrtn/s (kB_read/s, MB_read/s) - 表示每秒写入设备的数据量,以块(KB、MB)表示。
  • Blk_read (kB_read, MB_read) - 读取块总数(KB、MB)
  • Blk_wrtn (kB_read, MB_read)- 写入块总数(KB、MB)
1
2
3
4
5
6
7
8
$ iostat
Linux 5.10.0-16-amd64 (debian-template) 	12/11/2022 	_x86_64_	(2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           0.04    0.00    0.09    0.00    0.00   99.87

Device             tps    kB_read/s    kB_wrtn/s    kB_dscd/s    kB_read    kB_wrtn    kB_dscd
sda               0.26         8.22         1.88         0.00     578135     131934          0

使用示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 显示CPU使用率
iostat -c

# 显示CPU使用率 按照周期刷新 sec
iostat -c N

# 设备使用率
iostat -d

# 以人类可读方式展示
iostat -h

# 显示一些扩展选项
iostat -x

# 以kb为单位展示
iostat -k

# 以mb为单位展示
iostat -m

# 显示设备与分区的使用率
iostat -p

# 显示指定设备的使用率
iostat -p <device_name>

# 忽略非活跃设备
iostat -z

htop

htop可以理解为linux中的与windows任务管理器相同的产品,与top不同的是,htop是一个支持交互式的top命令

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install htop -y
  • RHEL/CentOS/Fedora:yum install -y htop

CPU和内存使用状态

htop上部屏幕,为CPU和存储使用详情

显示的颜色

默认模式

  • 蓝色:低优先级进程(nice> 0)
  • 绿色:正常(用户)流程
  • 红色:内核时间(内核,iowait,irqs …)
  • 橙色:有效时间(窃取时间+访客时间)

详细模式

  • 蓝色:低优先级线程(nice> 0)
  • 绿色:正常(用户)流程
  • 红色:系统进程
  • 橙色:IRQ时间
  • 洋红色:IRQ时间较慢
  • 灰色:IO等待时间
  • 青色:偷时间
  • 青色:访客时间

内存计量器更简单:

  • 绿色:已用内存页
  • 蓝色:缓冲页
  • 橙色:缓存页面

可以通过f1查看帮助对于颜色的说明

ldd

sar

sar System Activity Report的简写,可以用于收集、报告或保存系统活动的统计信息,如 Linux 系统中的 CPU 利用率、内存使用情况、I/O 设备使用情况。 sar 命令显示自系统启动以来的平均统计信息。它在输出中生成报告,也可以保存在文件中。

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install sysstat -y
  • RHEL/CentOS/Fedora:yum install -y sysstat

Notes:sar是服务,需要开启收集才可以查询到,配置 /etc/default/sysstat 修改为 ENABLED="false" 然后重启服务 systemctl restart sysstat.service

sar语法

1
$ sar [option] [interval] [count]

更多可以参考 [5]

ioping

ioping是一款磁盘延迟监控工具

  • Ubuntu/Debian/Mint:apt install -y ioping
  • RHEL/CentOS/Fedora:yum install -y ioping
Option describe
-c count ping的次数
-i interval 每次请求的间隔
-t time 最大有效的请求事件,太慢的请求将被忽略
-s size 请求大小
-S wsize
-o offset 在 file/device 开始的偏移量
-w deadline 在多少时间后停止
-p period 打印每秒请求的原生统计数据
-A 使用异步IO (syscalls io_submit(2), io_submit(2),
-B 批量模式,以安静的原始数据方式统计最终的数据
-C 使用 cached I/O 在posix_fadvise(2)读取之前 和写入 fdatasync(2)之后,来抑制缓存失效。
-D 使用direct I/O (O_DIRECT in open(2)).
-L 使用序列操作而不是随机操作,这相当于设置了默认大小,例如 -s 256k 与这个是相同的
-R 磁盘查找速度测试,这个选项将以人类可读模式输出每个请求
设置默认间隔为0, -i=0
停止测量将在3秒后停止 -w=3
设置工作集大小为64m -S=64m
-W 写而不是读。目录目标安全。写入 I/O 为不支持或在某种级别缓存非缓存读取从而提供更可靠的结果。对于file/device来说是危险的:这将会粉碎数据。
-Y 使用同步IO (O_SYNC in open(2)).
-y 使用数据同步IO (O_DSYNC in open(2)).
-k 重用临时工作目录文件 “ioping.tmp” (仅对于目标目录生效)
-q Suppress periodical human-readable output.

使用示例

RAW STATISTICS

1
2
$ ioping -p 100 -c 200 -i 0 -q .
100 16282962 6141 25155128 130599 162830 328499 37909 101 17115660

上面输出的结果意思为:

  • 统计请求的计数
  • 运行时间 usec 微秒
  • 每秒请求 (iops)
  • 传输速率 (bytes/sec)
  • 最小请求时间 (usec)
  • 平均请求时间 (usec)
  • 最大请求时间 (usec)
  • 请求时间偏差 (usec)
  • 总请求 (包含很慢和很快的)
  • 总共运行时间 (usec)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 使用默认值和当前目录 测试磁盘 I/O 延迟,ctrl - c 中断。
ioping .

# 测量/tmp设备的延迟,总计使用10个请求,每个请求1MB
ioping -c 10 -s 1M /tmp

# 测量 设备  /dev/sda 的查找速度
ioping -R /dev/sda

# 测试设备磁盘序列速度
ioping -RL /dev/sda

# 获取磁盘序列的速度(每秒多少字节)
ioping -RLB . | awk '{print $4}'

vnstat

vnstat是 Linux 中用于监控网络参数的命令,通常查看带宽消耗或一些流入或流出的流量,与网络接口上的流量。

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install -y vnstat
  • RHEL/CentOS/Fedora:epel yum install -y vnstat

vnstat是一个守护进程,如果需要记录需要启动这个服务才可以,而不是一个单独的命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 以小时显示流量
vnstat -h

# 以天显示流量
vnstat -d

# 以月为单位展示
vnstat -m

# 计算接口多长时间内的流量(这个是实时的,可以不用启动服务)
vnstat -tr 10 # 10 sec

# 指定一个接口
vnstat -i eth0

# 指定输出格式
vnstat --json
vnstat --xml

ifstat

ifstat是Linux下网络接口统计的命令

  • Ubuntu/Debian/Mint:apt install -y ifstat
  • RHEL/CentOS/Fedora:yum install -y ifstat
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 指定接口名
ifstat eth0

# 查看全部接口
ifstat -a

# 清除网络接口的数据
ifstat -z <interface_name>

# 展示x秒内网络数据的平均值
ifstat -t 10

iptraf

iptraf是Linux 中交互式的网络监控命令,通过交互式实现展示

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install -y iptraf-ng
  • RHEL/CentOS/Fedora:yum install -y iptraf-ng

iftop

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install -y iftop
  • RHEL/CentOS/Fedora:epel yum install -y iftop
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 指定端口的带宽统计
iftop -i enp0s8

# 隐藏顶部的流量刻度栏
iftop -b

# 不使用域名解析
iftop -n -i enp0s8

# 直接输出为文字,而不是交互式
iftop -t

# 显示指定子网的流量
iftop -F 192.168.2.0/24

# 根据source addr排序
iftop -o source

# 根据destnation addr排序
iftop -o destination

# 显示使用的带宽
iftop -B -i enp0s8

arpwatch

arpwatch是Linux上用于监视ARP记录的

各系统下的包名与安装

  • Ubuntu/Debian/Mint:apt install -y arpwatch
  • RHEL/CentOS/Fedora:epel yum install -y arpwatch
Option describe
-d debug模式
-f 设置用于存储 ethernet/ip address 的文件,默认在 /var/arpwatch/arp.dat
-i 指定默认接口
-n 指定本地网络
-u 指定用户或用户组
-Q The flags prevents arpwatch from sending reports by mail
-z 设置忽略的 IP范围,IP和掩码用 “/” 化为,如 -z 192.168.10.0/255.255.255.0
1
2
# 指定一个接口,命令并没有输出,当有新IP或MAC被改变时,会保存到/var/log/messages
arpwatch -i eth0

Reference

[1] perf Examples

[2] User-space introspection with Linux perf

[3] Getting Debugging Symbols

[4] Linux Perf Tools Tips

[5] 20 sar command examples in Linux

[6] A Guide to the htop command in Linux

本文发布于Cylon的收藏册,转载请著名原文链接~

链接:长期总结 - Linux性能分析命令

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」 许可协议进行许可。