Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 2 部分: DTrace
DTrace的原理
本系列文章详细地介绍了一个 Linux 下的全新的调式、诊断和性能测量工具 Systemtap 和它所依赖的基础 kprobe 以及促使开发该工具的先驱 DTrace 并给出实际使用例子使读者更进一步了解和认识这些工具。 本文是该系列文章之二,它详细地讲解了 DTrace 的原理。本系列文章之一讲解了 kprobe 的原理、编程接口、局限性和使用注意事项并给出实际使用示例帮助读者理解和认识 kprobe。本系列文章之三讲解了 Systemtap 的原理,以及 Systemtap 与 DTrace 比较,并通过一个例子向读者展示 Systemtap 的工作机理。
一、DTrace 简介
DTrace是一个强大的动态跟踪框架,它允许管理员、开发者和服务团队精确地回答关于操作系统和用户程序的任何问题。用户可以使用它管理成千上万个探测点,为每一个探测点指定执行条件(Predicates)和执行的动作(Actions),动态管理跟踪缓存和探测点开销。用户通过它能够对正在运行的系统跟踪来查看问题,也可以根据系统崩溃时产生的dump数据来查看问题。开发人员则可以实现新的提供者(Provider)和消费者(Consumer)以及配置管理探测点的工具。
DTrace对探测点上下文没有任何限制,也就说可以对任何函数进行探测,这是因为DTrace框架是完全非阻塞的,它基本上没有显式或隐式地调用内核其他功能。
Dtrace主要包含以下组件:
消费者(Consumer)
消费者是一个用户态应用,如dtrace,它能够通过Dtrace框架提供的接口库来访问DTrace内核组件
提供者(Provider)
提供者实现作内核模块,每一个模块建立某一种类的探测点,消费者能够使能提供者实现的任何探测点,并且可以把任何动作(action)绑定到这些探测点。提供者也能根据用户的跟踪请求创建新的探测点。
DTrace已经实现了16个提供者(当然用户可以实现自己的提供者),包括dtrace、lockstat、profile、fbt(Function Boundary Tracing)、syscall、sdt(Statcially Defined Tracing)、sysinfo、vminfo、proc、sched、io、mib、fpuinfo、pid、plockstat和fasttrap。
探测点(Probes)
探测点是由提供者创建的用于标识要探测的模块和函数。每一个探测点有一个名字。每一个探测点可以用四元组provider:module:function:name来标识,它也有独一无二的整数标识符。
预测(Predicates)
预测是一个用/括起来的表达式,类似于条件,它在探测点命中时计算以决定关联的动作是否被执行。预测是主要的条件结构,在D脚本中的复杂的控制流都是用它来实现的。对于任何探测点,该部分可以被完全省略,这时,关联到探测点的动作(action)将在任何一次命中后都被执行。预测必须是一个可计算的表达式。在D语言中,0值解释为假,1解释为真。
动作(Actions)
动作是用D语言编写的一些语句,它被Dtrace虚拟机在内核中执行。关联到探测点的动作会在该探测点命中时执行。一般地,动作用来记录指定的系统状态信息,但是它也能改变系统状态,这种动作称为破坏性动作(destructive action),缺省情况下不允许这种动作。
D脚本语言
D语言类似于awk脚本,用户使用它来编写动作和预测。
DTrace可以被用于性能监视、用户进程跟踪、匿名跟踪和推测跟踪(匿名跟踪没有消费者,这只能被超级用户执行,而且至多只能有一个匿名跟踪;推测跟踪则是指当探测点被命中后,动作是根据条件来执行的,predicates被用于实现推测跟踪),并且在没有使能跟踪的情况下没有任何开销,对系统性能没有任何影响。
二、DTrace原理
DTrace的核心组件全部在内核中实现,包括探测点处理、缓存以及instrumentation,用户态进程作为DTrace消费者(consumer)通过利用DTrace库能够和内核中的DTrace组件进行通信,DTrace提供的应用工具(dtrace就是一个典型的消费者,只是它使得用户可以非常方便地使用DTrace提供的任何功能)。DTrace框架不执行任何instrumentation,它只是负责指派instrumentation给对应的提供者(provider)。当DTrace核心组件指令提供者执行instrumentation时,提供者自己确定要instrument的点,然后回调DTrace框架提供的接口来创建探测点。为了创建一个探测点,提供者需要指定模块名、函数名以及探测点名。
每一个探测点用一个独一无二的四元组表示(简介部分已经讲到),四元组包括提供者、模块、函数名和探测点名,创建的探测点并不会被立即执行,它还需要消费者使能(探测点也可以被消费者失效),只有使能的探测点才会被执行。DTrace框架提供的探测点创建接口函数在执行成功时会给提供者返回一个探测点标识符。这些创建的探测点会通知给消费者,消费者能使能它感兴趣的探测点,当使能探测点时,DTrace将创建一个使能控制块(ECB -- Enabling Control Block)并绑定到该探测点,如果该探测点原来是失效的(即没有其它ECB绑定到该探测点),DTrace还将调用该探测点的提供者来真正使能该探测点(当然,如果该探测点已经是使能的,即它的ECB链不为空,这个操作是不必要的)。当CPU执行到一个使能的探测点(即运行到提供该探测点的提供者)时,对应的提供者会把控制传递到DTrace框架的入口并传递探测点的标识符作为第一个参数,DTrace框架得到控制后会失效当前CPU上的中断,然后执行该探测点ECB链上的每一个ECB指定的活动(一个探测点可以绑定多个动作),然后使能中断并把控制返回到该提供者。提供者不需要考虑如何多路复用处理一个探测点的多个消费者,ECB能很好地处理它。
每一个ECB可以有预测或条件(predicates),如果ECB有预测或条件,那么动作只有在该条件满足时才被执行。每一个ECB可以有多个动作,它们都会在条件满足时执行。如果动作要求保存一些数据,数据将被保存到对应于相应的消费者的缓存。动作不可以保存数据到内核内存,不可以修改寄存器,也不可以对系统状态做任何变化(破坏性动作除外,那要求用户必须是特权用户)。
DTrace为每一个DTrace消费者在每一个CPU上分配一些内核缓存,消费者状态指向该缓存,消费者的所有ECB都有一个指向消费者状态的指针。当一个ECB的动作要求保存数据时,数据就被保存到这些缓存中,一个ECB保存的数据量是一个常数,不同的ECB该常数可以不同。在处理ECB之前,会核对那些缓存看是否有足够的空间保存数据,如果没有足够的空间,对应于该缓存的一个丢失计数器会加1,该ECB上的所有动作将被跳过。消费者需要定期地读取缓存中的数据,否则会导致数据丢失。缓存实现完全是免锁的,即消费者读的同时,ECB的动作仍能在需要时立刻保存数据,不必锁等待。它是这样来实现的:每一个CPU上有两个缓存,一个是活动的(active),一个是非活动的(inactive),当消费者想读取指定CPU的缓存时,两个缓存被交换,即活动的变成非活动的,非活动的变成活动的,这个交换操作可以在极其短的时间内完成,并使用中断失效来保护(ECB的动作保存数据或其它消费者的读取操作需要访问这些缓存,因而必须被同步)。在交换之后,消费者从不活动的缓存读取数据,而ECB能够向活动的缓存写数据。在每一个CPU上的缓存中,每一次的数据保存都会把探测点标识符(EPID -- Enabled Probe Identifier,EPID与ECB一一对应,因此可用于查询对应的ECB已经保存的数据的长度)放在首部。
动作(actions)和预测/条件(predicates)用D语言编写,它们会转换成DIF(D Intermediate Forat,DTrace实现的一种虚拟机指令),DIF简化了仿真和代码生成。
它DIF指令是解释执行的,安全检查可以在解释时进行,因此安全性可以得到保证。当DIF指令装入内核时,操作码,保留位,寄存器,字符串引用,变量引用以及一些基本的安全检查都要被严格检查。一些运行时错误(如除0)并不能从静态分析中发现,因此它们被DIF虚拟机处理。当遇到这样的指令,DIF虚拟机将不执行它们,并导致当前ECB的处理终止,相应的消费者得到一个运行时错误。从设备的I/O内存区装入数据也是不允许的,DIF可以根据要装入的数据地址很容易地做判断。对于无效的数据装入地址,DIF虚拟机判断它是否有效很复杂,因此借用硬件已有的错误处理机制来实现,DTrace修改页失效处理函数来检查这种情况并做特殊处理,当遇到这样的情况,将导致页失效,页失效处理函数会检查导致页失效的指令是否来自DIF虚拟机,如果是,页失效处理函数将设置一个标志位来表示发生了页失效,然后跳到导致页失效指令的下一条指令执行,也即让DIF虚拟机继续执行其余的DIF虚拟机指令,因此DIF虚拟机能够在执行下一条虚拟机指令前能够有机会检查那个标志位。每次DIF虚拟机在执行一条虚拟机指令前都会检查那个标志位,如果被设置了,当前的ECB处理将被终止,相应的消费者将得到一个运行时错误。这种实现增加了页失效处理函数的开销,但是相对于整个页失效处理函数的开销,它是非常小的,因此对系统性能的影响可以忽略不记。
D语言类似于awk脚本语言,它支持所有ANSI C支持的操作符,变量类型,也支持typedef并能够定义struct、union和enum。也允许访问内核定义的数据类型和全局变量。D语言支持C语法的变量声明,变量可以声明,也可以不声明,如果不声明,它的类型在赋值时确定,实际类型为所赋值的类型。
D语言也可以调用DTrace提供的函数和变量。D语言支持全局变量、语句内变量、线程本地变量和关联数组。为了区分语句内变量和线程本地变量,在引用变量时需要有前缀,this->表示语句内变量,self->表示线程本地变量。语句内变量类似于C语言的静态局部变量,线程本地变量就是每一个访问该变量的线程都有自己的变量存储,不同的线程互不影响,C语言没有类似的变量与之对应。D语言也支持一种特殊的数据类型,聚合(Aggregations)。为了实现聚合,需要实现相应的聚合函数。用一个实例可以很好地说明何为聚合:
syscall::write:entry
{
@counts[execname] = count();
}
其中@表示该变量是聚合,counts就是聚合变量的名称,用户可以随意取名,execname是一个DTrace变量,表示当前进程名,用户可以根据需要指定不同的值,它是这个聚合的索引,类似于数组的索引,只是它可以为整数,也可以是字符串。count()是聚合函数,它返回@counts[execname] + 1,也就说语句@counts[execname] = count()实现了@counts[execname] 加1。
聚合不同于关联数组,赋值操作必须通过聚合函数来做,索引也不同,关联数组的索引是逗号分割的一个或多个表达式列表。 用户态工具dtrace能把D语言转换成DIF指令。一个D程序的结构如下:
probe-descriptions
/predicate/
{
action-statements
}
probe-descriptions用于指定探测点,它是一个四元组,与前面讲到的探测点四元组的组成一样,包括提供者、模块、函数名、探测点名,只是这四个元素的每一个都可以不提供(那表示匹配任何值),predicate就是预测或条件,它可以没有,action-statements就是动作,它可以是一条或多条D语句。
DTrace能够跟踪用户态应用(Systemtap目前不能),这是由pid提供者实现的。
DTrace还实现了一种特殊的跟踪推测跟踪(Speculative Tracing)。有时消费者在执行探测点时并不知道是否该探测是它所需要的,只有在探测执行后一段时间才能知道,因此预测没法覆盖这种情况。推测跟踪的原理是先执行探测并暂时保存数据在一个临时缓存,如果它发现那些数据是感兴趣的,就提交到真正的缓存,否则就丢弃那些数据。
三、实例解析
下面是一个实际的使用示例:
# dtrace -n syscall:::entry'/pid == 31337/{ @syscalls[probefunc] = count(); }'
dtrace: description 'syscall:::entry' matched 215 probes
^C
open 1
lwp_park 2
times 4
fcntl 5
close 6
sigaction 6
read 10
ioctl 14
sigprocmask 106
write 1092
选项-n用于使能指定的探测点,syscall:::entry就是前面提到的四元组,它用于描述哪些探测点将被使能,如果某个元素为空,表示将匹配该元素对应的任何组件。该例子中的四元组指定的探测点为系统调用入口。/括起来的部分就是预测(Predicate),它表示只有对当前进程PID为31337的进程的系统调用执行后面指定的动作,大括号包含的部分为真正的动作,@表示它为Dtrace会聚,会聚是一个变量类型,它被用于采集到的数据的综合处理,一般在性能监视中使用最为普遍,syscalls为会聚的变量名,probefunc为会聚的键,它是Dtrace内嵌变量,表示被探测的函数的名称,你可以把syscalls理解为关联数组,当然可以随意取名,count为Dtrace为会聚实现的内部函数,它返回它被调用的次数,注意,不同的探测点count互不相干。
小结
本文讲解了DTrace以及它的实现原理,并通过一个实际的例子给读者一个直观的认识,如果读者对它有兴趣可以阅读参考资料中的DTrace指南来了解更多详细的信息。本文是系列文章“Linux下的一个全新的性能测量和调式诊断工具 -- Systemtap”之二,有兴趣的读者可以阅读该系列文章之一和三。
Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 2 部分: DTrace的更多相关文章
- Linux 下的一个全新的性能测量和调式诊断工具 Systemtap, 第 3 部分: Systemtap
Systemtap的原理,Systemtap与DTrace比较,以及安装要求和安装步骤本系列文章详细地介绍了一个Linux下的全新的调式.诊断和性能测量工具Systemtap和它所依赖的基础kprob ...
- 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)列 表示,程序占用 ...
随机推荐
- 项目版本与分支管理之阿里AoneFlow模式分析
前言 在我前期的项目管理的经验中,一个项目需要维护多个产品及多个版本,这给版本与分支的管理增加了难度.前期没有重视,使得分支太多太乱,版本也没记录好,引发了很多的问题.在多种分支与版本的管理模式下,最 ...
- Java 线程池原理分析
1.简介 线程池可以简单看做是一组线程的集合,通过使用线程池,我们可以方便的复用线程,避免了频繁创建和销毁线程所带来的开销.在应用上,线程池可应用在后端相关服务中.比如 Web 服务器,数据库服务器等 ...
- C#在使用Assembly加载程序集时失败
错误现象: 进行插件读取时出现错误:"尝试从一个网络位置加载程序集,在早期版本的 .NET Framework 中,这会导致对该程序集进行沙盒处理.此发行版的 .NET Framework ...
- jenkins构建个人github上的项目
最近刚进一家新公司,公司采用的是自动化集成测试工具jenkins进行,构建,部署项目 因为以前,没接触过这类工具,所以打算在自己本机安装一个jenkins进行学习 具体安装步骤,很简单,不做讲解 1. ...
- macOS下python3通过scrapy框架重新生成不得姐网站视频采集过程日志
1.搭建虚拟python3环境(Virtualenvwrapper) 参考http://www.cnblogs.com/it-tsz/p/pyhton.html 2.安装scrapy 前提先安装好pi ...
- 用DotTrace 来分析.NET-Core程序
1. 前言 看园子里面讲dotTrace 的文章不多,最近也有这方面的需要,于是去搜索了一下,.NET 性能分析方面的工具.目的呢,主要是想发现我的代码中,哪些代码占用了最多时间,来进行优化.主要 ...
- [SPOJ 10628]Count on a tree
Description 题库链接 求不带修改的树上路径第 \(K\) 小. \(N\) 个节点 \(M\) 组询问. \(1\leq N,M\leq 100000\) Solution 主席树维护树上 ...
- [HZOI 2015]疯狂的机器人
[题目描述] 现在在二维平面内原点上有一只机器人 他每次操作可以选择向右走,向左走,向下走,向上走和不走(每次如果走只能走一格) 但是由于本蒟蒻施展的大魔法,机器人不能走到横坐标是负数或者纵坐标是负数 ...
- [HNOI2005]狡猾的商人
题目描述 输入输出格式 输入格式: 从文件input.txt中读入数据,文件第一行为一个正整数w,其中w < 100,表示有w组数据,即w个账本,需要你判断.每组数据的第一行为两个正整数n和m, ...
- ●洛谷P1291 [SHOI2002]百事世界杯之旅
题链: https://www.luogu.org/recordnew/show/5861351题解: dp,期望 定义dp[i]表示还剩下i个盖子没收集时,期望还需要多少次才能手机完. 初始值:dp ...