# kldload dtraceall
第 27 章. DTrace
目录
27.1. 概要
DTrace,也称为动态跟踪,由 Sun™ 开发,作为一种用于在生产和预生产系统中查找性能瓶颈的工具。除了诊断性能问题外,DTrace 还可用于帮助调查和调试 FreeBSD 内核和用户空间程序中的意外行为。
DTrace 是一款卓越的性能分析工具,拥有强大的功能,可以用于诊断系统问题。它还可以运行预先编写的脚本以利用其功能。用户可以使用 DTrace D 语言编写自己的实用程序,从而根据特定需求自定义其性能分析。
FreeBSD 实现完全支持内核 DTrace,并对用户空间 DTrace 提供实验性支持。用户空间 DTrace 允许用户使用 pid
提供程序对用户空间程序执行函数边界跟踪,并向用户空间程序插入静态探针以供后续跟踪。一些端口,例如 databases/postgresql12-server 和 lang/php74,都提供了一个 DTrace 选项来启用静态探针。
DTrace 的官方指南由 Illumos 项目维护,网址为 DTrace 指南。
阅读完本章后,您将了解
什么是 DTrace 及其提供的功能。
Solaris™ DTrace 实现与 FreeBSD 提供的实现之间的区别。
如何在 FreeBSD 上启用和使用 DTrace。
阅读本章前,您应该
了解 UNIX® 和 FreeBSD 基础知识(FreeBSD 基础知识)。
对安全性及其与 FreeBSD 的关系有所了解(安全性)。
27.2. 实现差异
虽然 FreeBSD 中的 DTrace 与 Solaris™ 中的 DTrace 类似,但仍然存在一些差异。主要区别在于,在 FreeBSD 中,DTrace 实现为一组内核模块,并且在加载这些模块之前无法使用 DTrace。要加载所有必要的模块
从 FreeBSD 10.0-RELEASE 开始,当运行 dtrace
时,模块会自动加载。
FreeBSD 使用 DDB_CTF
内核选项来支持从内核模块和内核本身加载 CTF
数据。CTF
是 Solaris™ 紧凑型 C 类型格式,它封装了类似于 DWARF
和古老的 stabs 的简化调试信息。CTF
数据由 ctfconvert
和 ctfmerge
构建工具添加到二进制文件中。ctfconvert
实用程序解析编译器创建的 DWARF
ELF
调试部分,而 ctfmerge
将来自对象的 CTFELF
部分合并到可执行文件或共享库中。
FreeBSD 与 Solaris™ 的提供程序存在一些差异。最值得注意的是 dtmalloc
提供程序,它允许在 FreeBSD 内核中按类型跟踪 malloc()
。Solaris™ 中的一些提供程序,例如 cpc
和 mib
,在 FreeBSD 中不存在。这些可能会出现在 FreeBSD 的未来版本中。此外,在两个操作系统中都可用的某些提供程序不兼容,因为它们的探针具有不同的参数类型。因此,在 Solaris™ 上编写的 D
脚本可能在 FreeBSD 上无法修改使用,反之亦然。
由于安全差异,只有 root
才能在 FreeBSD 上使用 DTrace。Solaris™ 有几个低级安全检查,FreeBSD 中尚不存在。因此,/dev/dtrace/dtrace 严格限制为 root
使用。
DTrace 属于通用开发和分发许可证 (CDDL
) 许可。要在 FreeBSD 上查看此许可证,请参阅 /usr/src/cddl/contrib/opensolaris/OPENSOLARIS.LICENSE 或在线查看 http://opensource.org/licenses/CDDL-1.0。虽然具有 DTrace 支持的 FreeBSD 内核是 BSD
许可的,但当模块以二进制形式分发或加载二进制文件时,会使用 CDDL
。
27.3. 启用 DTrace 支持
在 FreeBSD 9.2 和 10.0 中,DTrace 支持内置于 GENERIC 内核中。FreeBSD 早期版本的用户或希望静态编译 DTrace 支持的用户应该将以下行添加到自定义内核配置文件中,并使用 配置 FreeBSD 内核 中的说明重新编译内核
options KDTRACE_HOOKS options DDB_CTF makeoptions DEBUG=-g makeoptions WITH_CTF=1
AMD64 架构的用户还应该添加此行
options KDTRACE_FRAME
此选项提供对 FBT
的支持。虽然 DTrace 在没有此选项的情况下也能工作,但对函数边界跟踪的支持将受到限制。
一旦 FreeBSD 系统重新启动到新内核中,或使用 kldload dtraceall
加载了 DTrace 内核模块,系统将需要 Korn shell 的支持,因为 DTrace 工具包中有一些用 ksh
编写的实用程序。确保已安装 shells/ksh93 软件包或端口。也可以在 shells/pdksh 或 shells/mksh 下运行这些工具。
最后,安装当前的 DTrace 工具包,这是一个用于收集系统信息的现成脚本集合。有一些脚本可以检查打开的文件、内存、CPU
使用情况等等。FreeBSD 10 将其中一些脚本安装到 /usr/share/dtrace 中。在其他 FreeBSD 版本上,或要安装完整的 DTrace 工具包,请使用 sysutils/dtrace-toolkit 软件包或端口。
/usr/share/dtrace 中的脚本已专门移植到 FreeBSD。DTrace 工具包中并非所有脚本都可以在 FreeBSD 上按原样工作,有些脚本可能需要一些工作才能在 FreeBSD 上工作。 |
DTrace 工具包包含许多用 DTrace 特殊语言编写的脚本。这种语言称为 D 语言,它与 C++ 非常相似。本文档不包含对该语言的深入讨论。在 Illumos 动态跟踪指南 中对它进行了广泛的介绍。
27.4. 在内核外模块中启用 DTrace
要向内核外模块添加 DTrace 支持(这对于开发和调试非常有用),请在模块的 Makefile 中包含以下行
CFLAGS+= -DKDTRACE_HOOKS
此标志在编译期间启用 DTrace 挂钩,从而允许对模块进行高级调试和监视。请确保在此修改后重新编译模块以激活 DTrace 功能。
27.5. 使用 DTrace
DTrace 脚本由一个或多个探针(或检测点)列表组成,其中每个探针都与一个操作相关联。每当满足探针的条件时,就会执行关联的操作。例如,当打开文件、启动进程或执行代码行时,可能会发生操作。该操作可能是记录一些信息或修改上下文变量。上下文变量的读取和写入允许探针共享信息并协作分析不同事件的相关性。
要查看所有探针,管理员可以执行以下命令
# dtrace -l | more
每个探针都有一个 ID
、一个 PROVIDER
(dtrace 或 fbt)、一个 MODULE
和一个 FUNCTION NAME
。有关此命令的更多信息,请参阅 dtrace(1)。
本节中的示例概述了如何使用 DTrace 工具包中两个完全支持的脚本:hotkernel 和 procsystime 脚本。
hotkernel 脚本旨在识别哪个函数使用了最多的内核时间。它将产生类似于以下内容的输出
# cd /usr/local/share/dtrace-toolkit
# ./hotkernel
Sampling... Hit Ctrl-C to end.
按照说明,使用 Ctrl+C 键组合停止进程。终止后,脚本将显示内核函数列表和计时信息,并按时间升序对输出进行排序
kernel`_thread_lock_flags 2 0.0%
0xc1097063 2 0.0%
kernel`sched_userret 2 0.0%
kernel`kern_select 2 0.0%
kernel`generic_copyin 3 0.0%
kernel`_mtx_assert 3 0.0%
kernel`vm_fault 3 0.0%
kernel`sopoll_generic 3 0.0%
kernel`fixup_filename 4 0.0%
kernel`_isitmyx 4 0.0%
kernel`find_instance 4 0.0%
kernel`_mtx_unlock_flags 5 0.0%
kernel`syscall 5 0.0%
kernel`DELAY 5 0.0%
0xc108a253 6 0.0%
kernel`witness_lock 7 0.0%
kernel`read_aux_data_no_wait 7 0.0%
kernel`Xint0x80_syscall 7 0.0%
kernel`witness_checkorder 7 0.0%
kernel`sse2_pagezero 8 0.0%
kernel`strncmp 9 0.0%
kernel`spinlock_exit 10 0.0%
kernel`_mtx_lock_flags 11 0.0%
kernel`witness_unlock 15 0.0%
kernel`sched_idletd 137 0.3%
0xc10981a5 42139 99.3%
此脚本也适用于内核模块。要使用此功能,请使用 -m
运行脚本
# ./hotkernel -m
Sampling... Hit Ctrl-C to end.
^C
MODULE COUNT PCNT
0xc107882e 1 0.0%
0xc10e6aa4 1 0.0%
0xc1076983 1 0.0%
0xc109708a 1 0.0%
0xc1075a5d 1 0.0%
0xc1077325 1 0.0%
0xc108a245 1 0.0%
0xc107730d 1 0.0%
0xc1097063 2 0.0%
0xc108a253 73 0.0%
kernel 874 0.4%
0xc10981a5 213781 99.6%
procsystime 脚本捕获并打印给定进程 ID
(PID
)或进程名称的系统调用时间使用情况。在以下示例中,生成了一个新的 /bin/csh 实例。然后,执行 procsystime 并保持等待状态,同时在 csh
的另一个实例中键入了几个命令。以下是此测试的结果
# ./procsystime -n csh
Tracing... Hit Ctrl-C to end...
^C
Elapsed Times for processes csh,
SYSCALL TIME (ns)
getpid 6131
sigreturn 8121
close 19127
fcntl 19959
dup 26955
setpgid 28070
stat 31899
setitimer 40938
wait4 62717
sigaction 67372
sigprocmask 119091
gettimeofday 183710
write 263242
execve 492547
ioctl 770073
vfork 3258923
sigsuspend 6985124
read 3988049784
如所示,read()
系统调用使用了最多的纳秒时间,而 getpid()
系统调用使用了最少的时间。
上次修改时间:2024 年 5 月 1 日,由 Danilo G. Baio 修改