微信号:gh_183a769668a5

介绍:记录在工作学习中的笔记,专注于分享移动开发领域高质量文章,努力做一个徘徊于牛A和牛C之间的人,

浅谈动态跟踪技术之DTrace

2018-03-31 21:46 DemonHunter

什么是动态追踪


举个简单例子,一个人正在健身房里跑步,我们用摄像机📹偷偷对他进行录像,事后我们就可以使用录像对这个人运动过程中的步频、速度、呼吸节奏等数据进行分析研究,以便为这个人提供更加科学的付费健身咨询服务(这个人并不知道被录像了)。仔细想想这不是一个很有价值的事吗?

对这个例子的整个过程分析,它大致有几个特点:

1、对健身者是无感知,不影响他当前正在进行的运动(低影响)

2、我们录像的时机可以随时开始,随时结束(低耦合) 

3、录像的对象可以是人,也可以是物体(可移植)

这就是动态追踪技术(Dynamic Tracing),在计算机领域是一种后现代的高级调试技术,可以帮助开发者在非常短的时间内,回答一些很难的关于软件系统方面的问题,从而更快速地排查和解决问题,也可以帮助产品决策者实时了解当前产品的线上运行情况。在火箭🚀般飞速发展的移动互联网时代,APP的用户规模,业务种类繁多,逻辑越来越复杂,代码编写也不再是单一语言。作为开发者、产品决策者正在面临无法掌控整个系统的巨大压力,动态追踪技术实际就能帮助我们实现这种愿景。

动态追踪的原理


动态追踪技术通常是基于操作系统内核来实现的。操作系统内核其实可以控制整个软件世界,因为它其实是处于"造物主"这样的一个地位。它拥有绝对的权限,同时它可以确保我们针对软件系统发出的各种"查询"不会影响到软件系统本身的正常运行。换句话说,我们的这种查询必须是足够安全的,是可以在生产环境上大量使用的。一般是通过探针这样的机制来发起查询。我们会在软件系统的某一个层次,或者某几个层次上面,安置一些探针(测试人员术语叫打桩,产品人员术语叫埋点),然后我们会自己定义这些探针所关联的处理程序,当关联程序不运行时,这些探针在系统中不会产生影响。而这些关联程序可以通过这些探针实时地向我们反馈信息,帮助解决许多重大问题。  

这有点像中医里面的针灸,就是说如果我们把软件系统看成是一个人,我们可以往他的一些穴位上扎一些“针”,那么这些针头上面通常会有我们自己定义的一些“传感器”,我们可以自由地采集所需要的那些穴位上的关键信息,然后把这些信息汇总起来,产生可靠的病因诊断和可行的治疗方案。这里的追踪通常涉及两个纬度。一个是时间纬度,因为这个软件还一直在运行,它便有一个在时间线上的连续的变化过程。另一个纬度则是空间纬度,因为可能它涉及到多个不同的进程,包含内核进程,而每个进程经常会有自己的内存空间、进程空间,那么在不同的层次之间,以及在同一层次的内存空间里面,我可以同时沿纵向和横向,获取很多在空间上的宝贵信息。这有点儿像蛛蛛在蛛网上搜索猎物。<摘录至https://openresty.org/posts/dynamic-tracing>   

DTrace初探


DTrace是动态追踪技术的鼻祖,它于 21 世纪初诞生于 Solaris 操作系统,是由原来的Sun Microsystems公司的工程师编写的,先后被移植到LinuxFreeBSDNetBSDMac OS X等操作系统上。iOS 系统也有,大名鼎鼎的Instrument工具就是基于DTrace实现的,而且更多的功能还在随着 iOS 系统进行版本迭代。

DTrace工具组件包括提供器探测器

1、提供器:由dtrace内核驱动命令及附加在上面的dtrace脚本组成(后缀名.d)。Mac OS X默认就安装了dtrace工具;脚本使用D语言编写,也叫d脚本,Mac OS X系统的 /usr/share/examples/DTTk/ 目录下有很多例子;  

