使用Systemtap跟踪系统调用 (一)

简介: SystemTap是一个诊断Linux系统性能或功能问题的开源软件。它使得对运行时的Linux系统进行诊断调式变得更容易、更简单。有了它,开发者或调试人员不再需要重编译、安装新内核、重启动等烦人的步骤。

systemtap介绍
SystemTap是一个诊断Linux系统性能或功能问题的开源软件。它使得对运行时的Linux系统进行诊断调式变得更容易、更简单。有了它,开发者或调试人员不再需要重编译、安装新内核、重启动等烦人的步骤。网上找了一张图可以比较清楚的说明它的工作原理:
image.png

systemtap安装:

1.安装步骤:

1.1 yum install systemtap

1.2 yum install kernel-devel kernel-headers gcc elfutils

1.3 通过 http://debuginfo.centos.org/7/x86_64/

下载kernel-debuginfo以及kernel-debuginfo-common,要下载对应内核版本的(错误版本会提示semantic error: no match等报错);

例如我的环境安装的内核版本为3.10.0-693.el7.x86_64:

所以我们需要下载如下两个包:

kernel-common-x86_64-3.10.0-693.el7.x86_64.rpm

kernel-debuginfo-common-x86_64-3.10.0-693.el7.x86_64.rpm

执行rpm安装依赖包:

1.4 执行stap-prep验证环境是否已经正常安装

如上这是一个常见错误,自动安装时没有匹配对kernel和kernel-devel版本,我们可以 卸载kernel-devel-3.10.0-1062.4.3.el7.x86_64,去官方源下载正确的头文件包装上。

安装完后测试stap是否可以正常工作:(永恒的hello world)

stap -e 'probe kernel.function("sys_open") {log("hello world") exit()}'

典型案例
我们想知道文件是谁创建的或者谁在访问这个文件,其实如果是后台daemon程序访问,且获取句柄后并没有立即释放那查询很简单,可以举例说明一下:

如上图用tail打开文件/root/.ssh/known_hosts,我们通过扫描/proc文件系统可以很快定位是进程号为7424的进程占用,再通过进程号返找进程名就行了,但是试想一下,如果程序没有一直占用这个句柄呢,是每次使用完就立即释放了呢,就没这么容易找了。下面看下systemtap是如何解决这个问题的,如下例子是利用systemtap跟踪系统调用sys_open的方法:

!/usr/bin/env stap

function is_open_creating:long (flag:long)

{

CREAT_FLAG = 4

if (flag & CREAT_FLAG)

{

        return 1

}

return 0

}

probe begin

{

printf("monitor file beginn")

}

probe kernel.function("sys_open")

{

    creating = is_open_creating($mode);

    filename = user_string_quoted(pointer_arg(1));

    if(creating)

    {

        printf("pid %ld (%s) create the file %s\n",pid(),execname(),filename);

    }

    else

    {

        printf("pid %ld (%s) open the file %s \n",pid(),execname(),filename);

    }

}

我们来测试一下效果:
image.png

如上是抓到的结果,可以看到PID,进程名以及对应的文件操作和文件名。

当我们发现系统硬盘I/O繁忙时,第一反应就是用pidstat和iotop看一下哪些进程使用I/O频繁,如下:(我们做dd写盘测试然后用两个工具分别统计一下)

如上分别是pidstat和iotop的结果,可以很清晰的看出高IO调用的进程。

这里还可以简单介绍下上述两个进程统计的I/O数据是从哪里来的,如下截图我们可以看到也是从/proc下面捞出来的:

rchar: //在read(),pread(),readv(),sendfile等系统调用中读取的字节数

wchar: //在write(),pwrite(),writev(),sendfile等系统调用中写入的字节数

syscr: //调用read(),pread(),readv(),sendfile等系统调用的次数

syscw: //调用write(),pwrite(),writev(),sendfile等系统调用的次数

read_bytes: //进程读取的物理I/O字节数,包括mmap pagein,在submit_bio()中统计的

write_bytes: //进程写出的物理I/O字节数,包括mmap pageout,在submit_bio()中统计

cancelled_write_bytes: //如果进程截短了cache中的文件,事实上就减少了原本要发生的写I/O

    从图中看貌似也非常容易就发现了该IO占用的进程,但是试想一下另一种常见情况如果占用I/O的进程不止一个,同时有高I/O占用的硬盘又不止一块呢,而我们又希望找出是那几个进程占用了具体哪个硬盘的I/O呢,此时上述两个工具已经帮不上太多忙了,这时候又可以请systemtap出马了:

! /usr/bin/env stap

global device_name

probe begin {

    device_name = $1 //设备名

    printf ("device name: %x\n", device_name)

}

probe kernel.function("submit_bio")

{

    dev = $bio->bi_bdev->bd_dev

    if (dev == device_name)

            printf ("[%s](%d) dev:0x%x rw:%d size:%d\n",

            execname(), pid(), dev, bio->bi_size)

}

这里我们的设备名需要转换为十进制表述方式具体方法如下:

image.png

其中Device type: fd,0就是我们想要的,我们的主设备号fd(12-bit),次设备号0(20-bit),转换后fd00000=265289728,这里我们做下echo 111 >/root/test往test文件写几个字节数据试试:

image.png

如上图:bash dev:0xfd00000 rw:1 size:4096 这里指进程号6125 往块设备dm-0写了4096字节数据,为什么是4096?可以去了解下块设备的读写操作以及文件系统的block size对读写性能的影响。

参考文献:

https://sourceware.org/systemtap/man/stap.1.html

https://sourceware.org/systemtap/documentation.html

http://www.redbooks.ibm.com/abstracts/redp4469.html

目录
相关文章
|
2月前
|
Rust 关系型数据库 C语言
使用uftrace跟踪bpf程序的执行
使用uftrace跟踪bpf程序的执行
|
4月前
|
监控 安全 Linux
Linux命令truss详解:系统调用跟踪的利器
`truss`(或`strace`)是Linux调试利器,用于跟踪系统调用和信号。它帮助开发者优化性能、调试错误和进行安全审计。通过附加到进程,记录调用细节、参数、返回值和错误。使用参数如`-d`显示调试信息,`-e`跟踪特定调用,`-o`输出到文件,`-p`跟踪指定进程。注意其对性能的影响,通常需要root权限,并建议过滤输出和结合其他工具分析。
|
存储 网络协议 Linux
高效调试与分析:利用ftrace进行Linux内核追踪(下)
高效调试与分析:利用ftrace进行Linux内核追踪
|
运维 前端开发 关系型数据库
高效调试与分析:利用ftrace进行Linux内核追踪(上)
高效调试与分析:利用ftrace进行Linux内核追踪
如何定位strace中系统调用在内核中的位置
要了解内核函数的含义,最好的方法,就是去查询所用内核版本的源代码。
42 0
|
消息中间件 运维 监控
Linux Command strace 调试跟踪(1)
Linux Command strace 调试跟踪(1)
Linux Command strace 调试跟踪(1)
|
缓存 监控 网络协议
Linux Command strace 调试跟踪(2)
Linux Command strace 调试跟踪(2)
Linux Command strace 调试跟踪(2)
|
Linux C语言
Linux strace检查程序的系统调用及时间
简介 strace常用来跟踪进程执行时的系统调用和所接收的信号。 在Linux世界,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通 过系统调用访问硬件设备。
1883 0