[转帖]小技巧!如何用 systemtap 排查问题

技巧,如何,systemtap,排查,问题 · 浏览次数 : 0

小编点评

## vfs.write.return {   if (@defined($file->f_path->dentry)) {   dev_nr=$file->f_path->dentry->d_inode->i_sb->s_dev inode_nr = $file->f_path->dentry->d_inode->i_ino }  else {   dev_nr=$file->f_dentry->d_inode->i_sb->s_dev inode_nr = $file->f_dentry->d_inode->i_ino }   if ($return &&     dev_nr == MKDEV($1,$2) &&      inject == \"on\\")  {# printf(\"dev %x func: %s\\", dev_nr, ppfunc())    ka_cnt++;    udelay($3);  }} ``` 这段代码展示了如何使用 vfs.write.return 来测试设备打开的异步操作。 **主要逻辑如下:** 1. 判断设备是否已经打开。 2. 如果已打开,获取设备的 ID。 3. 如果尚未打开,获取设备的 ID。 4. 如果打开,设置设备 ID、入口 ID、设备索引等变量。 5. 如果打开并成功,设置 udelay 时间。 6. 如果打开失败,设置 udelay 时间。 **程序运行过程中遇到了一些问题:** 1. 在 `if` 语句中使用 `@defined()` 运算符判断设备打开状态可能出现错误,因为 `@defined()` 函数只会在编译阶段被编译,而代码运行时可能尚未编译完成。 2. 在 `udelay()` 函数中使用 `sleep()` 函数会导致程序阻塞,无法进行后续的执行。 3. 在 `if` 语句中使用 `dev_nr` 进行比较可能会出现精度问题,建议使用 `eq` 或 `ne` 等比较运算符。 **总结:** 这段代码展示了如何使用 vfs.write.return 来测试设备打开的异步操作,但存在一些问题需要解决。建议对代码进行修改和调试,以确保其正常运行。

正文

https://www.modb.pro/db/79444

 

霸爷博客,干货满满。有两篇文章现在还记得,《Linux下如何知道文件被哪个进程写》[1]和《巧用Systemtap注入延迟模拟IO设备抖动》[2],周末突然想起来,发现能看懂了:)

本文虽然说是小技巧,可是难度一点也不低 ^_^

什么是 systemtap

Systemtap is a tool that allows developers and administrators to write and reuse simple scripts to deeply examine the activities of a live Linux system. Data may be extracted, filtered, and summarized quickly and safely, to enable diagnoses of complex performance or functional problems.

我们一般调试程序,业务程序加日志,打 log, 基本能满足需求。再不济,使用 strace、lsof、perf 足够看到性能瓶颈,可以参考我 go gc[3] 的文章。但是系统编程,就不能狂打日志,而且很多调用栈都处于 kernel space,那么普通的调试手段就显得捉襟见肘了。

此时 systemtap 就能派上用场,他会在内核函数加 probe 探针,对 kernel space 函数调用进行统计汇总,甚至可以对其进行干预。但是对 user space 调试支持不是很好。

安装

本机环境:DELL R720, Ubuntu 14.04 3.19.0-25-generic x86_64

apt-get  install systemtap systemtap-client systemtap-common systemtap-runtime systemtap-server -y

对于 centos 系统也一样,yum install 即可。此时还要使用执行 stap-prep 安装缺失的内核镜像调试包。比如我的就是

linux-image-3.19.0-25-generic-dbgsym_3.19.0-25.26~14.04.1_amd64.ddeb

遇到缺什么包直接安装,或是从网上下载。systemtap 最好不要用源码安装,涉及内核的包都很恶心,版本必须匹配,可以用 uname -r 查看。

1. Linux下如何知道文件被哪个进程写

有个文件,不定期的被修改,如果只是瞬间的写入,lsof 也没有办法,就算定期执行,也可能有缺失。那么此时 systemtap 就该大显身手了,先上代码:

#!/usr/bin/env stap

probe vfs.write, vfs.read
{
  if (@defined($file->f_path->dentry)) {
 dev_nr=$file->f_path->dentry->d_inode->i_sb->s_dev
 inode_nr = $file->f_path->dentry->d_inode->i_ino
 } else {
 dev_nr=$file->f_dentry->d_inode->i_sb->s_dev
 inode_nr = $file->f_dentry->d_inode->i_ino
 }
  # dev and ino are defined by vfs.write and vfs.read
  if (dev_nr == MKDEV($1,$2) && inode_nr==$3){
    printf ("%s(%d) %s 0x%x/%u\n",execname(), pid(), ppfunc(), dev_nr, inode_nr)
   }
}

probe timer.ms(10) {
 exit()
}

语法类似 awk 代码很简单,probe 定义探针,后面紧跟着探测点,可以是具体的函数名,支持 * 匹配,大括号定义探针触发动作。

file 是函数 vfs.read, vfs.write 的参数,dev_nr,inode_nr 根据 file 结构体获取设备号和 inode,探测点是针对内核函数的,所以可以获取函数所有参数。

