这两天突然对火焰图起了兴趣,至于什么是systemtap、什么是火焰图这里我不多说了,网上有很多介绍,这里说记录一下我的安装过程以及
碰到的坑。

首先,最最重要的,确认内核版本!!! 一般文章都是说使用uname -r就可以了,但我就被这个问题坑了很久,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost]# uname -r
3.10.0-229.20.1.el7.x86_64
[root@localhost]# rpm -qa|grep kernel
kernel-headers-3.10.0-327.22.2.el7.x86_64
kernel-debuginfo-common-x86_64-3.10.0-229.20.1.el7.x86_64
kernel-debuginfo-3.10.0-229.20.1.el7.x86_64
kernel-3.10.0-229.20.1.el7.x86_64
kernel-3.10.0-229.el7.x86_64
kernel-devel-3.10.0-229.20.1.el7.x86_64
kernel-3.10.0-327.22.2.el7.x86_64
kernel-tools-libs-3.10.0-327.22.2.el7.x86_64
kernel-tools-3.10.0-327.22.2.el7.x86_64

这里可以看出,使用uname -r显示我的内核版本是3.10.0-229.20.1.el7.x86_64,可实际上内核版本应该是3.10.0-327.22.2.el7.x86_64

所以我安装了错误的devel,debuginfo后执行测试代码,报错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost ~]# stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'
Pass 1: parsed user script and 110 library script(s) using 220064virt/37636res/3136shr/34876data kb, in 280usr/20sys/305real ms.
semantic error: while resolving probe point: identifier 'kernel' at /usr/share/systemtap/tapset/linux/vfs.stp:882:18
source: probe vfs.read = kernel.function("vfs_read")
^
semantic error: missing x86_64 kernel/module debuginfo [man warning::debuginfo] under '/lib/modules/3.10.0-327.22.2.el7.x86_64/build'
semantic error: while resolving probe point: identifier 'vfs' at <input>:1:7
source: probe vfs.read {printf("read performed\n"); exit()}
^
semantic error: no match
Pass 2: analyzed script: 0 probe(s), 0 function(s), 0 embed(s), 0 global(s) using 230224virt/47628res/5088shr/42876data kb, in 110usr/70sys/174real ms.
Pass 2: analysis failed. [man error::pass2]

错误很明显,内核版本和我安装的程序版本不一致所造成的。所以,如果个人建议如果执行过yum update升级过内核,一定要重启机器。

问题找到后,使用rpm命令卸载掉版本错误的kernel-devel、kernel-debuginfo、kernel-debuginfo-common包重新安装:

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
yum --enablerepo=*-debuginfo --showduplicates list kernel kernel-devel kernel-debuginfo
可安装的软件包
kernel.x86_64 3.10.0-327.el7 base
kernel.x86_64 3.10.0-327.3.1.el7 updates
kernel.x86_64 3.10.0-327.4.4.el7 updates
kernel.x86_64 3.10.0-327.4.5.el7 updates
kernel.x86_64 3.10.0-327.10.1.el7 updates
kernel.x86_64 3.10.0-327.13.1.el7 updates
kernel.x86_64 3.10.0-327.18.2.el7 updates
kernel.x86_64 3.10.0-327.22.2.el7 updates
kernel-debuginfo.x86_64 3.10.0-123.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.1.2.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.4.2.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.4.4.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.6.3.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.8.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.9.2.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.9.3.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.13.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.13.2.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-123.20.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-229.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-229.1.2.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-229.4.2.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-229.7.2.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-229.11.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-229.14.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-229.20.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-327.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-327.3.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-327.4.4.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-327.4.5.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-327.10.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-327.13.1.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-327.18.2.el7 base-debuginfo
kernel-debuginfo.x86_64 3.10.0-327.22.2.el7 base-debuginfo
kernel-debuginfo.x86_64 4.4.12-301.el7 base-debuginfo
kernel-debuginfo.x86_64 4.4.13-303.el7.centos base-debuginfo
kernel-debuginfo.x86_64 4.4.14-201.el7.centos base-debuginfo
kernel-devel.x86_64 3.10.0-327.el7 base
kernel-devel.x86_64 3.10.0-327.3.1.el7 updates
kernel-devel.x86_64 3.10.0-327.4.4.el7 updates
kernel-devel.x86_64 3.10.0-327.4.5.el7 updates
kernel-devel.x86_64 3.10.0-327.10.1.el7 updates
kernel-devel.x86_64 3.10.0-327.13.1.el7 updates
kernel-devel.x86_64 3.10.0-327.18.2.el7 updates
kernel-devel.x86_64 3.10.0-327.22.2.el7 updates

这里一定要选择 同样的版本,然后进行安装:

1
yum --enablerepo=*-debuginfo install kernel-debuginfo-3.10.0-327.22.2.el7 kernel-devel-3.10.0-327.22.2.el7 systemtap

网上说要自己去网站下载,其实不用。默认情况下yum源中把debuginfo给禁用了,启用后就可以直接使用yum安装了。

安装完成后,再次执行测试代码:

1
2
3
4
5
6
7
8
[root@localhost]# stap -v -e 'probe vfs.read {printf("read performed\n"); exit()}'
Pass 1: parsed user script and 110 library script(s) using 220064virt/37636res/3136shr/34876data kb, in 320usr/40sys/350real ms.
Pass 2: analyzed script: 1 probe(s), 1 function(s), 4 embed(s), 0 global(s) using 346424virt/165124res/4184shr/161236data kb, in 2470usr/380sys/2897real ms.
Pass 3: translated to C into "/tmp/stapNLmHP1/stap_44be74d5ef233d456ccbd3bd3e171034_1659_src.c" using 346424virt/165444res/4504shr/161236data kb, in 30usr/80sys/99real ms.
Pass 4: compiled C into "stap_44be74d5ef233d456ccbd3bd3e171034_1659.ko" in 2570usr/520sys/3266real ms.
Pass 5: starting run.
read performed
Pass 5: run completed in 10usr/50sys/339real ms.

成功。

再简单记录一下安装成功后如何生成火焰图,首先下载nginx-systemtap-toolkitFlameGraph,这里为了简单我就
直接使用sample-bt来抓取数据:

1
2
3
4
5
[root@localhost nginx-systemtap-toolkit]# ./sample-bt -p 1643 -t 20 -u > a.bt
WARNING: Tracing 1643 (/usr/sbin/nginx) in user-space only...
WARNING: no or bad debug frame hdr
WARNING: No binary search table for eh frame, doing slow linear search for stap_e5e3efd7e0aa9b92e61d7eed4a6c46b6_11190
WARNING: Time's up. Quitting now...(it may take a while)

这个脚本的作用在文档里说的很清楚不再赘述,-p 指定了要调试的进程号,-t 表示监控20秒,-u 表示用户空间。可以使用-k抓取内核空间或同时使用俩者。

生成a.bt文件后,生成火焰图步骤如下:

1
2
./stackcollapse-stap.pl a.bt > a.cbt
./flamegraph.pl a.cbt > a.svg

最终,a.svg就是我们的火焰图了。