Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap
Systemtap的原理,Systemtap与DTrace比较,以及安装要求和安装步骤
本系列文章详细地介绍了一个Linux下的全新的调式、诊断和性能测量工具Systemtap和它所依赖的基础kprobe以及促使开发该工具的先驱DTrace并给出实际使用例子使读者更进一步了解和认识这些工具。 本文是该系列文章之三,它讲解了Systemtap的原理,Systemtap与DTrace比较,以及安装要求和安装步骤,最后通过一个例子向读者展示Systemtap的工作机理。本系列文章之一讲解了kprobe的原理、编程接口、局限性和使用注意事项并给出实际使用示例帮助读者理解和认识kprobe。本系列文章之二讲解了DTrace的原理。
一、简介
SystemTap是一个诊断Linux系统性能或功能问题的开源软件。它使得对运行时的Linux系统进行诊断调式变得更容易、更简单。有了它,开发者或调试人员不再需要重编译、安装新内核、重启动等烦人的步骤。
为了诊断系统问题或性能,开发者或调试人员只需要写一些脚本,然后通过SystemTap提供的命令行接口就可以对正在运行的内核进行诊断调试,以前需要的修改或插入调试代码、重新编译内核、安装内核和重启动等这些琐碎的工作完全消除。目前该工具并不支持对用户态应用的诊断调试,但是它们在以后会被添加进去。当前该项目的主要开发人员为来自Red Hat, IBM, Intel和Hitachi的工程师。其中Redhat主要负责脚本转换/翻译器和运行时库,IBM负责kprobe和relayfs,Intel负责转换器安全检查以及performance monitor tapset。
二、Systemtap原理
Systemtap使用了类似于awk和C语言的脚本语言(类似于Dtrace的D语言),它只使用了三种数据类型,整数(integers)、字符串(strings)以及关联数组(associative Arrays),它有完整的控制结构,包括块(blocks)、条件(conditionals)、循环(loops)和函数(functions)。语句分割符;是可选的,变量不需要声明类型,它们是根据上下文自动推测和检查的,它使用了kprobe提供的接口来实现探测,对于每一个探测,需要定义探测点以及相应的处理函数,探测点就是指kprobe中被探测的函数或指令地址(也被称为内核事件)的),但在Systemtap中,用户可以指定原文件,原代码的某一行,或者一个异步事件,如周期性的定时器,探测点使用了层次化的命名方式,探测点处理函数能够立刻输出数据,与printk很类似,它也能查看内核数据。脚本然后被一个翻译器转换成C代码并编译成一个内核模块。探测点根据内核的DWARF调试信息映射到内核的虚地址(因此Systemtap要求用户必须准备好可用的内核调试信息),所有的脚本内容在转换时进行严格的检查,并且在运行时也要检查(如无限循环、内存使用、递归和无效指针等),因此有好的安全性,不会影响正在运行的系统(这对生产系统是非常重要的)。 Systemtap包含了一个黑名单,其中列出的函数不能被Systemtap探测,因为它们会导致无限探测循环、锁重入等问题。
下图直观地给出了Systemtap的工作原理:
Systemtap脚本文件是.stp后缀的文件,使用的脚本语言是前面讲到的Systemtap自己定义的脚本语言,一个Systemtap脚本描述了将要探测的探测点以及定义了相关联的处理函数,每一个探测点对应于一个内核函数或事件或函数内部的某一位置。被关联的处理函数将在内核执行到对应的探测点时被执行。
tapsets是一个脚本库,包含了许多tapset,每一个tapset一般为某一内核子系统或特定的功能块预定义了一套探测点、辅助函数或全局变量供用户脚本或其它的tapset引用,它定义的一些数据能够被每一个探测点处理函数或脚本使用,这些数据通常通过使用处理函数语句块(HSB Handler Statement Block)来出口,HSB语句块中的变量就是被出口的数据。tapset一般由该内核子系统的开发者或对子系统非常了解的开发者编写,既使用了脚本语言,也使用了C语言,并且它已经被测试和验证,可以安全使用。tapsets属于Systemtap发行包的一部分。
Systemtap实现了一个脚本转换器/翻译器,当用户执行一个Systemtap脚本时,Systemtap将首先对它进行分析和一些安全检查,如果它引用了Systemtap预定义的脚本库提供的函数,Systemtap也将读取脚本库得到相应的代码,对于一些内核变量或符号的引用,它必须根据内核调试信息来解析到相应的地址。然后,它被转换成C代码,在这个转换中,Systemtap将根据需要增加必要的锁和安全检查代码。探测点之间共享的变量将被转换成恰当的静态声明并有锁保护,每组本地变量被转换到一个合成的调用帧结构中以避免消耗内核的栈空间。关联到探测点的处理函数被封装成一个接口函数,那调用恰当的kprobe接口函数来注册该探测点。
产生的C代码包含了一些对运行时tapset的引用,运行时tapset库提供了许多Systemtap接口函数,如通用的查询表、受限内存管理、启动、关闭、I/O操作以及其它一些函数。生成的C代码编译链接之后生成一个可加载的内核模块。为了快速得到运行结果,Systemtap使用了relayfs,当加载生成的内核模块后,该模块的初始化函数初始化自身,然后调用kprobe接口函数注册脚本中定义的探测点。当内核运行到注册的探测点时,相应的处理函数被调用,用户在处理函数中的输出语句将调用relayfs接口函数输出结果数据,用户在处理函数也可以调用一些内核的性能测量函数。当用户主动停止或脚本设定的条件满足时,模块将调用退出函数卸载已经注册的探测点并做一些清理处理就卸载模块自身。
Systemtap在运行时启动了一个进程,它专门负责通过relayfs读去模块的输出数据并即时地输出给用户。
三、SystemTap与DTrace比较
项目方面:
使用的语言:
探测能力:
安全性:
图形用户界面:
四、Systemtap的安装
运行Systemtap的前提条件是:
- 内核支持并配置了kprobe(2.6.11和以上)
- 内核模块编译环境(即编译内核模块所需的内核头文件以及模块配置信息,对于Fedora core或Redhat指kernel-devel或kernel-smp-devel RPM包)
- 内核调试信息(对于Fedora core或Redhat指kernel-debuginfo RPM包)
- C编译环境(即libc库头文件和编译工具链)
- 有libdwfl的elfutils(只有支持libwdfl的elfutils,systemtap才能正常工作,如果您的系统的elfutils较旧,您必须下载elfutils源码包来编译,systemtap能够和elfutils一块编译)
- root权限(为了运行Systemtap,您必须具有root权限)
如果您使用的是Fedora core 4或更新的Fedora core版本,安装Systemtap非常容易:
# yum install kernel-devel
# yum --enablerepo=core-debuginfo --enablerepo=updates-debuginfo \
install kernel-debuginfo
# yum install systemtap
然后运行下面命令可以验证是否成功。
# stap -ve 'probe begin { log("hello world") exit () }'
# stap -c df -e 'probe syscall.* { if (target()==pid()) log(name." ".argstr) }'
如果您想安装最新的Systemtap,您可以自己用源码包来构建,其步骤是:
1.确保elfutils支持libdwlf
如果您的elfutils并没有libdwlf,您需要下载它。
Systemtap能自动build它,因此对于这种情况,您只需下载最新的elfutils
ftp://sources.redhat.com/pub/systemtap/elfutils/elfutils-NNNN.tar.gz
ftp://sources.redhat.com/pub/systemtap/elfutils/elfutils-portability.patch
,解压elfutils-NNNN.tar.gz并打上补丁elfutils-portability.patch.具体命令如下:
# cd /home/yangyi
# wget ftp://sources.redhat.com/pub/systemtap/elfutils/elfutils-NNNN.tar.gz
# wget ftp://sources.redhat.com/pub/systemtap/elfutils/elfutils-portability.patch
# tar zxvf elfutils-NNNN.tar.gz
# cd elfutils-NNNN
# patch p0 ../ elfutils-portability.patch
2. 下载Systemtap源码包并解压
# cd /home/yangyi
# wget ftp://sources.redhat.com/pub/systemtap/snapshots/systemtap-YYYYMMDD.tar.bz2
# tar -jxvf systemtap-YYYYMMDD.tar.bz2
# cd systemtap-YYYYMMNN/src
或
# cvs -d :pserver:anoncvs@sources.redhat.com:/cvs/systemtap login
注:密码是anoncvs
# cvs -d :pserver:anoncvs@sources.redhat.com:/cvs/systemtap co src
# cd src
3.安装
# ./configure [--with-elfutils=/home/yangyi/elfutils-NNNN] [other autoconf options]
# make all check
# make install
注意,选项—with-elfutils带的参数是elfutils的源码包的路径,如果您已经安装了最新的elfutils,这个选项是不必要的.
对于其它Linux发行,没有便捷的安装方式可利用,您必须自己构建内核并设置Systemtap要求的前提条件。有时,您可能想使用最新的内核,您也可以使用这种方式来做。
要想编译一个支持Systemtap的内核,您必须配置这些内核选项:
Kernel hacking --->
[*] Kernel debugging
[*] Compile the kernel with debug info Instrumentation Support --->
[*] Kprobes (EXPERIMENTAL) General setup --->
[*] Kernel->user space relay support (formerly relayfs)
您可以用以下符号grep生成的配置文件.config来确认这些配置是否成功:
CONFIG_DEBUG_INFO
CONFIG_KPROBES
CONFIG_RELAY
如果成功,它们应当都为Y.
在使用该构建好的内核启动系统后,您必须确保Systemtap能够找到该内核对应的内核映像文件(即vmlinux), 该映像必须为非压缩的没有去掉调试和符号信息的内核映像(就是在内核构建根目录下的vmlinux文件),Systemtap将会在以下三个位置
/boot/vmlinux-`uname -r`
/usr/lib/debug/lib/modules/`uname -r`/vmlinux
/lib/modules/`uname -r`/vmlinux
寻找该内核映像,因此您必须确保它在这三个位置的其中一个上。当然这三个可以是符号链接。
您也需要建立以下两个符号链接指向您的内核的源码树。
/usr/src/kernels/`uname -r`
/lib/modules/`uname -r`/source
您还需要建立以下符号链接指向您的内核的build树。
/lib/modules/`uname -r`/build
例如, 假定您的内核源码树是/home/yangyi/linux-2.6.20,您的内核build树是/home/yangyi/kernel-build
(注意,2.6内核的build目录可以和源码目录不同,具体做法是
cd /home/yangyi/linux-2.6.20
make O=/home/yangyi/kernel-build menuconfig
make O=/home/yangyi/kernel-build
sudo make O=/home/yangyi/kernel-build modules_install install
这样同一个源码树可以做多个build,各build可以根据需要重新build而不影响其他的build,因此建议大家使用这种方式build内核。 )
特别提醒,您的系统现在启动的必须是您按刚才要求编译好的内核,否则在执行下面的操作之前您必须用该内核启动您的系统。
# ln -s /home/yangyi/linux-2.6.20/vmlinux /boot/vmlinux-`uname -r`
# mkdir -p /usr/src/kernels
# ln -s /home/yangyi/linux-2.6.20 /usr/src/kernels/`uname -r`
# mkdir -p /lib/modules/`uname -r`
# ln -s /home/yangyi/kernel-build /lib/modules/`uname -r`/build
# ln -s /home/yangyi/linux-2.6.20 /lib/modules/`uname -r`/source
对于使用debian Linux的读者,您可以使用如下的方式安装Systemtap:
# apt-get build-dep systemtap
# apt-get --compile source systemtap
# dpkg -i systemtap*deb
如果您想在debian Linux中为Systemtap使用新的内核,您可以按下面的步骤去做:
1. 下载并配置最新的内核源码包
# apt-get install linux-source-2.6.20 kernel-package fakeroot
# cd /usr/src
# tar jxvf linux-source-2.6.20.tar.bz2
# cd linux-source-2.6.20
# cp /boot/config-2.6-xxxxxxxx .
# make menuconfig
配置以下内核选项:
Kernel hacking --->
[*] Kernel debugging
[*] Compile the kernel with debug info Instrumentation Support --->
[*] Kprobes (EXPERIMENTAL) General setup --->
[*] Kernel->user space relay support (formerly relayfs)
2.添加下行到文件/etc/kernel-pkg.conf
install_vmlinux = YES
3.构建内核
# fakeroot make-kpkg --initrd --append-to-version=-systemtap-1.0 \
kernel_image kernel_headers
注意两个选项:--initrd让kernel-package构建initrd,--append-to-version将修改命令uname -a的输出中出现的内核名称,您可以指定为您喜欢的名称。参数kernel_image表示构建内核映像,参数kernel_headers表示构建内核头文件。
4.安装定制的内核
dpkg -i ../kernel-image-2.6.20-systemtap-1.0_10.00.Custom_i386.deb
dpkg -i ../kernel-headers-2.6.20-systemtap-1.0_10.00.Custom_i386.deb
注意,您构建的deb包的名称依赖于您选择的内核以及构建时的参数。
5.拷贝您的内核build目录到/lib/modules/<your new kernel version>/build
五、使用实例详解
下面给出一个简单的例子详细解释systemtap的工作原理。
这个stp脚本将每隔5秒钟输出系统调用的最多的20个系统调用。
#!/usr/bin/env stap
#
# This script continuously lists the top 20 systemcalls on the system
# 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++ == 20)
break
}
printf("--------------------------------------\n")
delete syscalls
} probe kernel.function("sys_*") {
syscalls[probefunc()]++
} # print top syscalls every 5 seconds
probe timer.ms(5000) {
print_top ()
}
该脚本第一行指定了脚本的解释器stap,它首先将分析该脚本并把它转换成C语言的代码,然后进行编译,和systemtap安装时带的库进行链接,产生一个内核模块并把它加载到系统中,最后启动一个用户态进程不停得从systemtap提供的relayfs接口读取数据并显示到屏幕上。
#表示注释,类似于shell语法。
语句global syscalls声明syscalls是一个全局变量。
注意,stp并不需要分号这样的语句分割符。
function print_top()定义一个函数print_top,这与shell的语法类似。
Systemtap实现了强大的输出支持, log和printf用的比较多,其中printf与C语言中的printf语法一样。循环语句foreach ([name] in syscalls-)表示把syscalls数组按降序排列然后遍历每一个它的元素, name将保存得到的元素的下标,在该实例中就是系统调用名称, 因而syscalls实际是一个关联数组。 读者不难看出print_top函数就是输出syscalls数组中值最大的二十个元素。
probe kernel.function(“sys_*)为每一个以sys_开头的内核函数定义一个kprobe探测点以及相应的探测点处理函数。对内核熟悉的读者一看就知道以sys_开头的内核函数就是系统调用。它定义的探测点函数是为相应的系统调用记数器加1。
probe timer.ms(5000)声明了一个5000毫秒的定时器探测点(kprobe现在已经支持定时器探测点),相应的探测点处理函数将调用print_top输出系统调用的最多的20个系统调用的名称和调用次数。
更多关于stp脚本语言的语言参考能在最新的systemtap的源码包中找到,有兴趣的读者可以看看。需要特别提醒该脚本在编译链接后生成了一个内核模块,因此它运行在内核态,所有用户在执行该脚本后看到的输出都是stap启动的用户态进程通过systemtap提供的relayfs接口从内核读取出来才显示到屏幕上的。
小结
本文详细地讲解了Systemtap的工作原理并通过与Dtrace比较让读者了解Systemtap的来由和与现存工具的异同。为了让读者能够根据自己使用的Linux发行版方便安装Systemtap,本文详细讲解了几种安装方式。最后通过一个实际的例子让读者真正体会一下Systemtap与kprobe的关系和运行机理。本文是系列文章“Linux下的一个全新的性能测量和调式诊断工具 -- Systemtap”之三,有兴趣的读者可以阅读该系列文章之一和二。
Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap的更多相关文章
- Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 2 部分: DTrace
DTrace的原理本系列文章详细地介绍了一个 Linux 下的全新的调式.诊断和性能测量工具 Systemtap 和它所依赖的基础 kprobe 以及促使开发该工具的先驱 DTrace 并给出实际使用 ...
- Linux 下的一个全新的性能测量和调式诊断工具 Systemtap,第 1 部分: kprobe
kprobe 的原理.编程接口.局限性和使用注意事项 本系列文章详细地介绍了一个Linux下的全新的调式.诊断和性能测量工具Systemtap和它所依赖的基础kprobe以及促使开发该工具的先驱DTr ...
- Linux下性能测量和调试诊断工具Systemtap
一.简介 SystemTap是一个诊断Linux系统性能或功能问题的开源软件.它使得对运行时的Linux系统进行诊断调式变得更容易.更简单.有了它,开发者或调试人员不再需要重编译.安装新内核.重启动等 ...
- Linux下配置一个VNC服务器
在Linux下配置一个VNC服务器,并设置2个用户,要求其中一个用户登录时不需要输入密码. 然后在客户端使用ssh+vncview的方式访问. 1确认vnc安装 2配置vncserver 3测试vnc ...
- 如何在Linux下拷贝一个目录呢
cp -af newadmin/movie/. uploadfile/mallvideo/ 如何在Linux下拷贝一个目录呢?这好像是再简单不过的问题了. 比如要把/home/usera拷贝到/m ...
- 如何在linux下制作一个windows的可启动u盘?
如何在linux下制作一个windows的可启动u盘? 情景是这样的,有一个windows10的iso,现在想通过U盘安装,要求即支持UEFI(启动引导器),又支持Legacy(启动引导器),因为有一 ...
- 【转载】在Linux下,一个文件也有三种时间,分别是:访问时间、修改时间、状态改动时间
在windows下,一个文件有:创建时间.修改时间.访问时间.而在Linux下,一个文件也有三种时间,分别是:访问时间.修改时间.状态改动时间. 两者有此不同,在Linux下没有创建时间的概念,也就是 ...
- 在Linux下制作一个磁盘文件,在u-boot 阶段对emmc 烧写整个Linux系统方法
在Linux 下制作一个磁盘文件, 可以给他分区,以及存储文件,然后dd 到SD卡便可启动系统. 在u-boot 下启动后可以读取该文件,直接在u-boot 阶段就可以做烧写操作,省略了进入系统后才进 ...
- linux下,一个运行中的程序,究竟占用了多少内存
linux下,一个运行中的程序,究竟占用了多少内存 1. 在linux下,查看一个运行中的程序, 占用了多少内存, 一般的命令有 (1). ps aux: 其中 VSZ(或VSS)列 表示,程序占用 ...
随机推荐
- Node.js+Koa开发微信公众号个人笔记(三)响应文本
响应输入文本和响应事件类似,首先对微信服务器发送来的数据的MsgType进行处理,如果是text,说明是文本,接下来可以对文本内容进行处理,比如用户输入了1,可以给用户回复一个文本或者图文或者视频等信 ...
- spring clound微服务架构实践(1)——搭建服务注册中心
一.创建一个空maven parent模板 1-1.新建project,选择maven 1-2.给此模板起名 1-3.此模板的保存位置,此处放入我的git项目spring-clound-learnin ...
- 输出一个对象,会默认执行toString()方法
今天在看编程思想时看到enum知识点时发现了这个小问题(可能我基础太差了) 如图 然后就一步一步的跟进源码发现了其中的奥秘,首先进入println()方法如下图 看图执行了valueOf()方法进行s ...
- linux-非root用户运行tomcat
# 前言:为什么要使用非root用户运行tomcat root用户启动tomcat有一个严重的问题,那就是tomcat具有root权限. 这意味着你的任何一个页面脚本(html/js)都具有root权 ...
- PyQt5 QSerialPort子线程操作
环境: python3.6 pyqt5 只是简单的一个思路,请忽略脆弱的异常防护: # -*- coding: utf-8 -*- import sys from PyQt5.QtWidgets im ...
- [HAOI 2007]理想的正方形
Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第 ...
- [SCOI 2012]滑雪与时间胶囊
Description a180285非常喜欢滑雪.他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有一编号i(1<=i<=N)和一高度Hi. ...
- 無名(noname)
[问题描述] 因为是蒯的题所以没想好名字,为什么要用繁体呢?去看<唐诗三百首>吧! 题意很简单,给你一个串,求他有多少个不同的子串,满足前缀为A,后缀为B. 需要注意的是,串中所有的字母都 ...
- 51 nod 1427 文明 (并查集 + 树的直径)
1427 文明 题目来源: CodeForces 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 安德鲁在玩一个叫“文明”的游戏.大妈正在帮助他. 这个游 ...
- ●BZOJ 3879 SvT
题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3879 题解: 后缀数组,单调栈,RMQ 其实类似 BZOJ 3238 [Ahoi2013]差 ...