execname 执行 vfs.write 或 vfs.read 程序名

pid 执行 vfs.write 或 vfs.read 进程号

ppfunc 是控测点函数名,这个内置函数在不同版本可能不一样,比如霸爷文章里是 probefuc

1.1 开终端执行 dd

打开终端执行 dd 不断的写入数据,并查看文件 inode 号

dd if=/dev/zero of=test.dat
stat -c "%i" /disk1/test.dat
ls -al /dev/sdb1

这里 dev/sdb1 是挂载在 disk1 目录下的设备

1.2 执行 stap 探测

stap -v inodewatch.stp 8 17 15
Pass 1: parsed user script and 95 library script(s) using 84976virt/30204res/5152shr/25852data kb, in 200usr/0sys/456real ms.
Pass 2: analyzed script: 3 probe(s), 7 function(s), 5 embed(s), 0 global(s) using 610884virt/195324res/12432shr/180716data kb, in 1810usr/290sys/3605real ms.
Pass 3: translated to C into "/tmp/stapJEOYcQ/stap_20c430109956cd1ffc28c7ceaf0aa2f1_6899_src.c" using 599240virt/188844res/8908shr/180712data kb, in 0usr/0sys/73real ms.
Pass 4: compiled C into "stap_20c430109956cd1ffc28c7ceaf0aa2f1_6899.ko" in 1840usr/320sys/4180real ms.
Pass 5: starting run.
dd(25763) vfs_write 0x800011/15
dd(25763) vfs_write 0x800011/15
dd(25763) vfs_write 0x800011/15
dd(25763) vfs_write 0x800011/15
dd(25763) vfs_write 0x800011/15
Pass 5: run completed in 0usr/40sys/724real ms.

stap 执行脚本需要 5 个步骤,解析脚本,分析,生成 c 代码,编绎成内核模块 ko 文件。最后执行模块,可以看到 dd 任务在写文件,调用 vfs_write

2. 巧用Systemtap注入延迟模拟IO设备抖动

霸爷的这篇例子很有意思,systemtap 模拟磁盘 IO 抖动,对于一些存储系统,压测时可以试一下。原理还是很简单的,在 vfs_write, vfs_read 时 sleep 一小段时间即可,时间可以随机。先上代码

cat inject_ka.stp
global inject, ka_cnt

probe procfs("cnt").read {
  $value = sprintf("%d\n", ka_cnt);
}
probe procfs("inject").write {
  inject= $value;
  printf("inject count %d, ka %s", ka_cnt, inject);
}

probe vfs.read.return,
      vfs.write.return {
  if (@defined($file->f_path->dentry)) {
 dev_nr=$file->f_path->dentry->d_inode->i_sb->s_dev
 inode_nr = $file->f_path->dentry->d_inode->i_ino
 } else {
 dev_nr=$file->f_dentry->d_inode->i_sb->s_dev
 inode_nr = $file->f_dentry->d_inode->i_ino
 }

  if ($return &&
      dev_nr == MKDEV($1,$2) &&
      inject == "on\n")
  {
# printf("dev %x func: %s\n", dev_nr, ppfunc())
    ka_cnt++;
    udelay($3);
  }
}

probe begin{
  println("ik module begin:)");
}

代码有些略长,先看探针 probe vfs.read.return, vfs.write.return 表示在退出前执行探针代码,判断 dev_nr 是不是目标设备,并且打开了 ineject, 如果打开,那么 udelay 一小段时间。

至于另外两个探针,procfs("cnt"), procfs("inject") 读取 proc/systemtap 时触发,修改全局变量 inject 来决定是否打开 IO 注入。

2.1 执行代码

这个脚本执行可能会遇到 vfs_lookup_path 报错,很恶心,我把 procfs.c 升级了一个版本,并注释掉 vfs_lookup_path 部分才解决 ...

stap -DMAXSKIPPED=9999 -m ik -g inject_ka.stp 8 17 400
ik module begin:)

8,17 表示磁盘设备号,400表示 udelay 时间,此时脚本阻塞在这里,并没有开始执行 IO 注入。打开另一个终端执行注入,持续 30 秒。

echo on| tee /proc/systemtap/ik/inject  && sleep 30 && echo off| tee /proc/systemtap/ik/inject

此时可以看到 stap 有输出。

2.2 测试磁盘性能

简单的使用 dd 来测试 IO 延迟对顺序写的影响

注入前

dd if=/dev/zero of=test.dat  bs=8k count=1000000
1000000+0 records in
1000000+0 records out
8192000000 bytes (8.2 GB) copied, 34.8372 s, 235 MB/s

注入后

dd if=/dev/zero of=test.dat  bs=8k count=1000000
1000000+0 records in
1000000+0 records out
8192000000 bytes (8.2 GB) copied, 79.5475 s, 103 MB/s

可以看到 dd 性能下降很大,通过调整  udelay 时间可以模拟不同延迟下的性能。如果是随机的,或是符合正态分布的可能更好。

小结