2、探测器(即探针):由提供器启动,可标识所检测的模块和函数,其名称标准格式为 提供器:模块:函数:名称,每个探针还具有一个唯一的整数标识符。在苹果开源的xnu内核中可以看到苹果版的DTrace源码,打包为内核模块来收集跟踪数据,它提供接口通过 dtrace 内核驱动命令访问内核数据,在内核源码中很多带有 provider 关键字都属于标识某个模块数据的探针。其定义如下:

D语言


这里的 D语言 语法大部分跟 C语言 非常相似(这就带来了很好的可移植性),但总体架构是不同的。每个脚本由若干个探针语句组成。它们都符合如下的形式

probe descriptions

/ predicate /

{

    action statements

}

断言 (predicate) 和动作语句 (action statement) 部分都是可选的。  

probe descriptions 即探针描述定义了语句匹配什么类型的探针,结构就是之前提到的 提供器:模块:函数:名称 — provider:module:function:name,所有的部分都可以省略。其中 BEGIN 语句在所有探针开始之前运行,END 语句在脚本退出时候执行。

[语法很简单,设计很复杂,更详细的介绍参见。](https://docs.oracle.com/cd/E23824_01/html/E22973/glghi.html#scrolltoc),常用的如下:

当运行 dtrace 工具时,我们传入的脚本被编译成字节码。接着字节码被传入安插了探针的代码中(通常是kernel)。在 kernel 中有一个解释器来运行这些字节码。当将静态探针加入可执行程序 (一个 app 或 framework),它们被作为S_DTRACE_DOF(Dtrace Object Format)部分被加入,并且在程序运行时被加载进kernel。这样DTrace就知道当前的静态探针。

DTrace示例


使用 dtrace -l 可以查看 Mac OS X 系统上的所有探针,dtrace -l -m <module_name> 可以查看指定模块的探针。

注意 

1、如果出现错误:dtrace: failed to initialize dtrace: DTrace requires additional privileges

可以提升 dtrace 工具的权限:sudo dtrace -l

2、如果出现错误:dtrace: system integrity protection is on, some features will not be available

可以从安全模式关闭  csrutil disable

举个例子,假设需求是要跟踪系统 malloc 方法的所有分配内存大小,可以设计探针的定义文件 DTraceDemo.probe:

provider DTraceDemo {

   probe malloc_log(void *ptr, size_t size);

};

然后,执行下面的命令生成探针的头文件,后面带入测试工程中编译

/* 

 * 更多dtrace用法,参见sudo dtrace --help 

 *(其实没有help参数,习惯而已)

 */

sudo dtrace -h -o DTraceDemo.h -s DTraceDemo.probe

测试代码如下:

最后,创建自己的脚本 DTraceDemo.d,文件名必须以 .d 后缀结尾,这是 D 脚本的约定结尾。[更多d脚本例子参见。](https://github.com/opendtrace/toolkit.git)使用 sudo dtrace -s DTraceDemo.d 命令开始 dtrace 测试,接着启动测试功能得到输出如下:结束语


在许多不同的情况下,需要跟踪应用程序。对于开发人员来说,可以通过跟踪应用程序来诊断问题,这可能比使用调试器更方便。DTrace 等工具的跟踪能力更强,可以获得非常有针对性的丰富的应用程序信息。在 iOS 开发中经常使用的调试工具instruments,其核心数据采集原理即 DTrace

 
DemonHunter 更多文章 iOS 10 UserNotifications 实践 WKWebView 不支持 NSURLProtocol 吗 关于 iOS 图片加载 聊聊JSPatch的动态性原理 我的2016年终总结
猜您喜欢 更快速将你的页面展示给用户[前端优化篇] 关于软件质量的YY 干货|基于iso或安装源制作docker基础镜像制作 Android开发心得整理 房价的逻辑终于有人说透了,万科副总裁雄文剖析中国房价