SystemTap 是一种新颖的 Linux 内核诊断工具,提供了一种从运行中的 Linux 内核快速和安全地获取信息的能力。SystemTap 是内核开发人员和系统管理员的福音,因为这使得他们可以通过编写或者重用简单的脚本来收集内核的实时数据,而不需要再忍受修改源码、编译内核、重启系统的漫长煎熬。本文介绍了 SystemTap 的安装、使用和基本原理,并用一些有趣的例子揭示了 SystemTap 提供的强大能力。
在 SystemTap 出现之前,对于 Linux 程序员或者系统管理员而言,调试内核往往是一场噩梦。例如,你怀疑传递给系统调用 read 的参数 fd 出了问题,想把它打印出来,你需要做的是:首先得到一份内核源码,找到 sys_read() 的函数体中插入 printk() 语句,接下来重新编译内核,然后用新的内核重新启动系统。谢天谢地,你总算看到了你想要看到的东西,不过你马上会发现遇到了一个新的麻烦:除非重新启动系统到原来的内核,printk() 会无休止地打印下去。
SystemTap 的目的就是要把人们从这种泥潭中解救出来。SystemTap 提供了一个简单的命令行接口和强大的脚本语言,同时预定义了丰富的脚本库。基于内核中的 kprobe,SystemTap允许你自由地从运行中的内核无害地收集调试信息和性能数据,来用于之后的分析和处理。你可以随时开始或者停止这种收集过程,而无需漫长的修改代码、编译内核和重启系统的悲惨循环。SystemTap 使得上面的问题变得简单了,简单得只需要一条命令就可以做到:
stap -e 'probe syscall.read { printf("fd = %d\n",fd) } |
SystemTap的功能和Sun的DTrace和IBM的dprobe工具相似。但是和它们不同的是, SystemTap是遵循GPL的开源软件项目。它的出现使得Linux社区也拥有了功能强大而且易于使用的动态内核调试工具。目前,SystemTap 的主要开发成员来自于RedHat、IBM、Intel和Hitachi,其中还包括来自IBM中国开发中心的工程师。
安装SystemTap
在安装SystemTap之前,需要确保系统中已经安装了其它两个软件包:
接下来就可以安装SystemTap了,这有通过RPM或者源码安装两种方式:
1. 通过RPM安装 Fedora Core 6缺省情况下已经安装了systemtap。如果没有,也可以从如下的地址下载: http://download.fedora.redhat.com/pub/fedora/linux/
core/updates/testing/6/i386/SystemTap-0.5.10-1.fc6.i386.rpm
2.通过源码安装:
从SystemTap的FTP站点下载最新的源码
ftp://sources.redhat.com/pub/SystemTap/snapshots/SystemTap-20061104.tar.bz2
然后安装如下:
/root > tar -jxf SystemTap-20061104.tar.bz2 /root > cd src /root/src> ./configure /root/src> make /root/src> make install |
运行SystemTap
运行SystemTap首先需要root权限。
运行SystemTap有三种形式:
1. 从文件(通常以.stp作为文件名后缀)中读入并运行脚本:stap [选项] 文件名
2. 从标准输入中读入并运行脚本: stap [选项] -
3. 运行命令行中的脚本:stap [选项] -e 脚本
4. 直接运行脚本文件(需要可执行属性并且第一行加上#!/usr/bin/stap):./脚本文件名使用"Ctrl+C"中止SystemTap的运行。
systemtap的选项还在不断的扩展和更新中,其中最常用的选项包括:
-v -- 打印中间信息
-p NUM -- 运行完Pass Num后停止(缺省是运行到Pass 5)
-k -- 运行结束后保留临时文件不删除
-b -- 使用RelayFS文件系统来将数据从内核空间传输到用户空间
-M -- 仅当使用-b选项时有效,运行结束时不合并每个CPU的单独数据文件
-o FILE -- 输出到文件,而不是输出到标准输出
-c CMD -- 启动探测后,运行CMD命令,直到命令结束后退出
-g -- 采用guru模式,允许脚本中嵌入C语句
其它更多选项请参看stap的手册。
SystemTap的语法
我们利用一个简单的systemtap脚本来介绍一下SystemTap的语法:
#!/usr/local/bin/stap global count function report(stat) { printf("stat=%d\n", stat) } probe kernel.function("sys_read") { ++count } probe end { report() } |
function report(stat) %{ _stp_printf("stat=%d\n", THIS->stat); %} |
SystemTap的例子
了解了SystemTap的基本用法,下面让我们来看几个有趣的例子。
统计当前系统中调用最多的前10个系统调用
在进行性能分析的时候,我们常常需要知道那些函数调用次数最多,才能有的放矢地展开分析。下面这个简单的例子可以打印出在过去的5秒钟里调用次数最多的那些系统调用。
#!/usr/bin/env stap # # display the top 10 syscalls called in last 5 seconds # global syscalls function print_top () { cnt=0 log ("SYSCALL\t\t\t\tCOUNT") foreach ([name] in syscalls-) { printf("%-20s\t\t%5d\n",name, syscalls[name]) if (cnt++ == 10) break } printf("--------------------------------------\n") delete syscalls } probe syscall.* { syscalls[probefunc()]++ } probe timer.ms(5000) { print_top () } |
它的输出结果一目了然:
看看是谁在偷偷动我的文件
有时候,我们如果中了恶意的病毒软件,会发现某些文件莫名其妙的被修改,下面这个例子可以帮你监视谁在修改你的文件。
#!/usr/bin/env stap # # monitor who is messing my file of secrets # probe generic.fop.open { if(filename == "secrets") printf("%s is opening my file: %s\n", execname(), filename) } |
我们运行这个脚本,在另外一个窗口做一些操作,来看看它的输出结果:
上一页 [1] [2] [3] 下一页
打印ANSI字符串
SystemTap不仅仅是一个简单的调试工具,强大的脚本语言能力让它同样能做一些有趣的事情,
下面这个例子就可以对输出的字符进行美化:
#!/usr/bin/env stap # # print colorful ANSI strings # probe begin { printf("a \\ b |"); for (c = 40; c < 48; c++) printf(" %d ", c); printf("\12"); for (l = 0; l < 71; l++) printf("-"); printf("\12"); for (r = 30; r < 38; r++) for (t = 0; t < 2; t++) { printf("%d |", r); for (c = 40; c < 48; c++) printf("\033[%d;%d%s %s \033[0;0m", r, c, !t ? "m" : ";1m", !t ? "Normal" : "Bold "); printf("\12"); } exit(); } |
来看看它的输出:
SystemTap的基本原理
现在,大家已经熟悉了SystemTap的基本用法。在结束之前,让我们再来了解一下SystemTap的基本原理和工作流程以加深理解。
可以看出,SystemTap运行的过程依次分为五个阶段,通常称为Pass 1 - Pass 5。就像前面介绍用法的时候提到的,在命令行中加上-p NUM选项可以使得SystemTap在运行完Pass NUM之后停止,而不是运行到Pass 5。这允许你分析SystemTap在每一个阶段的输出,对于调试脚本尤其有用。
下面来介绍每一个阶段的主要功能:
小结
SystemTap是一个全新的工具,但已经表现出了强大的功能和广泛的适用性。SystemTap使得动态收集Linux内核信息和性能数据变得轻而易举,这就使人可以从繁琐的数据采集中解放出来,而专注于数据的处理和分析,这无疑是内核开发人员和系统管理人员的福音。随着越来越多用户的体验,越来越多的bug会被报告和修正,越来越多的新功能会被添加,SystemTap也会变得越来越稳定和完善。
原文链接:http://www-128.ibm.com/developerworks/cn/linux/l-systemtap/index.html
上一页 [1] [2] [3]