官网[4] 有很多 systemtap 使用例子和介绍,还可以抓网络协议栈,性能很强大。同时需要有一定的内核功底,至少要知道探针埋在哪里,openresty 大量使用 systemtap 进行调试,可以参考学习。

另外,安装是个很大问题,一定要注意版本,太新也不可以,ubuntu 系统 apt 源是 2.3,尝试过源码安装高版本,各种报错。

今天的分享就这些,写文章不容易,如果对大家有所帮助和启发,请大家帮忙点击再看
点赞
分享
三连

关于 systemtap 大家有什么看法,欢迎留言一起讨论 ^_^

参考资料

[1]

Linux下如何知道文件被哪个进程写: http://blog.yufeng.info/archives/2581#more-2581,

[2]

巧用Systemtap注入延迟模拟IO设备抖动: http://blog.yufeng.info/archives/2935,

[3]

go gc: https://www.jianshu.com/p/0791c35d3609,

[4]

systemtap 官网: https://sourceware.org/systemtap/examples/,

与[转帖]小技巧!如何用 systemtap 排查问题相似的内容:

[转帖]小技巧!如何用 systemtap 排查问题

https://www.modb.pro/db/79444 霸爷博客,干货满满。有两篇文章现在还记得,《Linux下如何知道文件被哪个进程写》[1]和《巧用Systemtap注入延迟模拟IO设备抖动》[2],周末突然想起来,发现能看懂了:) 本文虽然说是小技巧,可是难度一点也不低 ^_^ 什么是 s

[转帖]性能优化必备——火焰图

引言 本文主要介绍火焰图及使用技巧,学习如何使用火焰图快速定位软件的性能卡点。结合最佳实践实战案例,帮助读者加深刻的理解火焰图构造及原理,理解 CPU 耗时,定位性能瓶颈。 背景 当前现状 假设没有火焰图,你是怎么调优程序代码的呢?让我们来捋一下。 1. 功能开关法 想当年我刚工作,还是一个技术小白

[转帖]Linux小技巧:获取前一天日期、前一个月日期

最近脚本需要获取Linux前一天时间格式,用于设置日志文件名,网上查了查资料,这里记录一下。 1.date命令 1.1 date命令使用格式 date [-u] [-d datestr] [-s datestr] [--utc] [--universal] [--date=datestr] [--s

[转帖]一个小技巧解决笔记本HDMI接口失灵

https://baijiahao.baidu.com/s?id=1738289993804283647&wfr=spider&for=pc 现如今笔记本的接口是越来越多,哪怕是标榜无线化的苹果,也在MacBook Pro的接口上开起了“倒车”,不过这个问题只能说是智者见智,对于追求便携的用户来说接

[转帖]分享6个SQL小技巧

https://www.jianshu.com/p/2fcf0a4e83b7 简介 经常有小哥发出疑问,SQL还能这么写?我经常笑着回应,SQL确实可以这么写。其实SQL学起来简单,用起来也简单,但它还是能写出很多变化,这些变化读懂它不难,但要自己Get到这些变化,可能需要想一会或在网上找一会。 各

[转帖]SC命令管理服务状态

https://www.jianshu.com/p/e9b3079f9771 使用cmd命令手动、自动启动和禁用服务 小技巧使用命令行启动服务 在cmd下可有两种方法打开,net和sc,net用于打开没有被禁用的服务,语法是: net start 服务名 启动 net start 服务名net st

[转帖]shell 篇 用上今天分享的快捷键以后,我早下班了一小时

每次看着别人操作 shell 的时候,快捷键用得飞起,尤其是那个快速搜索历史命令,避免低效的↑↓键切换历史命令,很装逼有木有。。 废话不多说,下面是我整理的常用快捷键,真的可以提高自己的工作效率的,很不错!~ 一、常用快捷键小技巧 以下快捷键,都是一些常用的,记住这些命令,你的工作效率就会大大提升。

[转帖]电脑技巧:磁盘空间分析工具SpaceSniffer介绍

https://zhuanlan.zhihu.com/p/568310893 今天继续给大家分享一款磁盘空间分析工具SpaceSniffer,有需要下载地址可以私信小编获取。 1、简介 SpaceSniffer是由Uderzo公司研发的一款磁盘空间分析软件,安装包体积也只有2.3MB。 功能:主要是

[转帖]实用小技能:一键获取Harbor中镜像信息,快捷查询镜像

【摘要】一键获取Harbor中的镜像列表,无需登录harbor UI,也可批量下载镜像到本地并保存为tar包。本文已参与「开源摘星计划」,欢迎正在阅读的你加入。活动链接: https://github.com/weopenprojects/WeOpen-Star 前言 我们要查询Harbor中某个项

[转帖]【技术剖析】10. JVM 中不正确的类加载顺序导致应用运行异常问题分析

https://bbs.huaweicloud.com/forum/thread-169439-1-1.html 神Bug... 发表于 2021-11-15 10:36:113973查看 作者:程经纬、谢照昆 > 编者按:两位笔者分享了不同的案例,一个是因为 JDK 小版本升级后导致运行出错,最终