[DTrace-devel] restoring how DTrace adds probes

Eugene Loh eugene.loh at oracle.com
Mon Jun 8 12:25:06 PDT 2020


We should change DTrace's loading of probes to respond to which probes 
are requested by the user.  That is, we are currently populating probes 
in a fixed manner without regard for which probe descriptions were 
specified by the user, while legacy DTrace would load probes as 
requested by the user.  Restoring the legacy behavior and taking user 
requests in account is important for some probes -- like profile-* and 
tick-* -- that do not exist until the user requests them.

BACKGROUND.

Note that in the dtrace command-line tool, there are five passes through 
the command-line arguments.  Important events are:
   - the call to dtrace_open()
   - the second pass over arguments, collecting program specifications
   - the fourth pass, compiling these specifications

In legacy DTrace() (e.g., the master branch), probes are looked up -- or 
created if necessary -- during that fourth-pass compilation.  That is, 
we call
dt_compile_one_clause(),
which calls dt_setcontext() to look for a "representative probe",
which calls dt_probe_info(),
which calls dtrace_probe_iter(),
which dt_ioctl(dtp, DTRACEIOC_PROBEMATCH, &pd) to look up probes.

Then, in the kernel, dtrace_ioctl() has:
     /*
      * Before we attempt to match this probe, we want to give
      * all providers the opportunity to provide it.
      */
     dtrace_probe_provide(&desc, NULL);

That function loops over providers.  Each provider can provide probes to 
satisfy the specified probe description.

In contrast, in the most recent implementation of DTrace (e.g., the 
2.0-branch-dev branch), near the end of dtrace_open() -- strictly 
speaking, dt_vopen() -- we add:
     /*
      * Initialize the collection of probes that is made available by the
      * known providers.
      */
     dt_probe_init(dtp);
     for (i = 0; i < ARRAY_SIZE(dt_providers); i++)
                 dt_providers[i]->populate(dtp);

That is, we loop over providers to populate probes.  This is done before 
looking at any of the probe descriptions in command-line arguments or 
specified scripts.  The probes are provided from set lists, such as 
predefined dtrace probes (e.g., BEGIN and END) or probes found in lists 
in the tracefs file system.

Later, for example in dt_probe_iter(), the list of probes having been 
defined, we simply look up whether a probe is known or not. We do not 
currently allow a user to specify a probe that we did not already know.

I don't think I've thoroughly captured how the kernel handles probe 
queries in legacy DTrace;  the main point is simply that DTrace used to 
provide probes "on demand" while we now pre-define probe lists.

PROPOSAL.

Instead of the current "populate()" approach, in which each provider 
populates the list of probes without knowledge of the user's probe 
descriptions, let us revert to legacy DTrace's on-demand "provide()" 
approach, in which we track probes exclusively in response to 
user-specified probe descriptions. Specifically,

*)  In dt_vopen(), remove the new code that loops over providers calling 
their populate() functions.

*)  In dt_probe_iter(), allow providers to provide a probe.

DISCUSSION.

*)  We could use both mechanisms.  That is, during dtrace_open(), we can 
use the "populate()" model to populate probes without regards to 
user-specified probe descriptions.  Then later, when compiling probe 
descriptions, add probes as necessary.  But there is no value in having 
two mechanisms, and there is no sense in adding possibly tens of 
thousands of probes even in the relatively common case where the user 
specifies fewer than a dozen.

*)  We should clean up these two functions:
         - dtrace_probe_iter()
         -     dt_probe_iter()
Once again, we should revert somewhat to the legacy implementation.  
That is, dt_probe_iter() used to be a static function that was used 
simply as a callback within dtrace_probe_iter().  In the current 
version, dt_probe_iter() is no longer a static function.  On the other 
hand, it is still used only by dtrace_probe_iter().  And 
dtrace_probe_iter() has become simply a wrapper for dt_probe_iter().  
Therefore:
     - move probe iteration from dt_probe_iter() into dtrace_probe_iter()
     - if dt_probe_iter() is still needed, make it static once again

*)  DTrace has the IMHO peculiar practice of listing probes multiple 
times.  Consider:
     dtrace -n END -l -n BEGIN -n BEGIN
        ID   PROVIDER    MODULE    FUNCTION NAME
         2     dtrace                       END
         1     dtrace                       BEGIN
         1     dtrace                       BEGIN
This behavior is seen in both legacy and the current DTrace. Leaving 
this behavior is fine.

PROFILE PROVIDER.

While many providers can benefit from this proposal, it was motivated by 
the immediate desire to add a profile provider.  The following 
discussion is in that specific context.

*)  While users can specify their own profile probes, the provider 
should nonetheless provide some suggestive probes, following legacy 
DTrace's suit.  E.g., from the legacy kernel file dtrace/profile_dev.c:
     profile_rates[] = { 97, 199, 499, 997, 1999, 4001, 4999, ... };
     profile_ticks[] = { 1, 10, 100, 500, 1000, 5000, ...};

*)  A user probe description such as "profile:::" would clearly refer to 
all existing profile probes rather than to all conceivable profile probes.

*)  Legacy DTrace added profile probes persistently.  That is, if a user 
specified profile-1234, that probe would persist -- even to other DTrace 
invocations -- until the profile kernel module were unloaded.  The 
current implementation need not mimic such persistent behavior.




More information about the DTrace-devel mailing list