Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Commits on Mar 22, 2012
  1. @slfritchie @bufflig

    Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 1/4

    slfritchie authored bufflig committed
    Since it's been quite a while since I've written C code, *and* I
    haven't done any significant hacking on the VM itself in years, it's
    quite likely that I haven't done things in 100% proper style.  Or
    my co-collaborators Dustin Sallings (CouchBase) or Michal Ptaszek
    (Erlang Solutions).  My intent for this patch is to start discussion
    and review of DTrace support for consideration for the R15 release.
    
    For additional background on the motivation for this work, please
    see the slides for the presentation at the Erlang User Conference 2011
    in Stockholm:
      https://www.erlang-factory.com/upload/presentations/462/euc2011-draft2.pdf
    
    Changes relative to dtrace-review2 branch:
        * Fix errors in OTP test suite 'kernel' file_SUITE
        * Fix errors in OTP test suite 'kernel' prim_file_SUITE
        * Fix bad pointer bug in efile_drv.c flush_write()
        * Move the DTrace material from the top of `README.md` into a
          new file, `README.dtrace.md`
    
    Changes since last push to GitHub (relative to commit 5828a4f, which
    was the former `dtrace-review1` branch):
        * Rebased onto 14 Nov 2011's "master" branch
        * Recent changes to the async task queuing mechanism means that
          the async worker queue length is not available.  A bogus value
          of -1 is hard-coded until there's a good way to peek into the
          new queue structure and find the queue length.
        * Small fixes based on review comments by Mikael Pettersson,
          Andrew Thompson, and Andreas Schultz.
    
    Add autoconf support: use "./configure --enable-dtrace" on all supported
    platforms:
        * OS X Snow Leopard or later
        * Solaris 10 or OpenSolaris
        * Linux, via SystemTap's DTrace compatibility packages
        * FreeBSD 9.0RC1.  FreeBSD 8 and earlier do not have support
          for USDT, DTrace's User-land Statically Defined Tracing.
    
    See the file `erts/emulator/beam/erlang_dtrace.d` for the definition
    of all DTrace probes in the virtual machine so far.
    
    Example D scripts can be found in `lib/dtrace/examples`.  Note that if
    you see the error message `{name of probe} does not match any probes`,
    then there is no Erlang VM process + DTrace probes running.  To fix,
    start a DTrace-enabled VM or remove `-q` from the `dtrace` command line.
    
    The `lib/dtrace` directory contains a small code-only OTP application
    that contains code that allows Erlang code to trigger a DTrace probe.
    Dynamic creation & deletion of DTrace probes is not currently
    supported, so the `dtrace:p()` function is hacked to allow a variable
    number of arguments (up to four integers and up to four strings) to be
    used.  See the comments at the top of `lib/dtrace/src/dtrace.c` for
    more detail.
    
    One feature that may be controversial is the notion I've introduced
    of a special process dictionary key that can be used by Erlang code to
    tag I/O operations for an application-specific purpose.  Right now,
    that tag's name is `dtrace_utag`.  The dictionary keys used by `sys`
    and other modules start with a dollar sign.  Perhaps there is some
    convention (but not a dollar sign?) that this tag should use?
    
    The purpose of the process dictionary key is to allow the tag to
    be included in trace messages, e.g. for file I/O, without changing the
    API of the `file.erl` module's functions.  For example, here's a use
    of the tag when calling the `file:rename/2` function:
    
        (bar@sbb2)1> put(dtrace_utag, "GGOOOAAALL!!!!!").
        undefined
    
        (bar@sbb2)2> dtrace:init().
        ok
    
        %% Now start both the `user-probe.d` and `efile_drv.d` D scripts
        %% found in the `lib/dtrace/examples` directory.
    
        (bar@sbb2)3> dtrace:p(7, 8, 9, "one", "four").
        true
    
        %% The output from the `user-probe.d` script:
        <0.40.0> GGOOOAAALL!!!!! 7 8 9 0 'one' 'four' '' ''
    
        (bar@sbb2)4> file:rename("old-name", "new-name").
        {error,enoent}
    
        %% The output from the `efile_drv.d` script:
        async I/O pool port #Port<0.59> queue len 1
        async I/O pool port #Port<0.59> queue len 0
        efile_drv enter tag={1,110} user tag GGOOOAAALL!!!!! | RENAME (12) | args: old-name new-name , 0 0 (port #Port<0.59>)
        async I/O worker tag={1,110} | RENAME (12) | efile_drv-int_entry
        async I/O worker tag={1,110} | RENAME (12) | efile_drv-int_return
        efile_drv return tag={1,110} user tag GGOOOAAALL!!!!! | RENAME (12) | errno 2
    
    I'm not exactly happy with this choice of tagging, namely using
    `put(dtrace_utag, Tag::list())`.  But this is an experiment, so
    we'll see how it goes.  I can't imagine changing the API for
    all file.erl functions in order pass the tag explicitly.
    
    Some modules have some extensive (ab)use of the C preprocessor to
    reduce the amount of #ifdefs that clutter the code.  In several places,
    I have not #ifdef'ed automatic variables because of clutter.  For the
    same reason, there are a handful of cases where I added DTrace-related
    members to a struct definition without an #ifdef.  I feel that the
    result is easier to read than earlier drafts where I did use many more
    `https://github.com/slfritchie/otp/tree/dtrace-experiment+michal2` if
    you're curious.)  I expect there may be some debate about whether the
    bloat of the affected structs is worthwhile.  I erred on adding stuff
    to structs, especially in the efile_drv.c driver, not having a full
    grasp on what was thread-safe and what was not ... so I erred on the
    side of caution.
    
    The efile_drv.c has a work-around for a crazy GCC optimization bug.
    Thank goodness for Google, I dunno how I would've found a work-around
    for this silly thing.  Many thanks to Trond Norbye for writing clearly
    about the problem in a membase Git repo commit message.
    
    /*
     * A note on probe naming: if "__" appears in a provider probe
     * definition, then two things happen during compilation:
     *
     *    1. The "__" will turn into a hypen, "-", for the probe name.
     *    2. The "__" will turn into a single underscore, "_", for the
     *       macro names and function definitions that the compiler and
     *       C developers will see.
     *
     * We'll try to use the following naming convention.  We're a bit
     * limited because, as a USDT probe, we can only specify the 4th part
     * of the probe name, e.g. erlang*:::mumble.  The 2nd part of the
     * probe name is always going to be "beam" or "beam.smp", and the 3rd
     * part of the probe name will always be the name of the function
     * that's calling the probe.
     *
     * So, all probes will be have names defined in this file using the
     * convention category__name or category__sub_category__name.  This
     * will translate to probe names of category-name or
     * category-sub_category-name.
     *
     * Each of "category", "sub_category", and "name" may have underscores
     * but may not have hyphens.
     */
    
    Add tentative support for sequential tracing sending, queueing, and
    receiving a message.  I don't believe I've fully covered all the major
    places where it would be useful to have the sequential trace token info
    in a probe -- guidance from the OTP team would be helpful, if there's
    time to do that kind of review.
    
    Add global variable `erts_this_node_sysname`.
Something went wrong with that request. Please try again.