I'm trying to write a DTrace script which does the following:
I have something like this:
BEGIN {
threads_alive = 0;
}
proc:::lwp-start /execname == $$1/ {
self->started = timestamp;
threads_alive += 1;
}
proc:::lwp-exit /self->started/ {
threads_alive -= 1;
if (threads_alive == 0) {
exit(0);
}
}
However, this doesn't work, because threads_alive
is a scalar variable and thus it is not multi-cpu safe. As a result, multiple threads will overwrite each other's changes to the variable.
I have also tried using an aggregate variable instead:
@thread_count = sum(1)
//or
@threads_entered = count();
@threads_exitted = count();
Unfortunately, I haven't found syntax to be able to do something like @thread_count == 0
or @threads_started == @threads_stopped
.
DTrace doesn't have facilities for doing the kind of thread-safe data sharing you're proposing, but you have a few options depending on precisely what you're trying to do.
If the executable name is unique, you can use the proc:::start
and proc:::exit
probes for the start of the first thread and the exit of the last thread respectively:
proc:::start
/execname == $$1/
{
my_pid = pid;
}
proc:::exit
/pid == my_pid/
{
exit(0);
}
If you're using the -c
option to dtrace
, the BEGIN
probe fires very shortly after the corresponding proc:::start
. Internally, dtrace -c
starts the specified forks the specified command and then starts tracing at one of four points: exec
(before the first instruction of the new program), preinit
(after ld has loaded all libraries), postinit
(after each library's _init
has run), or main
(right before the first instruction of the program's main
function, though this is not supported in macOS).
If you use dtrace -x evaltime=exec -c <program>
BEGIN
will fire right before the first instruction of the program executes:
# 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
The 285us is due to the time it takes dtrace
to resume the process via /proc
or ptrace(2)
on macOS. Rather than proc:::start
or proc:::lwp-start
you may be able to use BEGIN
, pid$target::_dyld_start:entry
, or pid$target::main:entry
.