IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  AIX and UNIX  >

跟踪 UNIX 应用程序的解决方案

developerWorks
前一页第 4 页,共 10 页后一页

文档选项

样例代码


对本教程的评价

帮助我们改进这些内容


用 DTrace 进行动态跟踪

Solaris、FreeBSD 和 Mac OS X 内置的 Dynamic Tracing (DTrace) 功能提供一个更加动态的跟踪环境。与 truss 和相似的工具不同,可以使用 DTrace 检查正在运行的程序的内部情况,而不只是查看系统调用。另外,可以使用 DTrace 编写应用程序跟踪脚本,从而定制在跟踪过程中希望提取的信息。

DTrace 概述

DTrace 结合了您在 truss 和 strace 中已经看到的许多跟踪原理,但是在跟踪应用程序所用的方法和机制方面更加灵活。

truss 和 strace 只列出内核空间中的函数,而 DTrace 可以显示应用程序的函数名、它所依赖的任何库以及调用的内核函数。这把跟踪的方便性提高到与调试器差不多的水平。但是,与调试器不同,不能修改值,也不能暂停或以其他方式改变应用程序的执行过程。只能跟踪执行过程,而不能控制它。

与大多数跟踪工具和调试器相比,DTrace 的另一个独特之处是可以编写跟踪脚本,跟踪脚本定义要跟踪应用程序中的哪些方面,以及在执行应用程序时应该报告哪些信息。例如,可以指定 DTrace 只报告关于某个函数的信息,让它只输出函数调用中的一个参数。

除了输出特定信息之外,DTrace 还为许多实用程序值和函数提供内置支持。例如,在脚本中可以记录调用函数时的时间戳,然后把这个时间戳值与函数完成时的时间戳进行比较。通过比较这两个值,可以得到特定函数或操作的执行时间,可以使用这种跟踪信息提供执行和性能统计数据。

探测和提供者

DTrace 会在应用程序中添加检测机制,从而识别不同的执行点。这些执行点称为探测(probe),包括在内核、库和程序中定义的探测。内核、库和用户程序中的所有函数都可以指定为探测。另外,可以使用静态定义的探测识别感兴趣的特殊执行点。例如,在内核中可以使用探测识别向磁盘写数据的执行点。开发人员可以在程序中添加特定的探测,从而允许用户启用跟踪。这些探测称为 User-land Statically Defined Tracing(USDT)。

指定探测所用的结构是 provider:module:function:name,其中的 provider 是提供者的名称(例如,程序名、内核或操作系统的特定部分),module 是内核模块或库,function 常常是模块或程序中的函数名,name 标识探测。提供者还有一个特殊的标识符,PID;这用来标识正在运行的任何程序,可以用它跟踪正在运行的程序中的任何函数。

名称常常是系统或程序中已经定义的探测的名称。DTrace 还支持函数边界跟踪 (FBT),这可以跟踪进入和退出内核、库或应用程序中任何函数的执行点。当调用函数时,触发进入探测;当函数返回或完成执行时,触发返回探测。

指定探测的结构中的任何部分都可以忽略(在这种情况下,与所有项目匹配),也可以使用通配符。例如,可以使用 provider::: 指定某个提供者中的所有探测。还可以只指定一个 PID 提供者中的进入探测:pid$target:::entry

上面指定的探测与 truss 的操作相似,但是涉及的函数包括程序、操作系统和程序依赖的任何库。这提供比 truss 更广的范围。

在使用 PID 提供者时,可以使用模块标识程序。如果不指定模块,就会跟踪程序调用的每个函数。通过指定程序名,可以把输出限制在程序内定义的函数。例如,可以使用 pid$target:ageindays:: 跟踪 ageindays 应用程序中的函数的执行情况。

可以使用 dtrace 跟踪任何程序;不需要以特殊方式编译程序。因此,与 truss 不同,即使您不掌握程序的源代码,也可以深入了解应用程序。

可以使用 dtrace 工具获得探测列表;-l 命令行选项列出系统中定义的所有探测:$ dtrace -l

这个列表可能非常长。





回页首


单行跟踪

正如前面提到的,可以使用 DTrace 跟踪任何应用程序和其中的任何函数。从命令行使用 dtrace 有三种方式:指定一个命令;指定一个进程 ID;指定一个命名的静态探测。

在命令行上指定要执行的命令(使用 -c),使用 -n 选项指定希望监视的探测(见清单 10)。


清单 10. 指定希望监视的探测

