您能否在 DTrace 中以多 CPU 安全方式比较跨探测器的值?
Can you compare values across probes in a multi-CPU safe way in DTrace?
我正在尝试编写执行以下操作的 DTrace 脚本:
- 每当启动一个新线程时,增加一个计数。
- 每当这些线程之一退出时,递减计数,如果计数现在为零则退出脚本。
我有这样的东西:
BEGIN {
threads_alive = 0;
}
proc:::lwp-start /execname == $/ {
self->started = timestamp;
threads_alive += 1;
}
proc:::lwp-exit /self->started/ {
threads_alive -= 1;
if (threads_alive == 0) {
exit(0);
}
}
但是,这不起作用,因为 threads_alive
是一个标量变量,因此它不是 multi-cpu 安全的。结果,多个线程将覆盖彼此对变量的更改。
我也尝试过使用聚合变量:
@thread_count = sum(1)
//or
@threads_entered = count();
@threads_exitted = count();
不幸的是,我还没有找到能够执行 @thread_count == 0
或 @threads_started == @threads_stopped
.
之类的语法
DTrace 没有执行您提议的那种线程安全数据共享的工具,但您有几个选项,具体取决于您尝试执行的操作。
如果可执行文件名称是唯一的,您可以分别使用proc:::start
和proc:::exit
探测第一个线程的启动和最后一个线程的退出:
proc:::start
/execname == $/
{
my_pid = pid;
}
proc:::exit
/pid == my_pid/
{
exit(0);
}
如果您使用 dtrace
的 -c
选项,BEGIN
探测器会在相应的 proc:::start
之后不久触发。在内部,dtrace -c
启动指定的 fork 指定的命令,然后在四个点之一开始跟踪:exec
(在新程序的第一条指令之前),preinit
(在 ld 加载之后所有库),postinit
(在每个库的 _init
有 运行 之后),或 main
(就在程序的 main
函数的第一条指令之前,虽然这macOS 不支持)。
如果您使用 dtrace -x evaltime=exec -c <program>
BEGIN
将在程序的第一条指令执行之前触发:
# dtrace -xevaltime=exec -c /usr/bin/true -n 'BEGIN{ts = timestamp}' -n 'pid$target:::entry{printf("%dus", (timestamp - ts)/1000); exit(0); }'
dtrace: description 'BEGIN' matched 1 probe
dtrace: description 'pid$target:::entry' matched 1767 probes
dtrace: pid 1848 has exited
CPU ID FUNCTION:NAME
10 16757 _dyld_start:entry 285us
285us 是由于在 macOS 上通过 /proc
或 ptrace(2)
恢复进程需要 dtrace
的时间。您可以使用 BEGIN
、pid$target::_dyld_start:entry
或 pid$target::main:entry
.
而不是 proc:::start
或 proc:::lwp-start
我正在尝试编写执行以下操作的 DTrace 脚本:
- 每当启动一个新线程时,增加一个计数。
- 每当这些线程之一退出时,递减计数,如果计数现在为零则退出脚本。
我有这样的东西:
BEGIN {
threads_alive = 0;
}
proc:::lwp-start /execname == $/ {
self->started = timestamp;
threads_alive += 1;
}
proc:::lwp-exit /self->started/ {
threads_alive -= 1;
if (threads_alive == 0) {
exit(0);
}
}
但是,这不起作用,因为 threads_alive
是一个标量变量,因此它不是 multi-cpu 安全的。结果,多个线程将覆盖彼此对变量的更改。
我也尝试过使用聚合变量:
@thread_count = sum(1)
//or
@threads_entered = count();
@threads_exitted = count();
不幸的是,我还没有找到能够执行 @thread_count == 0
或 @threads_started == @threads_stopped
.
DTrace 没有执行您提议的那种线程安全数据共享的工具,但您有几个选项,具体取决于您尝试执行的操作。
如果可执行文件名称是唯一的,您可以分别使用proc:::start
和proc:::exit
探测第一个线程的启动和最后一个线程的退出:
proc:::start
/execname == $/
{
my_pid = pid;
}
proc:::exit
/pid == my_pid/
{
exit(0);
}
如果您使用 dtrace
的 -c
选项,BEGIN
探测器会在相应的 proc:::start
之后不久触发。在内部,dtrace -c
启动指定的 fork 指定的命令,然后在四个点之一开始跟踪:exec
(在新程序的第一条指令之前),preinit
(在 ld 加载之后所有库),postinit
(在每个库的 _init
有 运行 之后),或 main
(就在程序的 main
函数的第一条指令之前,虽然这macOS 不支持)。
如果您使用 dtrace -x evaltime=exec -c <program>
BEGIN
将在程序的第一条指令执行之前触发:
# dtrace -xevaltime=exec -c /usr/bin/true -n 'BEGIN{ts = timestamp}' -n 'pid$target:::entry{printf("%dus", (timestamp - ts)/1000); exit(0); }'
dtrace: description 'BEGIN' matched 1 probe
dtrace: description 'pid$target:::entry' matched 1767 probes
dtrace: pid 1848 has exited
CPU ID FUNCTION:NAME
10 16757 _dyld_start:entry 285us
285us 是由于在 macOS 上通过 /proc
或 ptrace(2)
恢复进程需要 dtrace
的时间。您可以使用 BEGIN
、pid$target::_dyld_start:entry
或 pid$target::main:entry
.
proc:::start
或 proc:::lwp-start