Home / Alt manpages / perldtrace(1)

  • perldtrace(1)
  • User command
  • linux

Trace Perl Subroutines with DTrace Probes

You will finish with a DTrace command that observes Perl subroutine entry and return, plus a way to trace file loads and interpreter phases. The examples follow the perldtrace(1) documentation installed with Perl 5.38.2. On this Ubuntu host, the perl-doc package is version 5.38.2-3.2ubuntu0.6, but the local Perl build does not include usable DTrace support, so the tracing commands are a portable recipe for a DTrace-capable system rather than a claim that they run here.

Allow about twenty minutes. You need a Perl binary compiled with -Dusedtrace, a DTrace implementation, and permission to observe the process. Perl and shell inspection commands are ordinary user commands. DTrace permissions depend on the operating system and its security policy; it may require elevated privileges. Do not use sudo automatically, and do not run probes against a production process until you understand the local tracing policy.

1. Check the Perl build before writing a probe

Perl exposes DTrace probes only when it was built with the -Dusedtrace configuration option. The manual says most systems build without them. Check the interpreter and the tracing tool first:

$ perl -v
$ command -v dtrace
$ perl -V | grep -i dtrace

The first command reports the Perl version. The second prints a path only when dtrace is installed. The third is a quick search of the build configuration; an empty result is not proof by itself, so treat it as a reason to check the platform's Perl build documentation or run a harmless probe test. On this host, Perl reports 5.38.2 and dtrace is not installed.

Checkpoint: if the Perl build lacks DTrace support, stop here. Rebuilding Perl or changing packages is outside this guide. The rest of the workflow applies to a suitable DTrace-capable installation.

2. Trace every Perl subroutine call

Use the sub-entry and sub-return probes together. This example asks DTrace to print the subroutine name:

# dtrace -qZn 'sub-entry, sub-return { trace(copyinstr(arg0)) }'

-n supplies the probe description, -Z allows the command to compile even when a matching probe is absent, and -q suppresses extra DTrace headers. The arg0 argument is the subroutine name. The process continues running while DTrace waits for matching events, so leave this terminal open.

In a second terminal, run a small Perl program:

$ perl -E 'sub outer { inner(@_) } sub inner { say shift } outer("hello")'
hello

The DTrace terminal receives entries for Perl's startup routines and for outer and inner, followed by corresponding return events. The exact internal function names and probe IDs are platform-specific. Stop the DTrace session with Ctrl-C after the test process exits. This ends observation and does not change the Perl program or its files.

3. Print source location and package

Both subroutine probes provide four arguments: subroutine name, file, line and package. Use them when a name alone is not enough:

# dtrace -n ':*perl*::sub-entry {
    printf("%s::%s entered at %s line %d\n",
        copyinstr(arg3), copyinstr(arg0), copyinstr(arg1), arg2);
}'

The :*perl*:: pattern selects Perl's provider probes. The package is arg3, the subroutine is arg0, the source file is arg1, and the line number is arg2. For returns, replace sub-entry with sub-return. The return probe describes the function that is returning, not the function that called it.

That caller limitation matters when interpreting output. DTrace can show a call sequence with the -F option and both probes, but the individual probe arguments do not provide caller metadata.

4. Watch modules being loaded

Use the file probes to see which files Perl is about to read and which it has successfully evaluated:

# dtrace -n ':*perl*:loading-file {
    printf("About to load %s\n", copyinstr(arg0));
}'
# dtrace -n ':*perl*:loaded-file {
    printf("Successfully loaded %s\n", copyinstr(arg0));
}'

loading-file fires before Perl reads a file for use, require or do. loaded-file fires after the file has been read and evaluated successfully. The argument is a local filesystem path, not a Module::Name string. Run only the probe you need, otherwise two DTrace sessions can make the output harder to follow.

5. Observe interpreter phases or opcodes

The phase-change probe reports transitions corresponding to Perl's ${^GLOBAL_PHASE} values. This prints the old and new phase:

# dtrace -n ':*perl*::phase-change {
    printf("Phase changed from %s to %s\n",
        copyinstr(arg1), copyinstr(arg0));
}'

Use op-entry when you need to count or inspect the opcodes executed by the Perl runloop:

# dtrace -qZn ':*perl*::op-entry {
    printf("About to execute opcode %s\n", copyinstr(arg0));
}'

This can produce a large volume of output. Start with a short, representative command and stop the session promptly. The probe fires before the opcode executes. If the Perl debugger is enabled, DTrace sees the event after debugger hooks but before the opcode itself.

6. Turn call events into useful counts

For a busy application, aggregate rather than printing every event. This manual-based example counts subroutine entries by fully qualified name and keeps the ten largest counts:

# dtrace -qZn 'sub-entry { @[strjoin(strjoin(copyinstr(arg3),"::"),copyinstr(arg0))] = count() } END { trunc(@, 10) }'

The result is a frequency table, not a timing profile. A frequently called function may be cheap, while a rarely called function may dominate elapsed time. Combine counts with a focused reproducer and other system-level probes when diagnosing a bottleneck.

7. Diagnose a failed or empty trace

A missing dtrace command means the tracing tool is not installed or is not on your PATH. An empty Perl configuration search, a probe compiler error, or no matching events usually points to an unsuitable Perl build, an incorrect provider pattern, or a process that has already exited. Check the exact Perl binary with command -v perl and repeat perl -v in the same environment used to start the program.

Do not treat -Z as a repair option. It suppresses an error for an absent probe, which is useful for portable scripts but can also hide a Perl build with no DTrace provider. For a first test, omit -Z and confirm that DTrace matches the probes. If the operating system refuses access, consult its DTrace privilege model or ask an administrator; changing security policy is not part of the trace itself.

Done means

  • You confirmed the Perl version, DTrace availability and whether the Perl build provides DTrace probes.
  • You traced subroutine entry and return for a short, controlled Perl command.
  • You know that probe arguments describe the invoked or returning subroutine, not its caller.
  • You can distinguish files about to load from files successfully loaded.
  • You used phase, opcode or aggregate probes only for a focused question and stopped high-volume tracing promptly.
  • You did not rebuild packages, alter persistent configuration or grant tracing privileges as an unexamined workaround.