proc 提供器提供了与以下活动有关的探测器:进程创建和终止、LWP 创建和终止、新程序映像的执行以及信号的发送和处理。
表 25–1 中对 proc 探测器进行了说明。
表 25–1 proc 探测器
探测器 |
说明 |
---|---|
create |
使用 fork(2)、forkall(2)、fork1(2) 或 vfork(2) 创建进程时将触发的探测器。args[0] 指向对应于新的子进程的 psinfo_t。可以通过检查派生线程 lwpsinfo_t 的 pr_flag 成员中的 PR_VFORKP,将 vfork 与其他 fork 变体区分开来。可以通过检查父进程的 psinfo_t (curpsinfo) 和子进程的 psinfo_t (args[0]) 的 pr_nlwp 成员,将 fork1 与 forkall 区分开来。因为 create 探测器仅在成功创建了进程之后触发,且 LWP 创建为创建进程的一部分,所以对于任何在创建进程时(为新进程触发 create 探测器之前)创建的 LWP,都将触发 lwp-create。 |
exec |
进程使用 exec(2) 系统调用的以下变体装入新进程映像时将触发的探测器:exec(2)、execle(2)、execlp(2)、execv(2)、execve(2)、execvp(2)。exec 探测器在装入进程映像之前触发。因此进程变量(如 execname 和 curpsinfo)将包含装入映像前的进程状态。在触发 exec 探测器之后的某个时间,exec-failure 探测器或 exec-success 探测器随后将在同一线程中触发。args[0] 指向新进程映像的路径。 |
exec-failure |
exec(2) 变体失败时将触发的探测器。exec-failure 探测器仅在同一线程中触发了 exec 探测器之后触发。args[0] 中提供了 errno(3C) 值。 |
exec-success |
exec(2) 变体成功时将触发的探测器。与 exec-failure 探测器一样,exec-success 探测器仅在同一线程中触发了 exec 探测器之后触发。触发 exec-success 探测器时,进程变量(如 execname 和 curpsinfo)将包含装入新的进程映像之后的进程状态。 |
exit |
当前线程正在退出时将触发的探测器。退出的原因(使用某个 SIGCHLD siginfo.h(3HEAD) 代码表示)包含在 args[0] 中。 |
fault |
线程遇到计算机故障时将触发的探测器。故障代码(如 proc(4) 中所定义)包含在 args[0] 中。args[1] 指向对应于故障的 siginfo 结构。只有引起信号的那些故障可以触发 fault 探测器。 |
lwp-create |
创建 LWP 时将触发的探测器,通常作为 thr_create(3C) 的结果。args[0] 指向对应于新线程的 lwpsinfo_t。args[1] 指向包含该线程进程的 psinfo_t。 |
lwp-start |
在新创建的 LWP 的上下文中触发的探测器。lwp-start 探测器将在执行任何用户级指令之前触发。如果该 LWP 是进程中的第一个 LWP,则 start 探测器将在 lwp-start 探测器之前触发。 |
lwp-exit |
LWP 正在退出(由于信号或对 thr_exit(3C) 的显式调用)时将触发的探测器。 |
signal-discard |
信号被发送到单线程进程,且进程未阻塞该信号,但忽略该信号时将触发的探测器。在这些条件下,信号在生成时将被废弃。目标进程和线程的 lwpsinfo_t 和 psinfo_t 分别包含在 args[0] 和 args[1] 中。信号数字包含在 args[2] 中。 |
signal-send |
将信号发送到线程或进程时将触发的探测器。signal-send 探测器在发送进程和线程的上下文中触发。接收进程和线程的 lwpsinfo_t 和 psinfo_t 分别包含在 args[0] 和 args[1] 中。信号数字包含在 args[2] 中。接收进程和线程时,signal-send 始终后跟 signal-handle 或 signal-clear。 |
signal-handle |
探测器就在线程处理信号之前的瞬间触发。signal-handle 探测器在将要处理信号的线程的上下文中触发。信号数字包含在 args[0] 中。指向对应于信号的 siginfo_t 结构的指针包含在 args[1] 中。如果没有 siginfo_t 结构或者信号处理程序未设置 SA_SIGINFO 标志,args[1] 的值将为 NULL。进程中的信号处理程序的地址包含在 args[2] 中。 |
signal-clear |
因为目标线程正在等待 sigwait(2)、sigwaitinfo(3RT) 或 sigtimedwait(3RT) 中的信号而清除暂挂信号时,将触发的探测器。在这些条件下,将清除暂挂信号并将信号数字返回到调用方。信号数字包含在 args[0] 中。signal-clear 在先前的等待线程的上下文中触发。 |
start |
在新创建的进程的上下文中触发的探测器。start 探测器将在执行进程中任何用户级指令之前触发。 |
表 25–2 中列出了 proc 探测器的参数类型。表 25–1 中说明了这些参数。
表 25–2 proc 探测器参数
探测器 |
args[0] |
args[1] |
args[2] |
---|---|---|---|
create |
psinfo_t * |
— |
— |
exec |
char * |
— |
— |
exec-failure |
int |
— |
— |
exit |
int |
— |
— |
fault |
int |
siginfo_t * |
— |
lwp-create |
lwpsinfo_t * |
psinfo_t * |
— |
lwp-start |
— |
— |
— |
lwp-exit |
— |
— |
— |
signal-discard |
lwpsinfo_t * |
psinfo_t * |
int |
signal-discard |
lwpsinfo_t * |
psinfo_t * |
int |
signal-send |
lwpsinfo_t * |
psinfo_t * |
int |
signal-handle |
int |
siginfo_t * |
void (*)(void) |
signal-clear |
int |
— |
— |
start |
— |
— |
— |
多种 proc 探测器具有 lwpsinfo_t(proc(4) 中记录的一种结构)类型的参数。DTrace 使用者可以使用的 lwpsinfo_t 结构的定义如下所示:
typedef struct lwpsinfo { int pr_flag; /* flags; see below */ id_t pr_lwpid; /* LWP id */ uintptr_t pr_addr; /* internal address of thread */ uintptr_t pr_wchan; /* wait addr for sleeping thread */ char pr_stype; /* synchronization event type */ char pr_state; /* numeric thread state */ char pr_sname; /* printable character for pr_state */ char pr_nice; /* nice for cpu usage */ short pr_syscall; /* system call number (if in syscall) */ int pr_pri; /* priority, high value = high priority */ char pr_clname[PRCLSZ]; /* scheduling class name */ processorid_t pr_onpro; /* processor which last ran this thread */ processorid_t pr_bindpro; /* processor to which thread is bound */ psetid_t pr_bindpset; /* processor set to which thread is bound */ } lwpsinfo_t;
pr_flag 字段是存储用于说明进程的标志的位掩码。表 25–3 中说明了这些标志及其含义。
表 25–3 pr_flag 值
PR_ISSYS |
该进程为系统进程。 |
PR_VFORKP |
该进程是 vfork(2) 的子进程的父进程。 |
PR_FORK |
该进程具有从 fork 中继承的模式集。 |
PR_RLC |
该进程具有最后一次关闭时运行的模式集。 |
PR_KLC |
该进程具有最后一次关闭时中止的模式集。 |
PR_ASYNC |
该进程具有异步停止模式集。 |
PR_MSACCT |
该进程已启用微状态记帐。 |
PR_MSFORK |
进程微状态记帐继承于 fork。 |
PR_BPTADJ |
该进程具有断点调整模式集。 |
PR_PTRACE |
该进程具有 ptrace(3C) 兼容的模式集。 |
PR_STOPPED |
该线程是已停止的 LWP。 |
PR_ISTOP |
该线程是在出现关注的事件时停止的 LWP。 |
PR_DSTOP |
该线程是具有正在生效的停止指令的 LWP。 |
PR_STEP |
该线程是具有正在生效的单步指令的 LWP。 |
PR_ASLEEP |
该线程是系统调用的可中断休眠中的 LWP。 |
PR_DETACH |
该线程是拆离的 LWP。请参见 pthread_create(3C) 和 pthread_join(3C)。 |
PR_DAEMON |
该线程是守护进程 LWP。请参见 pthread_create(3C)。 |
PR_AGENT |
该线程是进程的代理 LWP。 |
PR_IDLE |
该线程是 CPU 的空闲线程。当 CPU 的运行队列为空时,空闲线程仅在 CPU 中运行。 |
pr_addr 字段是表示线程的专用、内核中的数据结构的地址。虽然该数据结构为专用,但 pr_addr 字段可用作在线程的生命周期中线程的唯一标记。
当线程在同步对象上休眠时,将设置 pr_wchan 字段。pr_wchan 字段的含义专用于内核实现,但该字段也可用作同步对象的唯一标记。
当线程在同步对象上休眠时,将设置 pr_stype 字段。表 25–4 中说明了 pr_stype 字段的可能值。
表 25–4 pr_stype 值
SOBJ_MUTEX |
内核互斥同步对象。用于串行化内核中共享数据区域的访问。有关内核互斥同步对象的详细信息,请参见第 18 章和 mutex_init(9F)。 |
SOBJ_RWLOCK |
内核读取器/写入器同步对象。用于同步内核中共享对象的访问,共享对象可以允许多个并发读取器或一个写入器。有关内核读取器/写入器同步对象的详细信息,请参见第 18 章和 rwlock(9F)。 |
SOBJ_CV |
条件变量同步对象。条件变量的设计是无限等待,直到某个条件变为 true。条件变量通常用于同步(出于访问共享数据区域之外的原因),它通常是当进程执行程序指令的无限等待时使用的机制。例如,在 poll(2)、pause(2)、wait(3C) 中阻塞,以及类似情况。 |
SOBJ_SEMA |
信号同步对象。一般用途的同步对象,与条件变量对象一样,不跟踪拥有权说明。由于在 Solaris 内核中实现优先级继承必须具有拥有权,所以信号对象中没有固有拥有权将使这些对象不能被广泛使用。有关详细信息,请参见 semaphore(9F)。 |
SOBJ_USER |
用户级同步对象。所有对用户级同步对象的阻塞都使用 SOBJ_USER 同步对象处理。用户级同步对象包括使用 mutex_init(3C)、sema_init(3C)、rwlock_init(3C)、cond_init(3C) 及其 POSIX 等效项创建的对象。 |
SOBJ_USER_PI |
实现优先级继承的用户级同步对象。一些跟踪拥有权的用户级同步对象还允许优先级继承。例如,使用 pthread_mutex_init(3C) 创建的互斥对象可以使用 pthread_mutexattr_setprotocol(3C) 设置为继承优先级。 |
SOBJ_SHUTTLE |
互动同步对象。互动对象用于实现门。有关更多信息,请参见 door_create(3DOOR)。 |
pr_state 字段设置为表 25–5 中的某个值。pr_sname 字段设置为同一个表中括号内说明的相应字符。
表 25–5 pr_state 值
SSLEEP (S) |
线程处于休眠状态。sched:::sleep 探测器就在线程的状态转换为 SSLEEP 之前的瞬间触发。 |
SRUN (R) |
该线程可运行,但当前未运行。sched:::enqueue 探测器将在线程的状态转换为 SRUN 之前的瞬间触发。 |
SZOMB (Z) |
该线程是僵 LWP。 |
SSTOP (T) |
由于显式 proc(4) 指令或一些其他停止机制,该线程已停止。 |
SIDL (I) |
该线程是进程创建期间的中间状态。 |
SONPROC (O) |
该线程正在 CPU 中运行。sched:::on-cpu 探测器将在线程的状态转换为 SONPROC 一段时间后,在 SONPROC 线程的上下文中触发。 |
多种 proc 探测器具有 psinfo_t(proc(4) 中记录的一种结构)类型的参数。DTrace 使用者可以使用的 psinfo_t 结构的定义如下所示:
typedef struct psinfo { int pr_nlwp; /* number of active lwps in the process */ pid_t pr_pid; /* unique process id */ pid_t pr_ppid; /* process id of parent */ pid_t pr_pgid; /* pid of process group leader */ pid_t pr_sid; /* session id */ uid_t pr_uid; /* real user id */ uid_t pr_euid; /* effective user id */ gid_t pr_gid; /* real group id */ gid_t pr_egid; /* effective group id */ uintptr_t pr_addr; /* address of process */ dev_t pr_ttydev; /* controlling tty device (or PRNODEV) */ timestruc_t pr_start; /* process start time, from the epoch */ char pr_fname[PRFNSZ]; /* name of execed file */ char pr_psargs[PRARGSZ]; /* initial characters of arg list */ int pr_argc; /* initial argument count */ uintptr_t pr_argv; /* address of initial argument vector */ uintptr_t pr_envp; /* address of initial environment vector */ char pr_dmodel; /* data model of the process */ taskid_t pr_taskid; /* task id */ projid_t pr_projid; /* project id */ poolid_t pr_poolid; /* pool id */ zoneid_t pr_zoneid; /* zone id */ } psinfo_t;
pr_dmodel 字段设置为 PR_MODEL_ILP32(表示 32 位进程)或 PR_MODEL_LP64(表示 64 位进程)。
您可以使用 exec 探测器轻松地确定正在执行哪些程序以及由哪个用户执行,如下例所示:
#pragma D option quiet proc:::exec { self->parent = execname; } proc:::exec-success /self->parent != NULL/ { @[self->parent, execname] = count(); self->parent = NULL; } proc:::exec-failure /self->parent != NULL/ { self->parent = NULL; } END { printf("%-20s %-20s %s\n", "WHO", "WHAT", "COUNT"); printa("%-20s %-20s %@d\n", @); }
在生成计算机上运行示例脚本一段时间后将产生与以下示例类似的输出:
# dtrace -s ./whoexec.d ^C WHO WHAT COUNT make.bin yacc 1 tcsh make 1 make.bin spec2map 1 sh grep 1 lint lint2 1 sh lint 1 sh ln 1 cc ld 1 make.bin cc 1 lint lint1 1 sh lex 1 make.bin mv 2 sh sh 3 sh make 3 sh sed 4 sh tr 4 make make.bin 4 sh install.bin 5 sh rm 6 cc ir2hf 33 cc ube 33 sh date 34 sh mcs 34 cc acomp 34 sh cc 34 sh basename 34 basename expr 34 make.bin sh 87 |
如果要知道程序从创建到终止所运行的时间,可以启用 start 和 exit 探测器,如下例所示:
proc:::start { self->start = timestamp; } proc:::exit /self->start/ { @[execname] = quantize(timestamp - self->start); self->start = 0; }
在生成服务器上运行示例脚本几秒钟后将产生与以下示例类似的输出:
# dtrace -s ./progtime.d dtrace: script './progtime.d' matched 2 probes ^C ir2hf value ------------- Distribution ------------- count 4194304 | 0 8388608 |@ 1 16777216 |@@@@@@@@@@@@@@@@ 14 33554432 |@@@@@@@@@@ 9 67108864 |@@@ 3 134217728 |@ 1 268435456 |@@@@ 4 536870912 |@ 1 1073741824 | 0 ube value ------------- Distribution ------------- count 16777216 | 0 33554432 |@@@@@@@ 6 67108864 |@@@ 3 134217728 |@@ 2 268435456 |@@@@ 4 536870912 |@@@@@@@@@@@@ 10 1073741824 |@@@@@@@ 6 2147483648 |@@ 2 4294967296 | 0 acomp value ------------- Distribution ------------- count 8388608 | 0 16777216 |@@ 2 33554432 | 0 67108864 |@ 1 134217728 |@@@ 3 268435456 | 0 536870912 |@@@@@ 5 1073741824 |@@@@@@@@@@@@@@@@@@@@@@@@@ 22 2147483648 |@ 1 4294967296 | 0 cc value ------------- Distribution ------------- count 33554432 | 0 67108864 |@@@ 3 134217728 |@ 1 268435456 | 0 536870912 |@@@@ 4 1073741824 |@@@@@@@@@@@@@@ 13 2147483648 |@@@@@@@@@@@@ 11 4294967296 |@@@ 3 8589934592 | 0 sh value ------------- Distribution ------------- count 262144 | 0 524288 |@ 5 1048576 |@@@@@@@ 29 2097152 | 0 4194304 | 0 8388608 |@@@ 12 16777216 |@@ 9 33554432 |@@ 9 67108864 |@@ 8 134217728 |@ 7 268435456 |@@@@@ 20 536870912 |@@@@@@ 26 1073741824 |@@@ 14 2147483648 |@@ 11 4294967296 | 3 8589934592 | 1 17179869184 | 0 make.bin value ------------- Distribution ------------- count 16777216 | 0 33554432 |@ 1 67108864 |@ 1 134217728 |@@ 2 268435456 | 0 536870912 |@@ 2 1073741824 |@@@@@@@@@ 9 2147483648 |@@@@@@@@@@@@@@@ 14 4294967296 |@@@@@@ 6 8589934592 |@@ 2 17179869184 | 0 |
您可能不需要知道特定进程运行的时间,而需要知道各个线程运行的时间。以下示例说明了如何将 lwp-start 和 lwp-exit 探测器用于此目的:
proc:::lwp-start /tid != 1/ { self->start = timestamp; } proc:::lwp-exit /self->start/ { @[execname] = quantize(timestamp - self->start); self->start = 0; }
在 NFS(网络文件系统)和日历服务器上运行示例脚本将产生与以下示例类似的输出:
# dtrace -s ./lwptime.d dtrace: script './lwptime.d' matched 3 probes ^C nscd value ------------- Distribution ------------- count 131072 | 0 262144 |@ 18 524288 |@@ 24 1048576 |@@@@@@@ 75 2097152 |@@@@@@@@@@@@@@@@@@@@@@@ 245 4194304 |@@ 22 8388608 |@@ 24 16777216 | 6 33554432 | 3 67108864 | 1 134217728 | 1 268435456 | 0 mountd value ------------- Distribution ------------- count 524288 | 0 1048576 |@ 15 2097152 |@ 24 4194304 |@@@ 51 8388608 |@ 17 16777216 |@ 24 33554432 |@ 15 67108864 |@@@@ 57 134217728 |@ 28 268435456 |@ 26 536870912 |@@ 39 1073741824 |@@@ 45 2147483648 |@@@@@ 72 4294967296 |@@@@@ 77 8589934592 |@@@ 55 17179869184 | 14 34359738368 | 2 68719476736 | 0 automountd value ------------- Distribution ------------- count 1048576 | 0 2097152 | 3 4194304 |@@@@ 146 8388608 | 6 16777216 | 6 33554432 | 9 67108864 |@@@@@ 203 134217728 |@@ 87 268435456 |@@@@@@@@@@@@@@@ 534 536870912 |@@@@@@ 223 1073741824 |@ 45 2147483648 | 20 4294967296 | 26 8589934592 | 20 17179869184 | 19 34359738368 | 7 68719476736 | 2 137438953472 | 0 iCald value ------------- Distribution ------------- count 8388608 | 0 16777216 |@@@@@@@ 20 33554432 |@@@ 9 67108864 |@@ 8 134217728 |@@@@@ 16 268435456 |@@@@ 11 536870912 |@@@@ 11 1073741824 |@ 4 2147483648 | 2 4294967296 | 0 8589934592 |@@ 8 17179869184 |@ 5 34359738368 |@ 4 68719476736 |@@ 6 137438953472 |@ 4 274877906944 | 2 549755813888 | 0 |
您可以使用 signal-send 探测器确定与任何信号关联的发送和接收进程,如下例所示:
#pragma D option quiet proc:::signal-send { @[execname, stringof(args[1]->pr_fname), args[2]] = count(); } END { printf("%20s %20s %12s %s\n", "SENDER", "RECIPIENT", "SIG", "COUNT"); printa("%20s %20s %12d %@d\n", @); }
运行此脚本将会生成与以下示例类似的输出:
# dtrace -s ./sig.d ^C SENDER RECIPIENT SIG COUNT xterm dtrace 2 1 xterm soffice.bin 2 1 tr init 18 1 sched test 18 1 sched fvwm2 18 1 bash bash 20 1 sed init 18 2 sched ksh 18 15 sched Xsun 22 471 |
proc 提供器使用 DTrace 的稳定性机制描述其稳定性,如下表所示。有关稳定性机制的更多信息,请参见第 39 章。
元素 |
名称稳定性 |
数据稳定性 |
相关性类 |
---|---|---|---|
提供器 |
发展中 |
发展中 |
ISA |
模块 |
专用 |
专用 |
未知 |
功能 |
专用 |
专用 |
未知 |
名称 |
发展中 |
发展中 |
ISA |
参数 |
发展中 |
发展中 |
ISA |