$ dtrace -n 'pid$target:ageindays::entry' -c './ageindays 24/1/1980 26/3/1980'
dtrace: description 'pid$target:ageindays::entry' matched 7 probes
You have been alive 62 days
You were born on 24/1/1980 which is a Thursday
dtrace: pid 15925 has exited
CPU     ID                    FUNCTION:NAME
  1  57147                     _start:entry 
  1  57148                      __fsr:entry 
  1  57153                       main:entry 
  1  57152                  check_day:entry 
  1  57152                  check_day:entry 
  1  57151                  calc_diff:entry 
  1  57150                  leap_year:entry 
...

现在,指定一个正在运行的程序的进程 ID 以及希望跟踪的探测。例如,清单 11 跟踪 inetd 守护进程对 syslog 系统的调用。


清单 11. 跟踪对 syslog 系统的调用

$ dtrace -n 'pid$target::syslog:entry { printf("%d %s", arg0, copyinstr(arg1)) }' 
   -p `pgrep -x inetd`

还可以指定静态探测的名称,这与正在运行的任何进程中的所有探测匹配。例如,清单 12 跟踪对任何 exec 函数的调用(例如,当用户在 shell 中运行命令时)。因为没有指定特定的进程,这个探测会跟踪系统上任何用户对此函数的任何调用(见清单 12)。


清单 12. 指定静态探测的名称

$ dtrace -n 'syscall::exec*:entry'
dtrace: description 'syscall::exec*:entry' matched 2 probes
CPU     ID                    FUNCTION:NAME
  0  56750                      exece:entry 
  0  56750                      exece:entry 
  0  56750                      exece:entry 

在上面这些示例中,只使用了基本输出,输出的信息只包括函数或探测名称以及触发探测的 CPU 和进程 ID。可以通过使用 DTrace 脚本编程语言产生更丰富、更有选择性的探测输出。





回页首


编写 DTrace 脚本

DTrace 脚本编程语言提供一种简单的编程机制,可以在提供者触发探测时执行特定的操作(称为动作)。这种语言不具备 PHP 或 Perl 等完整语言环境的灵活性,但是可以使用它在变量中记录信息、执行基本的计算和支持基本的决策。

下面的基本示例在执行特定的探测点时输出值。可以使用别名 arg0、arg1 等获取探测或函数的参数。这个示例监视给定的进程中以 open 开头的所有函数,显示每个函数打开的文件。


清单 13. 监视给定的进程中以 open 开头的所有函数

#!/bin/dtrace -s

#pragma D option quiet

pid$target::open*:entry
{
   printf("Opened: %s\n",copyinstr(arg0));
}

可以把这段文本保存在 open.t 文件中,然后在此文件上设置执行位:$ chmod +x open.t

这个文件现在是一个可执行的脚本。在使用它时,应该通过 -p 命令行选项指定进程 ID。例如,对一个 shell 运行它,就会获得 shell 在执行期间打开的文件的列表(见清单 14)。


清单 14. 使用 -p 选项

$ ./open.t -p 15930
Opened: /root/.bash_path
Opened: /root/.bash_vars
Opened: /root/.bashrc
Opened: /root/.bash_aliases
...

DTrace 脚本的一种典型用途是合并和汇总信息,提供不同操作的计数和时间差。DTrace 脚本中的探测在一个线程中依次执行,这意味着可以监视一系列探测的执行情况。许多探测是成对提供的,启始探测表示操作开始的位置,结束探测表示操作完成的位置。

通过记录触发启始探测和结束探测的时间,就可以判断出操作花费的时间。在 DTrace 脚本中,可以使用 self 变量保存启始时间。例如,清单 15 中的脚本使用 MySQL 数据库系统中的命名探测监视查询的执行时间。


清单 15. 使用 MySQL 中的命名探测监视查询的执行时间

#!/usr/sbin/dtrace -s

#pragma D option quiet

dtrace:::BEGIN
{
   printf("%-80s %6s\n", "Query", "Duration (ms)");
}

mysql*:::query-start
{
   self->query = copyinstr(arg5);
   self->querystart = timestamp;
}

mysql*:::query-done
{
   this->elapsed = (timestamp - self->querystart) /1000000;
   printf("%-80s %6d\n", self->query, this->elapsed);
}

这个跟踪显示典型 DTrace 脚本的许多元素。首先,BEGIN 块输出一些标题信息,这在输出表格式数据时很有用。

query-start 探测包含许多参数,第六个参数 (arg5) 包含完整的查询文本。

在运行 MySQL 的服务器上执行查询时,可以获得执行每个查询花费的时间的统计数据(见清单 16)。


清单 16. 获得执行每个查询花费的时间的统计数据

$ ./basic.d
Query                                                           Duration (ms)
show tables                                                     203
select * from t1 where i <5                                  131526

这些示例只涉及 DTrace 的基本功能。更多示例和信息见 参考资料





回页首



前一页第 4 页,共 10 页后一页
    关于 IBM 隐私条约 联系 IBM 使用条款