From 0721ac40f91295bb3995f86966e5dd031028ca85 Mon Sep 17 00:00:00 2001 From: Scott Lystig Fritchie Date: Thu, 17 Nov 2011 00:42:55 -0600 Subject: Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 1/4 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 5828a4fb28, 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`. --- README.dtrace.md | 422 +++++++++++++++++++++++++++++++++++ configure.in | 4 + erts/configure.in | 76 +++++++ erts/emulator/Makefile.in | 25 ++- erts/emulator/beam/dtrace-wrapper.h | 118 ++++++++++ erts/emulator/beam/erl_driver.h | 2 + erts/emulator/beam/erl_node_tables.h | 1 + erts/emulator/beam/global.h | 7 + lib/Makefile | 2 +- lib/dtrace/Makefile | 36 +++ lib/dtrace/c_src/Makefile | 4 + lib/dtrace/c_src/Makefile.in | 152 +++++++++++++ lib/dtrace/c_src/dtrace.c | 174 +++++++++++++++ lib/dtrace/c_src/dtrace_user.d | 53 +++++ lib/dtrace/ebin/.placeholder | 0 lib/dtrace/src/Makefile | 102 +++++++++ lib/dtrace/src/dtrace.app.src | 27 +++ lib/dtrace/src/dtrace.appup.src | 19 ++ lib/dtrace/src/dtrace.erl | 216 ++++++++++++++++++ lib/dtrace/vsn.mk | 1 + 20 files changed, 1438 insertions(+), 3 deletions(-) create mode 100644 README.dtrace.md create mode 100644 erts/emulator/beam/dtrace-wrapper.h create mode 100644 lib/dtrace/Makefile create mode 100644 lib/dtrace/c_src/Makefile create mode 100644 lib/dtrace/c_src/Makefile.in create mode 100644 lib/dtrace/c_src/dtrace.c create mode 100644 lib/dtrace/c_src/dtrace_user.d create mode 100644 lib/dtrace/ebin/.placeholder create mode 100644 lib/dtrace/src/Makefile create mode 100644 lib/dtrace/src/dtrace.app.src create mode 100644 lib/dtrace/src/dtrace.appup.src create mode 100644 lib/dtrace/src/dtrace.erl create mode 100644 lib/dtrace/vsn.mk diff --git a/README.dtrace.md b/README.dtrace.md new file mode 100644 index 0000000000..71023dfe69 --- /dev/null +++ b/README.dtrace.md @@ -0,0 +1,422 @@ +DTrace and Erlang/OTP +===================== + +History +------- + +The first implementation of DTrace probes for the Erlang virtual +machine was presented at the [2008 Erlang User Conference] [4]. That +work, based on the Erlang/OTP R12 release, was discontinued due to +what appears to be miscommunication with the original developers. + +Several users have created Erlang port drivers, linked-in drivers, or +NIFs that allow Erlang code to try to activate a probe, +e.g. `foo_module:dtrace_probe("message goes here!")`. + +Goals +----- + +1. Annotate as much of the Erlang VM as is practical. + * The initial goal is to trace file I/O operations. +2. Support all platforms that implement DTrace: OS X, Solaris, + and (I hope) FreeBSD and NetBSD. +3. To the extent that it's practical, support SystemTap on Linux + via DTrace provider compatibility. +4. Allow Erlang code to supply annotations. + +Supported platforms +------------------- + +The autoconf procedure is supported, I believe, for OS X/Snow Leopard +and OpenSolaris/64-bit. Just add the `--enable-dtrace` option your +command to run the `configure` script. + +The code has been only very lightly tested on OS X. It ought to +compile on a Solaris 10 or OpenSolaris machine, but no promises yet. + +The autoconf stuff is ugly right now. It could use some cleaning up. +For example: + +* After editing the `erlang_dtrace.d` file, you need to re-run the +* top-level "configure" script in order to update `erlang_dtrace.h`. +* `make clean` will remove `erlang_dtrace.h`. A build will fail + unless the top-level "configure" script is re-run to re-create that + file. +* The `erlang_dtrace.h` file's location should probably be moved to an + OTP platform-specific build dir, for example, + `path/to/somewhere/i386-apple-darwin10.8.0` +* There are probably some other build by-products that are also being + put into the "wrong" directory, for example, `erlang_dtrace.o` for + Solaris platforms. + +Contributions +------------- + +Code contributions are welcome! This is a side project for me (SLF), +so things would go faster if other people are willing to pitch in. +Please use the GitHub pull request mechanism or send me an email +message. + +To build from scratch, use this recipe. If you're an experienced Git +user and wish to add my repository as a remote repository, be my +guest. Just resume the recipe at command #4. + + % git clone git://github.com/slfritchie/otp.git + % cd otp + % git checkout -b dtrace-experiment origin/dtrace-experiment + % env ERL_TOP=`pwd` ./otp_build autoconf + % env ERL_TOP=`pwd` ./configure --enable-dtrace + whatever args you need + % env ERL_TOP=`pwd` make + +Then `make install` and then start an Erlang shell via +`/path/to/installed/bin/erl +A 8`. The Erlang shell's banner should +include `[dtrace]`. + +Try using this (ugly) DTrace command to watch file I/O probes in use +(tested on OS X only, sorry): + + dtrace -Z -n 'erlang*:::efile_drv-entry {printf("%d %d %s | %d | %s %s , %d %d %d", arg0, arg1, arg2 == NULL ? "" : copyinstr(arg2), arg3, arg4 == NULL ? "" : copyinstr(arg4), arg5 == NULL ? "" : copyinstr(arg5), arg6, arg7, arg8)} erlang*:::efile_drv-int* {printf("%d %d %d | %d", arg0, arg1, arg2, arg3);} erlang*:::efile_drv-return {printf("%d %d %s | %d | %d %d %d", arg0, arg1, arg2 == NULL ? "" : copyinstr(arg2), arg3, arg4, arg5, arg6 ) ; }' + +Implementation summary +---------------------- + +So far, most effort has been focused on the `efile_drv.erl` code, +which implements most file I/O on behalf of the Erlang virtual +machine. This driver also presents a big challenge: its use of an I/O +worker pool (enabled by using the `erl +A 8` flag, for example) makes +it much more difficult to trace I/O activity because each of the +following may be executed in a different Pthread: + +* I/O initiation (Erlang code) +* I/O proxy process handling, e.g. read/write when file is not opened + in `raw` mode, operations executed by the code & file server processes. + (Erlang code) +* `efile_drv` command setup (C code) +* `efile_drv` command execution (C code) +* `efile_drv` status return (C code) + +**TODO: keep this description up-to-date.** + +Example output from `lib/dtrace/examples/efile_drv.d` while executing +`file:rename("old-name", "new-name")`: + + efile_drv enter tag={3,84} user tag some-user-tag | RENAME (12) | args: old-name new-name , 0 0 (port #Port<0.59>) + async I/O worker tag={3,83} | RENAME (12) | efile_drv-int_entry + async I/O worker tag={3,83} | RENAME (12) | efile_drv-int_return + efile_drv return tag={3,83} user tag | RENAME (12) | errno 2 + +... where the following key can help decipher the output: + +* `{3,83}` is the Erlang scheduler thread number (3) and operation + counter number (83) assigned to this I/O operation. Together, + these two numbers form a unique ID for the I/O operation. +* `12` is the command number for the rename operation. See the + definition for `FILE_RENAME` in the source code file `efile_drv.c` + or the `BEGIN` section of the D script `lib/dtrace/examples/efile_drv.d`. +* `old-name` and `new-name` are the two string arguments for the + source and destination of the `rename(2)` system call. + The two integer arguments are unused; the simple formatting code + prints the arguments anyway, 0 and 0. +* The worker pool code was called on behalf of Erlang port `#Port<0.59>`. +* The system call failed with a POSIX errno value of 2: `ENOENT`, + because the path `old-name` does not exist. +* The `efile_drv-int_entry` and `efile_drv_int_return` probes are + provided in case the user is + interested in measuring only the latency of code executed by + `efile_drv` asynchronous functions by I/O worker pool threads + and the OS system call that they encapsulate. + +So, where does the `some-user-tag` string come from? + +At the moment, the user tag comes from code like the following: + + put(dtrace_utag, "some-user-tag"), + file:rename("old-name", "new-name"). + +This method of tagging I/O at the Erlang level is subject to change. + +Example DTrace probe specification +---------------------------------- + + /** + * Fired when a message is sent from one local process to another. + * + * NOTE: The 'size' parameter is in machine-dependent words and + * that the actual size of any binary terms in the message + * are not included. + * + * @param sender the PID (string form) of the sender + * @param receiver the PID (string form) of the receiver + * @param size the size of the message being delivered (words) + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe message__send(char *sender, char *receiver, uint32_t size, + int token_label, int token_previous, int token_current); + + /** + * Fired when a message is sent from a local process to a remote process. + * + * NOTE: The 'size' parameter is in machine-dependent words and + * that the actual size of any binary terms in the message + * are not included. + * + * @param sender the PID (string form) of the sender + * @param node_name the Erlang node name (string form) of the receiver + * @param receiver the PID/name (string form) of the receiver + * @param size the size of the message being delivered (words) + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe message__send__remote(char *sender, char *node_name, char *receiver, + uint32_t size, + int token_label, int token_previous, int token_current); + + /** + * Fired when a message is queued to a local process. This probe + * will not fire if the sender's pid == receiver's pid. + * + * NOTE: The 'size' parameter is in machine-dependent words and + * that the actual size of any binary terms in the message + * are not included. + * + * @param receiver the PID (string form) of the receiver + * @param size the size of the message being delivered (words) + * @param queue_len length of the queue of the receiving process + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe message__queued(char *receiver, uint32_t size, uint32_t queue_len, + int token_label, int token_previous, int token_current); + + /** + * Fired when a message is 'receive'd by a local process and removed + * from its mailbox. + * + * NOTE: The 'size' parameter is in machine-dependent words and + * that the actual size of any binary terms in the message + * are not included. + * + * @param receiver the PID (string form) of the receiver + * @param size the size of the message being delivered (words) + * @param queue_len length of the queue of the receiving process + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe message__receive(char *receiver, uint32_t size, uint32_t queue_len, + int token_label, int token_previous, int token_current); + + /* ... */ + + /* Async driver pool */ + + /** + * Show the post-add length of the async driver thread pool member's queue. + * + * NOTE: The port name is not available: additional lock(s) must + * be acquired in order to get the port name safely in an SMP + * environment. The same is true for the aio__pool_get probe. + * + * @param port the Port (string form) + * @param new queue length + */ + probe aio_pool__add(char *, int); + + /** + * Show the post-get length of the async driver thread pool member's queue. + * + * @param port the Port (string form) + * @param new queue length + */ + probe aio_pool__get(char *, int); + + /* Probes for efile_drv.c */ + + /** + * Entry into the efile_drv.c file I/O driver + * + * For a list of command numbers used by this driver, see the section + * "Guide to probe arguments" in ../../../README.md. That section + * also contains explanation of the various integer and string + * arguments that may be present when any particular probe fires. + * + * TODO: Adding the port string, args[10], is a pain. Making that + * port string available to all the other efile_drv.c probes + * will be more pain. Is the pain worth it? If yes, then + * add them everywhere else and grit our teeth. If no, then + * rip it out. + * + * @param thread-id number of the scheduler Pthread arg0 + * @param tag number: {thread-id, tag} uniquely names a driver operation + * @param user-tag string arg2 + * @param command number arg3 + * @param string argument 1 arg4 + * @param string argument 2 arg5 + * @param integer argument 1 arg6 + * @param integer argument 2 arg7 + * @param integer argument 3 arg8 + * @param integer argument 4 arg9 + * @param port the port ID of the busy port args[10] + */ + probe efile_drv__entry(int, int, char *, int, char *, char *, + int64_t, int64_t, int64_t, int64_t, char *); + + /** + * Entry into the driver's internal work function. Computation here + * is performed by a async worker pool Pthread. + * + * @param thread-id number + * @param tag number + * @param command number + */ + probe efile_drv__int_entry(int, int, int); + + /** + * Return from the driver's internal work function. + * + * @param thread-id number + * @param tag number + * @param command number + */ + probe efile_drv__int_return(int, int, int); + + /** + * Return from the efile_drv.c file I/O driver + * + * @param thread-id number arg0 + * @param tag number arg1 + * @param user-tag string arg2 + * @param command number arg3 + * @param Success? 1 is success, 0 is failure arg4 + * @param If failure, the errno of the error. arg5 + */ + probe efile_drv__return(int, int, char *, int, int, int); + +Guide to efile_drv.c probe arguments +------------------------------------ + + /* Driver op code: used by efile_drv-entry arg3 */ + /* used by efile_drv-int_entry arg3 */ + /* used by efile_drv-int_return arg3 */ + /* used by efile_drv-return arg3 */ + + #define FILE_OPEN 1 (probe arg3) + probe arg6 = C driver dt_i1 = flags; + probe arg4 = C driver dt_s1 = path; + + #define FILE_READ 2 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = flags; + probe arg8 = C driver dt_i3 = size; + + #define FILE_LSEEK 3 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = offset; + probe arg8 = C driver dt_i3 = origin; + + #define FILE_WRITE 4 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = flags; + probe arg8 = C driver dt_i3 = size; + + #define FILE_FSTAT 5 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + + #define FILE_PWD 6 (probe arg3) + none + + #define FILE_READDIR 7 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_CHDIR 8 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_FSYNC 9 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + + #define FILE_MKDIR 10 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_DELETE 11 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_RENAME 12 (probe arg3) + probe arg4 = C driver dt_s1 = old_name; + probe arg5 = C driver dt_s2 = new_name; + + #define FILE_RMDIR 13 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_TRUNCATE 14 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = flags; + + #define FILE_READ_FILE 15 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_WRITE_INFO 16 (probe arg3) + probe arg6 = C driver dt_i1 = mode; + probe arg7 = C driver dt_i2 = uid; + probe arg8 = C driver dt_i3 = gid; + + #define FILE_LSTAT 19 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_READLINK 20 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_LINK 21 (probe arg3) + probe arg4 = C driver dt_s1 = existing_path; + probe arg5 = C driver dt_s2 = new_path; + + #define FILE_SYMLINK 22 (probe arg3) + probe arg4 = C driver dt_s1 = existing_path; + probe arg5 = C driver dt_s2 = new_path; + + #define FILE_CLOSE 23 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = flags; + + #define FILE_PWRITEV 24 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = flags; + probe arg8 = C driver dt_i3 = size; + + #define FILE_PREADV 25 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = flags; + probe arg8 = C driver dt_i3 = size; + + #define FILE_SETOPT 26 (probe arg3) + probe arg6 = C driver dt_i1 = opt_name; + probe arg7 = C driver dt_i2 = opt_specific_value; + + #define FILE_IPREAD 27 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = flags; + probe arg8 = C driver dt_i3 = offsets[0]; + probe arg9 = C driver dt_i4 = size; + + #define FILE_ALTNAME 28 (probe arg3) + probe arg4 = C driver dt_s1 = path; + + #define FILE_READ_LINE 29 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = flags; + probe arg8 = C driver dt_i3 = read_offset; + probe arg9 = C driver dt_i4 = read_ahead; + + #define FILE_FDATASYNC 30 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + + #define FILE_FADVISE 31 (probe arg3) + probe arg6 = C driver dt_i1 = fd; + probe arg7 = C driver dt_i2 = offset; + probe arg8 = C driver dt_i3 = length; + probe arg9 = C driver dt_i4 = advise_type; + + [1]: http://www.erlang.org/euc/08/ diff --git a/configure.in b/configure.in index 2c3ee1cb57..0d54dcd3a3 100644 --- a/configure.in +++ b/configure.in @@ -225,6 +225,10 @@ AC_ARG_ENABLE(native-libs, AS_HELP_STRING([--enable-native-libs], [compile Erlang libraries to native code])) +AC_ARG_ENABLE(dtrace, +AS_HELP_STRING([--enable-dtrace], + [Enable DTrace probes])) + AC_ARG_WITH(javac, AS_HELP_STRING([--with-javac=JAVAC], [specify Java compiler to use]) AS_HELP_STRING([--with-javac], [use a Java compiler if found (default)]) diff --git a/erts/configure.in b/erts/configure.in index b801994e14..88c73a7371 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -3545,6 +3545,81 @@ dnl LM_FIND_EMU_CC +dnl +dnl DTrace +dnl + +AC_MSG_CHECKING(if --enable-dtrace option specified) +AC_ARG_ENABLE(dtrace, + [AC_HELP_STRING([--enable-dtrace], + [Configure with dtrace static probes])], + [enable_dtrace="$enable_dtrace"]) dnl, [enable_dtrace="no"]) + +if test "$enable_dtrace" = "yes"; then + AC_CHECK_TOOL(DTRACE, dtrace, none) + test "$DTRACE" = "none" && AC_MSG_ERROR([No dtrace utility found.]) +else + AC_MSG_RESULT([not specified]) +fi + +AC_SUBST(DTRACE) + +AC_SUBST(DTRACE_CPP) +AC_SUBST(DTRACE_ENABLED) +AC_SUBST(DTRACE_ENABLED_2STEP) +DTRACE_CPP=-C +DTRACE_ENABLED= +DTRACE_ENABLED_2STEP= +DTRACE_2STEP_TEST=./dtrace-test.o +DTRACE_BITS_FLAG= +case $OPSYS in + freebsd) + if test "$BITS64" = "yes" ; then + DTRACE_BITS_FLAG=-64 + else + DTRACE_BITS_FLAG=-32 + fi + ;; + *) + : # Nothing to do + ;; +esac +if test "$enable_dtrace" = "yes" ; then + if test "$DTRACE" = "dtrace" ; then + AC_CHECK_HEADERS(sys/sdt.h) + # The OS X version of dtrace prints a spurious line here. + if ! dtrace -h $DTRACE_CPP -Iemulator/beam -o ./foo-dtrace.h -s emulator/beam/erlang_dtrace.d; then + AC_MSG_ERROR([Could not precompile erlang_dtrace.d: dtrace -h failed]) + fi + rm -f foo-dtrace.h + + $RM -f $DTRACE_2STEP_TEST + if dtrace -G $DTRACE_CPP $DTRACE_BITS_FLAG -Iemulator/beam -o $DTRACE_2STEP_TEST -s emulator/beam/erlang_dtrace.d 2> /dev/null && \ + test -f $DTRACE_2STEP_TEST ; then + rm $DTRACE_2STEP_TEST + DTRACE_ENABLED_2STEP=yes + AC_MSG_NOTICE([dtrace precompilation for 2-stage DTrace successful]) + else + AC_MSG_NOTICE([dtrace precompilation for 1-stage DTrace successful]) + fi + DTRACE_ENABLED=yes + AC_DEFINE(HAVE_DTRACE, 1, [Define to enable DTrace probes (or SystemTap probes on Linux systems)]) + case $OPSYS in + linux) + : # No extra libs to add to LIBS + ;; + freebsd) + LIBS="$LIBS -lelf" + ;; + *) + LIBS="$LIBS -ldtrace" + ;; + esac + else + AC_MSG_ERROR([Dtrace preprocessing test failed.]) + fi +fi + dnl dnl SSL, SSH and CRYPTO need the OpenSSL libraries dnl @@ -4388,6 +4463,7 @@ dnl ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in dnl ../lib/ssl/c_src/$host/Makefile:../lib/ssl/c_src/Makefile.in ../lib/crypto/c_src/$host/Makefile:../lib/crypto/c_src/Makefile.in + ../lib/dtrace/c_src/$host/Makefile:../lib/dtrace/c_src/Makefile.in ../lib/orber/c_src/$host/Makefile:../lib/orber/c_src/Makefile.in ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in ../lib/tools/c_src/$host/Makefile:../lib/tools/c_src/Makefile.in diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 279844adb2..3fb0964810 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -23,6 +23,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk ENABLE_ALLOC_TYPE_VARS = @ENABLE_ALLOC_TYPE_VARS@ HIPE_ENABLED=@HIPE_ENABLED@ +DTRACE_ENABLED=@DTRACE_ENABLED@ +DTRACE_ENABLED_2STEP=@DTRACE_ENABLED_2STEP@ LIBS = @LIBS@ Z_LIB=@Z_LIB@ NO_INLINE_FUNCTIONS=false @@ -483,6 +485,10 @@ GENERATE += $(HIPE_ASM) \ endif endif +ifdef DTRACE_ENABLED +GENERATE += $(TARGET)/erlang_dtrace.h +endif + ifdef HIPE_ENABLED OPCODE_TABLES += hipe/hipe_ops.tab endif @@ -590,6 +596,11 @@ $(TTF_DIR)/GENERATED: $(GENERATE) echo $? >$(TTF_DIR)/GENERATED endif +$(TARGET)/erlang_dtrace.h: beam/erlang_dtrace.d + dtrace -h -C -Ibeam -s $< -o ./erlang_dtrace.tmp + sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./erlang_dtrace.tmp > $@ + rm ./erlang_dtrace.tmp + # ---------------------------------------------------------------------- # Pattern rules # @@ -633,7 +644,6 @@ $(OBJDIR)/beam_emu.o: beam/beam_emu.c $(EMU_CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@ endif - $(OBJDIR)/%.o: beam/%.c $(CC) $(subst -O2, $(GEN_OPT_FLGS), $(CFLAGS)) $(INCLUDES) -c $< -o $@ @@ -833,7 +843,18 @@ endif BASE_OBJS = $(RUN_OBJS) $(EMU_OBJS) $(OS_OBJS) $(EXTRA_BASE_OBJS) -OBJS = $(BASE_OBJS) $(DRV_OBJS) +before_DTrace_OBJS = $(BASE_OBJS) $(DRV_OBJS) + +DTRACE_OBJS = +ifdef DTRACE_ENABLED_2STEP +DTRACE_OBJS = $(OBJDIR)/erlang_dtrace.o +$(OBJDIR)/erlang_dtrace.o: $(before_DTrace_OBJS) $(TARGET)/erlang_dtrace.h + dtrace -G -C -Ibeam \ + -s beam/erlang_dtrace.d \ + -o $@ $(before_DTrace_OBJS) +endif + +OBJS = $(before_DTrace_OBJS) $(DTRACE_OBJS) $(INIT_OBJS): $(TTF_DIR)/GENERATED $(OBJS): $(TTF_DIR)/GENERATED diff --git a/erts/emulator/beam/dtrace-wrapper.h b/erts/emulator/beam/dtrace-wrapper.h new file mode 100644 index 0000000000..f93871bd25 --- /dev/null +++ b/erts/emulator/beam/dtrace-wrapper.h @@ -0,0 +1,118 @@ +/* + * %CopyrightBegin% + * + * Copyright Dustin Sallings, Michal Ptaszek, Scott Lystig Fritchie 2011. + * All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +#ifndef __DTRACE_WRAPPER_H +#define __DTRACE_WRAPPER_H + +#define DTRACE_TERM_BUF_SIZE 256 + +#ifndef DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS +inline void dtrace_proc_str(Process *process, char *process_buf); +inline void dtrace_pid_str(Eterm pid, char *process_buf); +inline void dtrace_port_str(Port *port, char *port_buf); +inline void dtrace_fun_decode(Process *process, + Eterm module, Eterm function, int arity, + char *process_buf, char *mfa_buf); +#endif + +/* + * Some varieties of SystemTap macros do not like statically-sized + * char[N] buffers. (For example, CentOS 6's macros.) + * So, we'll play a game to humor them. + * + * The code necessary to play nice with CentOS 6's SystemTap looks + * stupid to a C programmer's eyes, so we hide the ugliness with this + * macro, which expands: + * + * DTRACE_CHARBUF(proc_name, 64); + * + * to become: + * + * char proc_name_BUFFER[64], *proc_name = proc_name_BUFFER; + */ + +#define DTRACE_CHARBUF(name, size) \ + char name##_BUFFER[size], *name = name##_BUFFER + +#ifdef HAVE_DTRACE + +#include "erlang_dtrace.h" + +#define DTRACE_ENABLED(name) \ + erlang_##name##_enabled() +#define DTRACE0(name) \ + erlang_##name() +#define DTRACE1(name, a0) \ + erlang_##name(a0) +#define DTRACE2(name, a0, a1) \ + erlang_##name((a0), (a1)) +#define DTRACE3(name, a0, a1, a2) \ + erlang_##name((a0), (a1), (a2)) +#define DTRACE4(name, a0, a1, a2, a3) \ + erlang_##name((a0), (a1), (a2), (a3)) +#define DTRACE5(name, a0, a1, a2, a3, a4) \ + erlang_##name((a0), (a1), (a2), (a3), (a4)) +#define DTRACE6(name, a0, a1, a2, a3, a4, a5) \ + erlang_##name((a0), (a1), (a2), (a3), (a4), (a5)) +#define DTRACE7(name, a0, a1, a2, a3, a4, a5, a6) \ + erlang_##name((a0), (a1), (a2), (a3), (a4), (a5), (a6)) +#define DTRACE10(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ + erlang_##name((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9)) +#define DTRACE11(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ + erlang_##name((a0), (a1), (a2), (a3), (a4), (a5), (a6), (a7), (a8), (a9), (a10)) + +#if defined(_SDT_PROBE) && !defined(STAP_PROBE11) +/* SLF: This is Ubuntu 11-style SystemTap hackery */ +/* work arround for missing STAP macro */ +#define STAP_PROBE11(provider,name,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_PROBE(provider, name, 11, \ + (arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11)) +#define _SDT_ASM_OPERANDS_11(arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11) \ + _SDT_ASM_OPERANDS_10(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9,arg10), \ + _SDT_ARG(11, arg11) +#endif + +#ifdef STAP_PROBE_ADDR +/* SLF: This is CentOS 5-style SystemTap hackery */ +/* SystemTap compat mode cannot support 11 args. We'll ignore the 11th */ +#define STAP_PROBE11(provider,probe,parm1,parm2,parm3,parm4,parm5,parm6,parm7,parm8,parm9,parm10,parm11) \ + STAP_PROBE10(provider,probe,(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7),(parm8),(parm9),(parm10)) +#endif /* STAP_PROBE_ADDR */ + +#else /* HAVE_DTRACE */ + +/* Render all macros to do nothing */ +#define DTRACE_ENABLED(name) 0 +#define DTRACE0(name) do {} while (0) +#define DTRACE1(name, a0) do {} while (0) +#define DTRACE2(name, a0, a1) do {} while (0) +#define DTRACE3(name, a0, a1, a2) do {} while (0) +#define DTRACE4(name, a0, a1, a2, a3) do {} while (0) +#define DTRACE5(name, a0, a1, a2, a3, a4) do {} while (0) +#define DTRACE6(name, a0, a1, a2, a3, a4, a5) do {} while (0) +#define DTRACE7(name, a0, a1, a2, a3, a4, a5, a6) do {} while (0) +#define DTRACE10(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ + do {} while (0) +#define DTRACE11(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ + do {} while (0) + +#endif /* HAVE_DTRACE */ + +#endif /* __DTRACE_WRAPPER_H */ diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index 7510f6b724..1ae9a211d7 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -649,6 +649,8 @@ EXTERN int erl_drv_getenv(char *key, char *value, size_t *value_size); #endif +/* also in global.h, but driver's can't include global.h */ +void dtrace_drvport_str(ErlDrvPort port, char *port_buf); diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h index b0a63ae035..8abb748a78 100644 --- a/erts/emulator/beam/erl_node_tables.h +++ b/erts/emulator/beam/erl_node_tables.h @@ -169,6 +169,7 @@ extern Sint erts_no_of_not_connected_dist_entries; extern DistEntry *erts_this_dist_entry; extern ErlNode *erts_this_node; +extern char erts_this_node_sysname[256]; /* must match erl_node_tables.c */ DistEntry *erts_channel_no_to_dist_entry(Uint); DistEntry *erts_sysname_to_connected_dist_entry(Eterm); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 97d7f0e904..6f6263d160 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1072,6 +1072,13 @@ void process_main(void); Eterm build_stacktrace(Process* c_p, Eterm exc); Eterm expand_error_value(Process* c_p, Uint freason, Eterm Value); void erts_save_stacktrace(Process* p, struct StackTrace* s, int depth); +ERTS_INLINE void dtrace_proc_str(Process *process, char *process_buf); +ERTS_INLINE void dtrace_pid_str(Eterm pid, char *process_buf); +ERTS_INLINE void dtrace_port_str(Port *port, char *port_buf); +ERTS_INLINE void dtrace_drvport_str(ErlDrvPort port, char *port_buf); +ERTS_INLINE void dtrace_fun_decode(Process *process, + Eterm module, Eterm function, int arity, + char *process_buf, char *mfa_buf); /* erl_init.c */ diff --git a/lib/Makefile b/lib/Makefile index aa4e074830..96ce2d1315 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -31,7 +31,7 @@ ifdef BUILD_ALL cosTransactions cosEvent cosTime cosNotification \ cosProperty cosFileTransfer cosEventDomain et megaco webtool \ xmerl edoc eunit ssh inviso typer erl_docgen \ - percept dialyzer hipe + percept dialyzer dtrace hipe EXTRA_FILE := $(wildcard EXTRA-APPLICATIONS) EXTRA_APPLICATIONS := $(if $(EXTRA_FILE),$(shell cat $(EXTRA_FILE))) endif diff --git a/lib/dtrace/Makefile b/lib/dtrace/Makefile new file mode 100644 index 0000000000..29d463aab1 --- /dev/null +++ b/lib/dtrace/Makefile @@ -0,0 +1,36 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# +# Macros +# + +SUB_DIRECTORIES = src c_src + +include vsn.mk +VSN = $(DTRACE_VSN) + +SPECIAL_TARGETS = + +# +# Default Subdir Targets +# +include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/dtrace/c_src/Makefile b/lib/dtrace/c_src/Makefile new file mode 100644 index 0000000000..f3320bb766 --- /dev/null +++ b/lib/dtrace/c_src/Makefile @@ -0,0 +1,4 @@ +# +# Invoke with GNU make or clearmake -C gnu. +# +include $(ERL_TOP)/make/run_make.mk diff --git a/lib/dtrace/c_src/Makefile.in b/lib/dtrace/c_src/Makefile.in new file mode 100644 index 0000000000..ed13684a95 --- /dev/null +++ b/lib/dtrace/c_src/Makefile.in @@ -0,0 +1,152 @@ +# +# %CopyrightBegin% +# +# Copyright Scott Lystig Fritchie 2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk +include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk + +# ---------------------------------------------------- +# Items from top-level configure +# ---------------------------------------------------- +DTRACE_ENABLED=@DTRACE_ENABLED@ +DTRACE_ENABLED_2STEP=@DTRACE_ENABLED_2STEP@ + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(DTRACE_VSN) + +# ---------------------------------------------------- +# The following variables differ between systems. +# Set by configure. +# ---------------------------------------------------- +CC = $(DED_CC) +LD = $(DED_LD) +SHELL = /bin/sh +LIBS = $(DED_LIBS) +LDFLAGS += $(DED_LDFLAGS) +CFLAGS = $(DED_CFLAGS) + +DTRACE_LIBNAME = dtrace + + +INCLUDES = $(DED_INCLUDES) + +ifeq ($(TYPE),debug) +TYPEMARKER = .debug +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DDEBUG +else +ifeq ($(TYPE),valgrind) +TYPEMARKER = .valgrind +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DVALGRIND +else +TYPEMARKER = +TYPE_FLAGS = $(CFLAGS) +endif +endif + +ALL_CFLAGS = $(TYPE_FLAGS) $(INCLUDES) -I$(OBJDIR) \ + -I$(ERL_TOP)/erts/emulator/$(TARGET) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/dtrace-$(VSN) + +# ---------------------------------------------------- +# Misc Macros +# ---------------------------------------------------- +OBJS = $(OBJDIR)/dtrace$(TYPEMARKER).o +## NIF_MAKEFILE = $(PRIVDIR)/Makefile + +# Higher-level makefiles says that we can only compile on UNIX flavors +NIF_LIB = $(LIBDIR)/dtrace$(TYPEMARKER).so + +ifeq ($(HOST_OS),) +HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess) +endif + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt valgrind: $(OBJDIR) $(LIBDIR) $(NIF_LIB) + +ifdef DTRACE_ENABLED +DTRACE_USER_HEADER=$(OBJDIR)/dtrace_user.h +$(OBJDIR)/dtrace_user.h: ./dtrace_user.d + dtrace -h -C $(INCLUDES) \ + -s ./dtrace_user.d \ + -o ./dtrace_user.tmp + sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./dtrace_user.tmp > $@ + rm ./dtrace_user.tmp +else +DTRACE_USER_HEADER= +endif + +ifdef DTRACE_ENABLED_2STEP +OBJS += $(OBJDIR)/dtrace_user.o +$(OBJDIR)/dtrace_user.o: $(OBJS) $(OBJDIR)/dtrace_user.h + touch $(OBJDIR)/erlang_dtrace.c + $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/erlang_dtrace.c + # The object file created above is immediately clobbered below. + # But creating it above avoids chicken-and-egg problem with OBJS + dtrace -G -C \ + -s ./dtrace_user.d \ + -o $@ $(OBJS) +endif + +$(OBJDIR): + -@mkdir -p $(OBJDIR) + +$(LIBDIR): + -@mkdir -p $(LIBDIR) + +$(OBJDIR)/%$(TYPEMARKER).o: %.c $(DTRACE_USER_HEADER) + $(INSTALL_DIR) $(OBJDIR) + $(CC) -c -o $@ $(ALL_CFLAGS) $< + +$(LIBDIR)/dtrace$(TYPEMARKER).so: $(OBJS) + $(INSTALL_DIR) $(LIBDIR) + $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +clean: + rm -f $(LIBDIR)/dtrace.so + rm -f $(LIBDIR)/dtrace.debug.so + rm -f $(LIBDIR)/dtrace.valgrind.so + rm -f $(OBJDIR)/dtrace.o + rm -f $(OBJDIR)/dtrace.debug.o + rm -f $(OBJDIR)/dtrace.valgrind.o + rm -f core *~ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/priv/obj + $(INSTALL_DIR) $(RELSYSDIR)/priv/lib + # $(INSTALL_DATA) $(NIF_MAKEFILE) $(RELSYSDIR)/priv/obj + $(INSTALL_PROGRAM) $(OBJS) $(RELSYSDIR)/priv/obj + $(INSTALL_PROGRAM) $(NIF_LIB) $(RELSYSDIR)/priv/lib + +release_docs_spec: diff --git a/lib/dtrace/c_src/dtrace.c b/lib/dtrace/c_src/dtrace.c new file mode 100644 index 0000000000..c9d25ece9c --- /dev/null +++ b/lib/dtrace/c_src/dtrace.c @@ -0,0 +1,174 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Dynamically loadable NIF library for DTrace + */ + + +#include "erl_nif.h" +#include "config.h" +#include "sys.h" +#define DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS +#include "dtrace-wrapper.h" +#ifdef HAVE_DTRACE +#include "dtrace_user.h" +#endif + +void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf); +void get_string_maybe(ErlNifEnv *env, const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz); + +#ifdef VALGRIND + # include +#endif + +#ifdef __GNUC__ + # define INLINE __inline__ +#else + # define INLINE +#endif + +#define MESSAGE_BUFSIZ 1024 + +/* NIF interface declarations */ +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); + +/* The NIFs: */ +static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +static ErlNifFunc nif_funcs[] = { + {"available", 0, available}, + {"user_trace_s1", 1, user_trace_s1}, + {"user_trace_i4s4", 9, user_trace_i4s4} +}; + +ERL_NIF_INIT(dtrace, nif_funcs, load, NULL, NULL, NULL) + +static ERL_NIF_TERM atom_true; +static ERL_NIF_TERM atom_false; +static ERL_NIF_TERM atom_error; +static ERL_NIF_TERM atom_not_available; +static ERL_NIF_TERM atom_badarg; +static ERL_NIF_TERM atom_ok; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + atom_true = enif_make_atom(env,"true"); + atom_false = enif_make_atom(env,"false"); + atom_error = enif_make_atom(env,"error"); + atom_not_available = enif_make_atom(env,"not_available"); + atom_badarg = enif_make_atom(env,"badarg"); + atom_ok = enif_make_atom(env,"ok"); + + return 0; +} + +static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_DTRACE + return atom_true; +#else + return atom_false; +#endif +} + +static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_DTRACE + ErlNifBinary message_bin; + DTRACE_CHARBUF(messagebuf, MESSAGE_BUFSIZ + 1); + + if (DTRACE_ENABLED(user_trace_s1)) { + if (!enif_inspect_iolist_as_binary(env, argv[0], &message_bin) || + message_bin.size > MESSAGE_BUFSIZ) { + return atom_badarg; + } + memcpy(messagebuf, (char *) message_bin.data, message_bin.size); + messagebuf[message_bin.size] = '\0'; + DTRACE1(user_trace_s1, messagebuf); + return atom_true; + } else { + return atom_false; + } +#else + return atom_error; +#endif +} + +void +get_string_maybe(ErlNifEnv *env, + const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz) +{ + ErlNifBinary str_bin; + + if (!enif_inspect_iolist_as_binary(env, term, &str_bin) || + str_bin.size > bufsiz) { + *ptr = NULL; + } else { + memcpy(buf, (char *) str_bin.data, str_bin.size); + buf[str_bin.size] = '\0'; + *ptr = buf; + } +} + +static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_DTRACE + DTRACE_CHARBUF(procbuf, 32 + 1); + DTRACE_CHARBUF(user_tagbuf, MESSAGE_BUFSIZ + 1); + char *utbuf = NULL; + ErlNifSInt64 i1, i2, i3, i4; + DTRACE_CHARBUF(messagebuf1, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf2, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf3, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf4, MESSAGE_BUFSIZ + 1); + char *mbuf1 = NULL, *mbuf2 = NULL, *mbuf3 = NULL, *mbuf4 = NULL; + + if (DTRACE_ENABLED(user_trace_i4s4)) { + dtrace_nifenv_str(env, procbuf); + get_string_maybe(env, argv[0], &utbuf, + user_tagbuf, sizeof(user_tagbuf)-1); + if (! enif_get_int64(env, argv[1], &i1)) + i1 = 0; + if (! enif_get_int64(env, argv[2], &i2)) + i2 = 0; + if (! enif_get_int64(env, argv[3], &i3)) + i3 = 0; + if (! enif_get_int64(env, argv[4], &i4)) + i4 = 0; + get_string_maybe(env, argv[5], &mbuf1, + messagebuf1, sizeof(messagebuf1)-1); + get_string_maybe(env, argv[6], &mbuf2, + messagebuf2, sizeof(messagebuf2)-1); + get_string_maybe(env, argv[7], &mbuf3, + messagebuf3, sizeof(messagebuf3)-1); + get_string_maybe(env, argv[8], &mbuf4, + messagebuf4, sizeof(messagebuf4)-1); + DTRACE10(user_trace_i4s4, procbuf, utbuf, + i1, i2, i3, i4, mbuf1, mbuf2, mbuf3, mbuf4); + return atom_true; + } else { + return atom_false; + } +#else + return atom_error; +#endif +} diff --git a/lib/dtrace/c_src/dtrace_user.d b/lib/dtrace/c_src/dtrace_user.d new file mode 100644 index 0000000000..45d3ef3b66 --- /dev/null +++ b/lib/dtrace/c_src/dtrace_user.d @@ -0,0 +1,53 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. + * All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +provider erlang { + /** + * Send a single string to a probe. + * + * @param NUL-terminated string + */ + probe user_trace__s1(char* message); + + /** + * Multi-purpose probe: up to 4 NUL-terminated strings and 4 + * 64-bit integer arguments. + * + * @param proc, the PID (string form) of the sending process + * @param user_tag, the user tag of the sender + * @param i1, integer + * @param i2, integer + * @param i3, integer + * @param i4, integer + * @param s1, string/iolist. D's arg6 is NULL if not given by Erlang + * @param s2, string/iolist. D's arg7 is NULL if not given by Erlang + * @param s3, string/iolist. D's arg8 is NULL if not given by Erlang + * @param s4, string/iolist. D's arg9 is NULL if not given by Erlang + */ + probe user_trace__i4s4(char *proc, char *user_tag, + int i1, int i2, int i3, int i4, + char *s1, char *s2, char *s3, char *s4); +}; + +#pragma D attributes Evolving/Evolving/Common provider erlang provider +#pragma D attributes Private/Private/Common provider erlang module +#pragma D attributes Private/Private/Common provider erlang function +#pragma D attributes Evolving/Evolving/Common provider erlang name +#pragma D attributes Evolving/Evolving/Common provider erlang args diff --git a/lib/dtrace/ebin/.placeholder b/lib/dtrace/ebin/.placeholder new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/dtrace/src/Makefile b/lib/dtrace/src/Makefile new file mode 100644 index 0000000000..d613402a63 --- /dev/null +++ b/lib/dtrace/src/Makefile @@ -0,0 +1,102 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(DTRACE_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/dtrace-$(VSN) + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +MODULES= \ + dtrace + +HRL_FILES= \ + +INTERNAL_HRL_FILES= \ + +ERL_FILES= $(MODULES:%=%.erl) +EXAMPLE_FILES= \ + ../examples/* + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) + +EXECUTABLES= \ + +APP_FILE= dtrace.app + +APP_SRC= $(APP_FILE).src +APP_TARGET= $(EBIN)/$(APP_FILE) + +APPUP_FILE= dtrace.appup + +APPUP_SRC= $(APPUP_FILE).src +APPUP_TARGET= $(EBIN)/$(APPUP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += \ + -I../include \ + -I ../../et/include \ + -I ../../../libraries/et/include + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + +$(APP_TARGET): $(APP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src + # $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + +release_docs_spec: diff --git a/lib/dtrace/src/dtrace.app.src b/lib/dtrace/src/dtrace.app.src new file mode 100644 index 0000000000..764e863559 --- /dev/null +++ b/lib/dtrace/src/dtrace.app.src @@ -0,0 +1,27 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +{application, dtrace, + [{description, "DTRACE version 1"}, + {vsn, "%VSN%"}, + {modules, [ + dtrace + ]}, + {registered, []}, + {applications, [kernel, stdlib]}, + {env, []}]}. diff --git a/lib/dtrace/src/dtrace.appup.src b/lib/dtrace/src/dtrace.appup.src new file mode 100644 index 0000000000..f730a2f8df --- /dev/null +++ b/lib/dtrace/src/dtrace.appup.src @@ -0,0 +1,19 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +{"%VSN%",[],[]}. diff --git a/lib/dtrace/src/dtrace.erl b/lib/dtrace/src/dtrace.erl new file mode 100644 index 0000000000..45addafc53 --- /dev/null +++ b/lib/dtrace/src/dtrace.erl @@ -0,0 +1,216 @@ +-module(dtrace). + +%%% @doc The DTrace interface module +%%% +%%% This DTrace interface module, with the corresponding NIFs, should +%%% work on any operating system platform where user-space DTrace +%%% probes are supported. +%%% +%%% Use the `dtrace:init()' function to load the NIF shared library and +%%% to initialize library's private state. +%%% +%%% It is recommended that you use the `dtrace:p()' function to add +%%% DTrace probes to your Erlang code. This function can accept up to +%%% four integer arguments and four string arguments; the integer +%%% argument(s) must come before any string argument. For example: +%%% ``` +%%% 1> put(dtrace_utag, "GGOOOAAALL!!!!!"). +%%% undefined +%%% 2> dtrace:init(). +%%% ok +%%% +%%% % % % Enable the DTrace probe using the 'dtrace' command. +%%% +%%% 3> dtrace:p(7, 8, 9, "one", "four"). +%%% true +%%% ''' +%%% +%%% Output from the example D script `user-probe.d' looks like: +%%% ``` +%%% <0.34.0> GGOOOAAALL!!!!! 7 8 9 0 'one' 'four' '' '' +%%% ''' +%%% +%%% If the expected type of variable is not present, e.g. integer when +%%% integer() is expected, or an I/O list when iolist() is expected, +%%% then the driver will ignore the user's input and use a default +%%% value of 0 or NULL, respectively. + +-export([init/0, available/0, + user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 + p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). +-export([scaff/0]). % Development only +-export([user_trace_i4s4/9]). % Know what you're doing! + +-type probe_arg() :: integer() | iolist(). +-type int_p_arg() :: integer() | iolist() | undef. +%% The *_maybe() types use atom() instead of a stricter 'undef' +%% because user_trace_i4s4/9 is exposed to the outside world, and +%% because the driver will allow any atom to be used as a "not +%% present" indication, we'll allow any atom in the types. +-type integer_maybe() :: integer() | atom(). +-type iolist_maybe() :: iolist() | atom(). + +-spec init() -> ok | {error, {term(), term()}}. + +init() -> + PrivDir = code:priv_dir(dtrace), + Lib = filename:join([PrivDir, "lib", "dtrace"]), + erlang:load_nif(Lib, 0). + +%%% +%%% NIF placeholders +%%% + +-spec available() -> true | false. + +available() -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_s1(iolist()) -> true | false | error | badarg. + +user_trace_s1(Message) -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_i4s4(iolist(), + integer_maybe(), integer_maybe(), + integer_maybe(), integer_maybe(), + iolist_maybe(), iolist_maybe(), + iolist_maybe(), iolist_maybe()) -> + true | false | error | badarg. + +user_trace_i4s4(_, _, _, _, _, _, _, _, _) -> + erlang:nif_error(nif_not_loaded). + +%%% +%%% Erlang support functions +%%% + +-spec p() -> true | false | error | badarg. + +p() -> + user_trace_int(undef, undef, undef, undef, undef, undef, undef, undef). + +-spec p(probe_arg()) -> true | false | error | badarg. + +p(I1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, undef, undef, undef, undef); +p(S1) -> + user_trace_int(undef, undef, undef, undef, S1, undef, undef, undef). + +-spec p(probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, undef, undef, undef, undef); +p(I1, S1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, undef, undef, undef); +p(S1, S2) -> + user_trace_int(undef, undef, undef, undef, S1, S2, undef, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, undef, undef, undef, undef); +p(I1, I2, S1) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, undef, undef, undef); +p(I1, S1, S2) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, undef, undef); +p(S1, S2, S3) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, undef, undef, undef, undef); +p(I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, undef, undef, undef); +p(I1, I2, S1, S2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, undef, undef); +p(I1, S1, S2, S3) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, undef); +p(S1, S2, S3, S4) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, undef, undef, undef); +p(I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, undef, undef); +p(I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, undef); +p(I1, S1, S2, S3, S4) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, undef, undef); +p(I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, undef); +p(I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, undef); +p(I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4). + +-spec user_trace_int(int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(), + int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) -> + true | false | error | badarg. + +user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> + UTag = prim_file:get_dtrace_utag(), + user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4). + +%% Scaffolding to write tedious code: quick brute force and not 100% correct. + +scaff_int_args(N) -> + L = lists:sublist(["I1", "I2", "I3", "I4"], N), + [string:join(L, ", ")]. + +scaff_int_guards(N) -> + L = lists:sublist(["is_integer(I1)", "is_integer(I2)", "is_integer(I3)", + "is_integer(I4)"], N), + lists:flatten(string:join(L, ", ")). + +scaff_char_args(N) -> + L = lists:sublist(["S1", "S2", "S3", "S4"], N), + [string:join(L, ", ")]. + +scaff_fill(N) -> + [string:join(lists:duplicate(N, "undef"), ", ")]. + +scaff() -> + L = [begin + IntArgs = scaff_int_args(N_int), + IntGuards = scaff_int_guards(N_int), + IntFill = scaff_fill(4 - N_int), + CharArgs = scaff_char_args(N_char), + CharFill = scaff_fill(4 - N_char), + InArgs = string:join(IntArgs ++ CharArgs, ", "), + OutArgs = string:join(IntArgs ++ IntFill ++ CharArgs ++ CharFill, + ", "), + {N_int + N_char, + lists:flatten([io_lib:format("p(~s) when ~s ->\n", + [InArgs, IntGuards]), + io_lib:format(" user_trace_int(~s);\n", [OutArgs]) + ])} + end || N_int <- [0,1,2,3,4], N_char <- [0,1,2,3,4]], + [io:format("%%~p\n~s", [N, Str]) || {N, Str} <- lists:sort(L)]. diff --git a/lib/dtrace/vsn.mk b/lib/dtrace/vsn.mk new file mode 100644 index 0000000000..73bf983c00 --- /dev/null +++ b/lib/dtrace/vsn.mk @@ -0,0 +1 @@ +DTRACE_VSN = 0.8 -- cgit v1.2.3 From 0331c29e0e494d4c1e4fdd05e48a3f88a8caea0b Mon Sep 17 00:00:00 2001 From: Scott Lystig Fritchie Date: Thu, 17 Nov 2011 00:44:30 -0600 Subject: Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 2/4 Add D scripts in the `lib/dtrace/examples` directory. Add SystemTap README and sample scripts, contributed by Andreas Schultz . --- README.systemtap.md | 72 +++++++++++ lib/dtrace/examples/dist.d | 62 +++++++++ lib/dtrace/examples/dist.systemtap | 76 ++++++++++++ lib/dtrace/examples/driver1.d | 114 +++++++++++++++++ lib/dtrace/examples/driver1.systemtap | 125 +++++++++++++++++++ lib/dtrace/examples/efile_drv.d | 103 +++++++++++++++ lib/dtrace/examples/efile_drv.systemtap | 112 +++++++++++++++++ lib/dtrace/examples/function-calls.d | 51 ++++++++ lib/dtrace/examples/function-calls.systemtap | 61 +++++++++ lib/dtrace/examples/garbage-collection.d | 39 ++++++ lib/dtrace/examples/garbage-collection.systemtap | 49 ++++++++ lib/dtrace/examples/memory1.d | 41 ++++++ lib/dtrace/examples/memory1.systemtap | 51 ++++++++ lib/dtrace/examples/messages.d | 94 ++++++++++++++ lib/dtrace/examples/messages.systemtap | 87 +++++++++++++ lib/dtrace/examples/port1.d | 140 +++++++++++++++++++++ lib/dtrace/examples/port1.systemtap | 152 +++++++++++++++++++++++ lib/dtrace/examples/process-scheduling.d | 35 ++++++ lib/dtrace/examples/process-scheduling.systemtap | 45 +++++++ lib/dtrace/examples/spawn-exit.d | 41 ++++++ lib/dtrace/examples/spawn-exit.systemtap | 51 ++++++++ lib/dtrace/examples/user-probe.d | 36 ++++++ lib/dtrace/examples/user-probe.systemtap | 46 +++++++ 23 files changed, 1683 insertions(+) create mode 100644 README.systemtap.md create mode 100644 lib/dtrace/examples/dist.d create mode 100644 lib/dtrace/examples/dist.systemtap create mode 100644 lib/dtrace/examples/driver1.d create mode 100644 lib/dtrace/examples/driver1.systemtap create mode 100644 lib/dtrace/examples/efile_drv.d create mode 100644 lib/dtrace/examples/efile_drv.systemtap create mode 100644 lib/dtrace/examples/function-calls.d create mode 100644 lib/dtrace/examples/function-calls.systemtap create mode 100644 lib/dtrace/examples/garbage-collection.d create mode 100644 lib/dtrace/examples/garbage-collection.systemtap create mode 100644 lib/dtrace/examples/memory1.d create mode 100644 lib/dtrace/examples/memory1.systemtap create mode 100644 lib/dtrace/examples/messages.d create mode 100644 lib/dtrace/examples/messages.systemtap create mode 100644 lib/dtrace/examples/port1.d create mode 100644 lib/dtrace/examples/port1.systemtap create mode 100644 lib/dtrace/examples/process-scheduling.d create mode 100644 lib/dtrace/examples/process-scheduling.systemtap create mode 100644 lib/dtrace/examples/spawn-exit.d create mode 100644 lib/dtrace/examples/spawn-exit.systemtap create mode 100644 lib/dtrace/examples/user-probe.d create mode 100644 lib/dtrace/examples/user-probe.systemtap diff --git a/README.systemtap.md b/README.systemtap.md new file mode 100644 index 0000000000..3bb3e626cd --- /dev/null +++ b/README.systemtap.md @@ -0,0 +1,72 @@ +SystemTap and Erlang/OTP +======================== + +Introduction +------------ + +SystemTap is DTrace for Linux. In fact Erlang's SystemTap support +is build using SystemTap's DTrace compatibility's layer. For an +introduction to Erlang DTrace support read README.dtrace.md. + +Requisites +---------- + +* Linux Kernel with UTRACE support + + check for UTRACE support in your current kernel: + + # grep CONFIG_UTRACE /boot/config-`uname -r` + CONFIG_UTRACE=y + + Fedora 16 is known to contain UTRACE, for most other Linux distributions + a custom build kernel will be required. + Check Fedora's SystemTap documentation for additional required packages + (e.g. Kernel Debug Symbols) + +* SystemTap > 1.6 + + A the time of writing this, the latest released version of SystemTap is + version 1.6. Erlang's DTrace support requires a MACRO that was introduced + after that release. So either get a newer release or build SystemTap from + git yourself (see: http://sourceware.org/systemtap/getinvolved.html) + +Building Erlang +--------------- + +Configure and build Erlang with SystemTap support: + + # ./configure --enable-dtrace + whatever args you need + # make + +Testing +------- + +SystemTap, unlike DTrace, needs to know what binary it is tracing and has to +be able to read that binary before it starts tracing. Your probe script +therefor has to reference the correct beam emulator and stap needs to be able +to find that binary. +The examples are written for "beam", but other versions such as "beam.smp" or +"beam.debug.smp" might exist (depending on your configuration). Make sure you +either specify the full the path of the binary in the probe or your "beam" +binary is in the search path. + +All available probes can be listed like this: + + # stap -L 'process("beam").mark("*")' + +or: + + # PATH=/path/to/beam:$PATH stap -L 'process("beam").mark("*")' + + +Probes in the dtrace.so NIF library like this: + + # PATH=/path/to/dtrace/priv/lib:$PATH stap -L 'process("dtrace.so").mark("*")' + +Running SystemTap scripts +------------------------- + +Adjust the process("beam") reference to your beam version and attach the script +to a running "beam" instance: + + # stap /path/to/probe/script/port1.systemtap -x diff --git a/lib/dtrace/examples/dist.d b/lib/dtrace/examples/dist.d new file mode 100644 index 0000000000..f37c827f14 --- /dev/null +++ b/lib/dtrace/examples/dist.d @@ -0,0 +1,62 @@ +/* example usage: dtrace -q -s /path/to/dist.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::dist-monitor +{ + printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", + pid, + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3), + copyinstr(arg4)); +} + +erlang*:::dist-port_busy +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); + blocked_procs[copyinstr(arg3)] = timestamp; +} + +erlang*:::dist-port_busy +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); + blocked_procs[copyinstr(arg3)] = timestamp; +} + +erlang*:::dist-output +{ + printf("dist output: node %s, port %s, remote_node %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::dist-outputv +{ + printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::process-scheduled +/blocked_procs[copyinstr(arg0)]/ +{ + pidstr = copyinstr(arg0); + printf("blocked pid %s scheduled now, waited %d microseconds\n", + pidstr, (timestamp - blocked_procs[pidstr]) / 1000); + blocked_procs[pidstr] = 0; +} diff --git a/lib/dtrace/examples/dist.systemtap b/lib/dtrace/examples/dist.systemtap new file mode 100644 index 0000000000..af27b2cab6 --- /dev/null +++ b/lib/dtrace/examples/dist.systemtap @@ -0,0 +1,76 @@ +/* example usage: stap /path/to/dist.systemtap -x */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("dist-monitor") +{ + printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", + pid(), + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4), + user_string($arg5)); +} + +probe process("beam").mark("dist-port_busy") +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); + blocked_procs[user_string($arg4)] = timestamp; +} + +probe process("beam").mark("dist-port_busy") +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); + blocked_procs[user_string($arg4)] = timestamp; +} + +probe process("beam").mark("dist-output") +{ + printf("dist output: node %s, port %s, remote_node %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("dist-outputv") +{ + printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("process-scheduled") +{ + pidstr = user_string($arg1); + if (pidstr in blocked_procs) { + printf("blocked pid %s scheduled now, waited %d microseconds\n", + pidstr, (timestamp - blocked_procs[pidstr]) / 1000); + delete blocked_procs[pidstr]; + } +} + +global blocked_procs; diff --git a/lib/dtrace/examples/driver1.d b/lib/dtrace/examples/driver1.d new file mode 100644 index 0000000000..9f53ffeb2a --- /dev/null +++ b/lib/dtrace/examples/driver1.d @@ -0,0 +1,114 @@ +/* example usage: dtrace -q -s /path/to/driver1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::driver-init +{ + printf("driver init name %s major %d minor %d flags %d\n", + copyinstr(arg0), arg1, arg2, arg3); +} + +erlang*:::driver-start +{ + printf("driver start pid %s driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-stop +{ + printf("driver stop pid %s driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-finish +{ + printf("driver finish driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::driver-flush +{ + printf("driver flush pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-output +{ + printf("driver output pid %s port %s port name %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::driver-outputv +{ + printf("driver outputv pid %s port %s port name %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::driver-control +{ + printf("driver control pid %s port %s port name %s command %d bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, arg4); +} + +erlang*:::driver-call +{ + printf("driver call pid %s port %s port name %s command %d bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, arg4); +} + +erlang*:::driver-event +{ + printf("driver event pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_input +{ + printf("driver ready_input pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_output +{ + printf("driver ready_output pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-timeout +{ + printf("driver timeout pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_async +{ + printf("driver ready_async pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-process_exit +{ + printf("driver process_exit pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-stop_select +{ + printf("driver stop_select driver name %s\n", copyinstr(arg0)); +} diff --git a/lib/dtrace/examples/driver1.systemtap b/lib/dtrace/examples/driver1.systemtap new file mode 100644 index 0000000000..8b99e465b7 --- /dev/null +++ b/lib/dtrace/examples/driver1.systemtap @@ -0,0 +1,125 @@ +/* example usage: stap /path/to/driver1.systemtap -x */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("driver-init") +{ + printf("driver init name %s major %d minor %d flags %d\n", + user_string($arg1), $arg2, $arg3, $arg4); +} + +probe process("beam").mark("driver-start") +{ + printf("driver start pid %s driver name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-stop") +{ + printf("driver stop pid %s driver name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-finish") +{ + printf("driver finish driver name %s\n", + user_string($arg1)); +} + +probe process("beam").mark("driver-flush") +{ + printf("driver flush pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-output") +{ + printf("driver output pid %s port %s port name %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("driver-outputv") +{ + printf("driver outputv pid %s port %s port name %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("driver-control") +{ + printf("driver control pid %s port %s port name %s command %d bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); +} + +probe process("beam").mark("driver-call") +{ + printf("driver call pid %s port %s port name %s command %d bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); +} + +probe process("beam").mark("driver-event") +{ + printf("driver event pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_input") +{ + printf("driver ready_input pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_output") +{ + printf("driver ready_output pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-timeout") +{ + printf("driver timeout pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_async") +{ + printf("driver ready_async pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-process_exit") +{ + printf("driver process_exit pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-stop_select") +{ + printf("driver stop_select driver name %s\n", user_string($arg1)); +} diff --git a/lib/dtrace/examples/efile_drv.d b/lib/dtrace/examples/efile_drv.d new file mode 100644 index 0000000000..c9c8080dba --- /dev/null +++ b/lib/dtrace/examples/efile_drv.d @@ -0,0 +1,103 @@ +/* example usage: dtrace -q -s /path/to/efile_drv.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +BEGIN +{ + op_map[1] = "OPEN"; + op_map[2] = "READ"; + op_map[3] = "LSEEK"; + op_map[4] = "WRITE"; + op_map[5] = "FSTAT"; + op_map[6] = "PWD"; + op_map[7] = "READDIR"; + op_map[8] = "CHDIR"; + op_map[9] = "FSYNC"; + op_map[10] = "MKDIR"; + op_map[11] = "DELETE"; + op_map[12] = "RENAME"; + op_map[13] = "RMDIR"; + op_map[14] = "TRUNCATE"; + op_map[15] = "READ_FILE"; + op_map[16] = "WRITE_INFO"; + op_map[19] = "LSTAT"; + op_map[20] = "READLINK"; + op_map[21] = "LINK"; + op_map[22] = "SYMLINK"; + op_map[23] = "CLOSE"; + op_map[24] = "PWRITEV"; + op_map[25] = "PREADV"; + op_map[26] = "SETOPT"; + op_map[27] = "IPREAD"; + op_map[28] = "ALTNAME"; + op_map[29] = "READ_LINE"; + op_map[30] = "FDATASYNC"; + op_map[31] = "FADVISE"; +} + +erlang*:::aio_pool-add +{ + printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1); +} + +erlang*:::aio_pool-get +{ + printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1); +} + +erlang*:::efile_drv-entry +{ + printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n", + arg0, arg1, + arg2 == NULL ? "" : "user tag ", + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3, + arg4 == NULL ? "" : copyinstr(arg4), + arg5 == NULL ? "" : copyinstr(arg5), arg6, arg7, + /* NOTE: port name in args[10] is experimental */ + copyinstr((user_addr_t) args[10])) +} + +erlang*:::efile_drv-int* +{ + printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n", + arg0, arg1, op_map[arg2], arg2, probename); +} + +/* efile_drv-return error case */ +erlang*:::efile_drv-return +/arg4 == 0/ +{ + printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n", + arg0, arg1, + arg2 == NULL ? "" : "user tag ", + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3, + arg5); +} + +/* efile_drv-return success case */ +erlang*:::efile_drv-return +/arg4 != 0/ +{ + printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n", + arg0, arg1, + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3); +} diff --git a/lib/dtrace/examples/efile_drv.systemtap b/lib/dtrace/examples/efile_drv.systemtap new file mode 100644 index 0000000000..5a47b3e22b --- /dev/null +++ b/lib/dtrace/examples/efile_drv.systemtap @@ -0,0 +1,112 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + op_map[1] = "OPEN"; + op_map[2] = "READ"; + op_map[3] = "LSEEK"; + op_map[4] = "WRITE"; + op_map[5] = "FSTAT"; + op_map[6] = "PWD"; + op_map[7] = "READDIR"; + op_map[8] = "CHDIR"; + op_map[9] = "FSYNC"; + op_map[10] = "MKDIR"; + op_map[11] = "DELETE"; + op_map[12] = "RENAME"; + op_map[13] = "RMDIR"; + op_map[14] = "TRUNCATE"; + op_map[15] = "READ_FILE"; + op_map[16] = "WRITE_INFO"; + op_map[19] = "LSTAT"; + op_map[20] = "READLINK"; + op_map[21] = "LINK"; + op_map[22] = "SYMLINK"; + op_map[23] = "CLOSE"; + op_map[24] = "PWRITEV"; + op_map[25] = "PREADV"; + op_map[26] = "SETOPT"; + op_map[27] = "IPREAD"; + op_map[28] = "ALTNAME"; + op_map[29] = "READ_LINE"; + op_map[30] = "FDATASYNC"; + op_map[31] = "FADVISE"; +} + +probe process("beam").mark("aio_pool-add") +{ + printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("aio_pool-get") +{ + printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("efile_drv-entry") +{ + printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n", + $arg1, $arg2, + $arg3 == NULL ? "" : "user tag ", + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4, + $arg5 == NULL ? "" : user_string($arg5), + $arg6 == NULL ? "" : user_string($arg6), $arg7, $arg8, + /* NOTE: port name in $arg[11] is experimental */ + user_string($arg11)) +} + +probe process("beam").mark("efile_drv-int*") +{ + printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n", + $arg1, $arg2, op_map[$arg3], $arg3, probefunc()); +} + +probe process("beam").mark("efile_drv-return") +{ + if ($arg5 == 0) { + /* efile_drv-return error case */ + printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n", + $arg1, $arg2, + $arg3 == NULL ? "" : "user tag ", + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4, + $arg6); + } else { + /* efile_drv-return success case */ + printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n", + $arg1, $arg2, + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4); + } +} + +global op_map; diff --git a/lib/dtrace/examples/function-calls.d b/lib/dtrace/examples/function-calls.d new file mode 100644 index 0000000000..238c5211ac --- /dev/null +++ b/lib/dtrace/examples/function-calls.d @@ -0,0 +1,51 @@ +/* example usage: dtrace -q -s /path/to/function-calls.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::function-entry +{ + printf("pid %s enter %s depth %d\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::function-return +{ + printf("pid %s return %s depth %d\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::bif-entry +{ + printf("pid %s BIF entry mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::bif-return +{ + printf("pid %s BIF return mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::nif-entry +{ + printf("pid %s NIF entry mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::nif-return +{ + printf("pid %s NIF return mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} diff --git a/lib/dtrace/examples/function-calls.systemtap b/lib/dtrace/examples/function-calls.systemtap new file mode 100644 index 0000000000..8fc4375135 --- /dev/null +++ b/lib/dtrace/examples/function-calls.systemtap @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("function-entry") +{ + printf("pid %s enter %s depth %d\n", + user_string($arg1), user_string($arg2), $arg3); +} + +probe process("beam").mark("function-return") +{ + printf("pid %s return %s depth %d\n", + user_string($arg1), user_string($arg2), $arg3); +} + +probe process("beam").mark("bif-entry") +{ + printf("pid %s BIF entry mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("bif-return") +{ + printf("pid %s BIF return mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("nif-entry") +{ + printf("pid %s NIF entry mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("nif-return") +{ + printf("pid %s NIF return mfa %s\n", user_string($arg1), user_string($arg2)); +} diff --git a/lib/dtrace/examples/garbage-collection.d b/lib/dtrace/examples/garbage-collection.d new file mode 100644 index 0000000000..f234e7d4db --- /dev/null +++ b/lib/dtrace/examples/garbage-collection.d @@ -0,0 +1,39 @@ +/* example usage: dtrace -q -s /path/to/garbage-collection.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::gc_major-start +{ + printf("GC major start pid %s need %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_minor-start +{ + printf("GC minor start pid %s need %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_major-end +{ + printf("GC major end pid %s reclaimed %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_minor-start +{ + printf("GC minor end pid %s reclaimed %d words\n", copyinstr(arg0), arg1); +} diff --git a/lib/dtrace/examples/garbage-collection.systemtap b/lib/dtrace/examples/garbage-collection.systemtap new file mode 100644 index 0000000000..64d69c6fbd --- /dev/null +++ b/lib/dtrace/examples/garbage-collection.systemtap @@ -0,0 +1,49 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("gc_major-start") +{ + printf("GC major start pid %s need %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_minor-start") +{ + printf("GC minor start pid %s need %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_major-end") +{ + printf("GC major end pid %s reclaimed %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_minor-start") +{ + printf("GC minor end pid %s reclaimed %d words\n", user_string($arg1), $arg2); +} diff --git a/lib/dtrace/examples/memory1.d b/lib/dtrace/examples/memory1.d new file mode 100644 index 0000000000..c2e16e0779 --- /dev/null +++ b/lib/dtrace/examples/memory1.d @@ -0,0 +1,41 @@ +/* example usage: dtrace -q -s /path/to/memory1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::copy-struct +{ + printf("copy_struct %d bytes\n", arg0); +} + +erlang*:::copy-object +{ + printf("copy_object pid %s %d bytes\n", copyinstr(arg0), arg1); +} + +erlang*:::process-heap_grow +{ + printf("proc heap grow pid %s %d -> %d bytes\n", copyinstr(arg0), + arg1, arg2); +} + +erlang*:::process-heap_shrink +{ + printf("proc heap shrink pid %s %d -> %d bytes\n", copyinstr(arg0), + arg1, arg2); +} diff --git a/lib/dtrace/examples/memory1.systemtap b/lib/dtrace/examples/memory1.systemtap new file mode 100644 index 0000000000..9723f2d02d --- /dev/null +++ b/lib/dtrace/examples/memory1.systemtap @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("copy-struct") +{ + printf("copy_struct %d bytes\n", $arg1); +} + +probe process("beam").mark("copy-object") +{ + printf("copy_object pid %s %d bytes\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("process-heap_grow") +{ + printf("proc heap grow pid %s %d -> %d bytes\n", user_string($arg1), + $arg2, $arg3); +} + +probe process("beam").mark("process-heap_shrink") +{ + printf("proc heap shrink pid %s %d -> %d bytes\n", user_string($arg1), + $arg2, $arg3); +} diff --git a/lib/dtrace/examples/messages.d b/lib/dtrace/examples/messages.d new file mode 100644 index 0000000000..6361f3a220 --- /dev/null +++ b/lib/dtrace/examples/messages.d @@ -0,0 +1,94 @@ +/* example usage: dtrace -q -s /path/to/messages.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +BEGIN +{ + printf("\n"); + printf("NOTE: message-queue message size 4294967295 means an external\n"); + printf(" message that the code isn't smart enough to determine\n"); + printf(" the actual size.\n"); + printf("\n"); +} + +erlang*:::message-send +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("send: %s -> %s: %d words\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::message-send +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("send: %s label %d token {%d,%d} -> %s: %d words\n", + copyinstr(arg0), + arg3, arg4, arg5, + copyinstr(arg1), arg2); +} + +/* + * TODO: + * Weird, on my OS X box, beam says arg6 = 0 but this script says 4294967296. + */ + +erlang*:::message-send-remote +/arg4 == 0 && arg5 == 0 && (arg6 == 0 || arg6 >= 4294967296)/ +{ + printf("send : %s -> %s %s: %d words\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::message-send-remote +/arg4 != 0 || arg5 != 0 || arg6 < 4294967296/ +{ + printf("send : %s label %d token {%d,%d} -> %s %s: %d words\n", + copyinstr(arg0), + arg4, arg5, arg6, + copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::message-queued +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("queued: %s: %d words, queue len %d\n", copyinstr(arg0), arg1, arg2); +} + +erlang*:::message-queued +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("queued: %s label %d token {%d,%d}: %d words, queue len %d\n", + copyinstr(arg0), arg3, arg4, arg5, + arg1, arg2); +} + +erlang*:::message-receive +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("receive: %s: %d words, queue len %d\n", + copyinstr(arg0), arg1, arg2); +} + +erlang*:::message-receive +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("receive: %s label %d token {%d,%d}: %d words, queue len %d\n", + copyinstr(arg0), arg3, arg4, arg5, + arg1, arg2); +} diff --git a/lib/dtrace/examples/messages.systemtap b/lib/dtrace/examples/messages.systemtap new file mode 100644 index 0000000000..ff8f4076b1 --- /dev/null +++ b/lib/dtrace/examples/messages.systemtap @@ -0,0 +1,87 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + printf("\n"); + printf("NOTE: message-queue message size 4294967295 means an external\n"); + printf(" message that the code isn't smart enough to determine\n"); + printf(" the actual size.\n"); + printf("\n"); +} + +probe process("beam").mark("message-send") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("send: %s -> %s: %d words\n", + user_string($arg1), user_string($arg2), $arg3); + } else { + printf("send: %s label %d token {%d,%d} -> %s: %d words\n", + user_string($arg1), + $arg4, $arg5, $arg6, + user_string($arg2), $arg3); + } +} + +probe process("beam").mark("message-send-remote") +{ + if ($arg5 == 0 && $arg6 == 0 && $arg7 == 0) { + printf("send : %s -> %s %s: %d words\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); + } else { + printf("send : %s label %d token {%d,%d} -> %s %s: %d words\n", + user_string($arg1), + $arg5, $arg6, $arg7, + user_string($arg2), user_string($arg3), $arg4); + } +} + +probe process("beam").mark("message-queued") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("queued: %s: %d words, queue len %d\n", user_string($arg1), $arg2, $arg3); + } else { + printf("queued: %s label %d token {%d,%d}: %d words, queue len %d\n", + user_string($arg1), $arg4, $arg5, $arg6, + $arg2, $arg3); + } +} + +probe process("beam").mark("message-receive") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("receive: %s: %d words, queue len %d\n", + user_string($arg1), $arg2, $arg3); + } else { + printf("receive: %s label %d token {%d,%d}: %d words, queue len %d\n", + user_string($arg1), $arg4, $arg5, $arg6, + $arg2, $arg3); + } +} diff --git a/lib/dtrace/examples/port1.d b/lib/dtrace/examples/port1.d new file mode 100644 index 0000000000..b82e783a14 --- /dev/null +++ b/lib/dtrace/examples/port1.d @@ -0,0 +1,140 @@ +/* example usage: dtrace -q -s /path/to/port1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +BEGIN +{ + driver_map["tcp_inet", 1] = "OPEN"; + driver_map["tcp_inet", 2] = "CLOSE"; + driver_map["tcp_inet", 3] = "CONNECT"; + driver_map["tcp_inet", 4] = "PEER"; + driver_map["tcp_inet", 5] = "NAME"; + driver_map["tcp_inet", 6] = "BIND"; + driver_map["tcp_inet", 7] = "SETOPTS"; + driver_map["tcp_inet", 8] = "GETOPTS"; + driver_map["tcp_inet", 11] = "GETSTAT"; + driver_map["tcp_inet", 12] = "GETHOSTNAME"; + driver_map["tcp_inet", 13] = "FDOPEN"; + driver_map["tcp_inet", 14] = "GETFD"; + driver_map["tcp_inet", 15] = "GETTYPE"; + driver_map["tcp_inet", 16] = "GETSTATUS"; + driver_map["tcp_inet", 17] = "GETSERVBYNAME"; + driver_map["tcp_inet", 18] = "GETSERVBYPORT"; + driver_map["tcp_inet", 19] = "SETNAME"; + driver_map["tcp_inet", 20] = "SETPEER"; + driver_map["tcp_inet", 21] = "GETIFLIST"; + driver_map["tcp_inet", 22] = "IFGET"; + driver_map["tcp_inet", 23] = "IFSET"; + driver_map["tcp_inet", 24] = "SUBSCRIBE"; + driver_map["tcp_inet", 25] = "GETIFADDRS"; + driver_map["tcp_inet", 40] = "ACCEPT"; + driver_map["tcp_inet", 41] = "LISTEN"; + driver_map["tcp_inet", 42] = "RECV"; + driver_map["tcp_inet", 43] = "UNRECV"; + driver_map["tcp_inet", 44] = "SHUTDOWN"; + driver_map["tcp_inet", 60] = "RECV"; + driver_map["tcp_inet", 61] = "LISTEN"; + driver_map["tcp_inet", 62] = "BINDX"; + /* No looping constructs, so repeat for udp_inet */ + driver_map["udp_inet", 1] = "OPEN"; + driver_map["udp_inet", 2] = "CLOSE"; + driver_map["udp_inet", 3] = "CONNECT"; + driver_map["udp_inet", 4] = "PEER"; + driver_map["udp_inet", 5] = "NAME"; + driver_map["udp_inet", 6] = "BIND"; + driver_map["udp_inet", 7] = "SETOPTS"; + driver_map["udp_inet", 8] = "GETOPTS"; + driver_map["udp_inet", 11] = "GETSTAT"; + driver_map["udp_inet", 12] = "GETHOSTNAME"; + driver_map["udp_inet", 13] = "FDOPEN"; + driver_map["udp_inet", 14] = "GETFD"; + driver_map["udp_inet", 15] = "GETTYPE"; + driver_map["udp_inet", 16] = "GETSTATUS"; + driver_map["udp_inet", 17] = "GETSERVBYNAME"; + driver_map["udp_inet", 18] = "GETSERVBYPORT"; + driver_map["udp_inet", 19] = "SETNAME"; + driver_map["udp_inet", 20] = "SETPEER"; + driver_map["udp_inet", 21] = "GETIFLIST"; + driver_map["udp_inet", 22] = "IFGET"; + driver_map["udp_inet", 23] = "IFSET"; + driver_map["udp_inet", 24] = "SUBSCRIBE"; + driver_map["udp_inet", 25] = "GETIFADDRS"; + driver_map["udp_inet", 40] = "ACCEPT"; + driver_map["udp_inet", 41] = "LISTEN"; + driver_map["udp_inet", 42] = "RECV"; + driver_map["udp_inet", 43] = "UNRECV"; + driver_map["udp_inet", 44] = "SHUTDOWN"; + driver_map["udp_inet", 60] = "RECV"; + driver_map["udp_inet", 61] = "LISTEN"; + driver_map["udp_inet", 62] = "BINDX"; +} + +erlang*:::port-open +{ + printf("port open pid %s port name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::port-command +{ + printf("port command pid %s port %s port name %s command type %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-control +{ + cmd = driver_map[copyinstr(arg2), arg3]; + cmd_str = (cmd == 0) ? "unknown" : cmd; + printf("port control pid %s port %s port name %s command %d %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, cmd_str); +} + +/* port-exit is fired as a result of port_close() or exit signal */ + +erlang*:::port-exit +{ + printf("port exit pid %s port %s port name %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-connect +{ + printf("port connect pid %s port %s port name %s new pid %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-busy +{ + printf("port busy %s\n", copyinstr(arg0)); +} + +erlang*:::port-not_busy +{ + printf("port not busy %s\n", copyinstr(arg0)); +} + +erlang*:::aio_pool-add +{ + printf("async I/O pool add thread %d queue len %d\n", arg0, arg1); +} + +erlang*:::aio_pool-get +{ + printf("async I/O pool get thread %d queue len %d\n", arg0, arg1); +} diff --git a/lib/dtrace/examples/port1.systemtap b/lib/dtrace/examples/port1.systemtap new file mode 100644 index 0000000000..a63d9b670c --- /dev/null +++ b/lib/dtrace/examples/port1.systemtap @@ -0,0 +1,152 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + driver_map["tcp_inet", 1] = "OPEN"; + driver_map["tcp_inet", 2] = "CLOSE"; + driver_map["tcp_inet", 3] = "CONNECT"; + driver_map["tcp_inet", 4] = "PEER"; + driver_map["tcp_inet", 5] = "NAME"; + driver_map["tcp_inet", 6] = "BIND"; + driver_map["tcp_inet", 7] = "SETOPTS"; + driver_map["tcp_inet", 8] = "GETOPTS"; + driver_map["tcp_inet", 11] = "GETSTAT"; + driver_map["tcp_inet", 12] = "GETHOSTNAME"; + driver_map["tcp_inet", 13] = "FDOPEN"; + driver_map["tcp_inet", 14] = "GETFD"; + driver_map["tcp_inet", 15] = "GETTYPE"; + driver_map["tcp_inet", 16] = "GETSTATUS"; + driver_map["tcp_inet", 17] = "GETSERVBYNAME"; + driver_map["tcp_inet", 18] = "GETSERVBYPORT"; + driver_map["tcp_inet", 19] = "SETNAME"; + driver_map["tcp_inet", 20] = "SETPEER"; + driver_map["tcp_inet", 21] = "GETIFLIST"; + driver_map["tcp_inet", 22] = "IFGET"; + driver_map["tcp_inet", 23] = "IFSET"; + driver_map["tcp_inet", 24] = "SUBSCRIBE"; + driver_map["tcp_inet", 25] = "GETIFADDRS"; + driver_map["tcp_inet", 40] = "ACCEPT"; + driver_map["tcp_inet", 41] = "LISTEN"; + driver_map["tcp_inet", 42] = "RECV"; + driver_map["tcp_inet", 43] = "UNRECV"; + driver_map["tcp_inet", 44] = "SHUTDOWN"; + driver_map["tcp_inet", 60] = "RECV"; + driver_map["tcp_inet", 61] = "LISTEN"; + driver_map["tcp_inet", 62] = "BINDX"; + /* No looping constructs, so repeat for udp_inet */ + driver_map["udp_inet", 1] = "OPEN"; + driver_map["udp_inet", 2] = "CLOSE"; + driver_map["udp_inet", 3] = "CONNECT"; + driver_map["udp_inet", 4] = "PEER"; + driver_map["udp_inet", 5] = "NAME"; + driver_map["udp_inet", 6] = "BIND"; + driver_map["udp_inet", 7] = "SETOPTS"; + driver_map["udp_inet", 8] = "GETOPTS"; + driver_map["udp_inet", 11] = "GETSTAT"; + driver_map["udp_inet", 12] = "GETHOSTNAME"; + driver_map["udp_inet", 13] = "FDOPEN"; + driver_map["udp_inet", 14] = "GETFD"; + driver_map["udp_inet", 15] = "GETTYPE"; + driver_map["udp_inet", 16] = "GETSTATUS"; + driver_map["udp_inet", 17] = "GETSERVBYNAME"; + driver_map["udp_inet", 18] = "GETSERVBYPORT"; + driver_map["udp_inet", 19] = "SETNAME"; + driver_map["udp_inet", 20] = "SETPEER"; + driver_map["udp_inet", 21] = "GETIFLIST"; + driver_map["udp_inet", 22] = "IFGET"; + driver_map["udp_inet", 23] = "IFSET"; + driver_map["udp_inet", 24] = "SUBSCRIBE"; + driver_map["udp_inet", 25] = "GETIFADDRS"; + driver_map["udp_inet", 40] = "ACCEPT"; + driver_map["udp_inet", 41] = "LISTEN"; + driver_map["udp_inet", 42] = "RECV"; + driver_map["udp_inet", 43] = "UNRECV"; + driver_map["udp_inet", 44] = "SHUTDOWN"; + driver_map["udp_inet", 60] = "RECV"; + driver_map["udp_inet", 61] = "LISTEN"; + driver_map["udp_inet", 62] = "BINDX"; +} + +probe process("beam").mark("port-open") +{ + printf("port open pid %s port name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("port-command") +{ + printf("port command pid %s port %s port name %s command type %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-control") +{ + cmd = driver_map[user_string($arg3), $arg4]; + cmd_str = (cmd == "") ? "unknown" : cmd; + printf("port control pid %s port %s port name %s command %d %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, cmd_str); +} + +/* port-exit is fired as a result of port_close() or exit signal */ + +probe process("beam").mark("port-exit") +{ + printf("port exit pid %s port %s port name %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-connect") +{ + printf("port connect pid %s port %s port name %s new pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-busy") +{ + printf("port busy %s\n", user_string($arg1)); +} + +probe process("beam").mark("port-not_busy") +{ + printf("port not busy %s\n", user_string($arg1)); +} + +probe process("beam").mark("aio_pool-add") +{ + printf("async I/O pool add thread %d queue len %d\n", $arg1, $arg2); +} + +probe process("beam").mark("aio_pool-get") +{ + printf("async I/O pool get thread %d queue len %d\n", $arg1, $arg2); +} + +global driver_map; \ No newline at end of file diff --git a/lib/dtrace/examples/process-scheduling.d b/lib/dtrace/examples/process-scheduling.d new file mode 100644 index 0000000000..9e31da2774 --- /dev/null +++ b/lib/dtrace/examples/process-scheduling.d @@ -0,0 +1,35 @@ +/* example usage: dtrace -q -s /path/to/process-scheduling.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::process-scheduled +{ + printf(" Schedule pid %s mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-unscheduled +{ + printf("Unschedule pid %s\n", copyinstr(arg0)); +} + +erlang*:::process-hibernate +{ + printf(" Hibernate pid %s resume mfa %s\n", + copyinstr(arg0), copyinstr(arg1)); +} diff --git a/lib/dtrace/examples/process-scheduling.systemtap b/lib/dtrace/examples/process-scheduling.systemtap new file mode 100644 index 0000000000..c8cee60a07 --- /dev/null +++ b/lib/dtrace/examples/process-scheduling.systemtap @@ -0,0 +1,45 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("process-scheduled") +{ + printf(" Schedule pid %s mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-unscheduled") +{ + printf("Unschedule pid %s\n", user_string($arg1)); +} + +probe process("beam").mark("process-hibernate") +{ + printf(" Hibernate pid %s resume mfa %s\n", + user_string($arg1), user_string($arg2)); +} diff --git a/lib/dtrace/examples/spawn-exit.d b/lib/dtrace/examples/spawn-exit.d new file mode 100644 index 0000000000..7310f3343d --- /dev/null +++ b/lib/dtrace/examples/spawn-exit.d @@ -0,0 +1,41 @@ +/* example usage: dtrace -q -s /path/to/spawn-exit.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::process-spawn +{ + printf("pid %s mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-exit +{ + printf("pid %s reason %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-exit_signal +{ + printf("sender %s -> pid %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::process-exit_signal-remote +{ + printf("sender %s -> node %s pid %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} diff --git a/lib/dtrace/examples/spawn-exit.systemtap b/lib/dtrace/examples/spawn-exit.systemtap new file mode 100644 index 0000000000..5e3be9fc1b --- /dev/null +++ b/lib/dtrace/examples/spawn-exit.systemtap @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("process-spawn") +{ + printf("pid %s mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-exit") +{ + printf("pid %s reason %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-exit_signal") +{ + printf("sender %s -> pid %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("process-exit_signal-remote") +{ + printf("sender %s -> node %s pid %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} diff --git a/lib/dtrace/examples/user-probe.d b/lib/dtrace/examples/user-probe.d new file mode 100644 index 0000000000..13baff6a32 --- /dev/null +++ b/lib/dtrace/examples/user-probe.d @@ -0,0 +1,36 @@ +/* example usage: dtrace -q -s /path/to/user-probe.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::user_trace-s1 +{ + printf("%s\n", copyinstr(arg0)); +} + +erlang*:::user_trace-i4s4 +{ + printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", + copyinstr(arg0), + arg1 == NULL ? "" : copyinstr(arg1), + arg2, arg3, arg4, arg5, + arg6 == NULL ? "" : copyinstr(arg6), + arg7 == NULL ? "" : copyinstr(arg7), + arg8 == NULL ? "" : copyinstr(arg8), + arg9 == NULL ? "" : copyinstr(arg9)); +} diff --git a/lib/dtrace/examples/user-probe.systemtap b/lib/dtrace/examples/user-probe.systemtap new file mode 100644 index 0000000000..c80bf94697 --- /dev/null +++ b/lib/dtrace/examples/user-probe.systemtap @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("dtrace.so").mark("user_trace-s1") +{ + printf("%s\n", user_string($arg1)); +} + +probe process("dtrace.so").mark("user_trace-i4s4") +{ + printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", + user_string($arg1), + $arg2 == NULL ? "" : user_string($arg2), + $arg3, $arg4, $arg5, $arg6, + $arg7 == NULL ? "" : user_string($arg7), + $arg8 == NULL ? "" : user_string($arg8), + $arg9 == NULL ? "" : user_string($arg9), + $arg9 == NULL ? "" : user_string($arg9)); +} -- cgit v1.2.3 From 2f532f889a6bd31f74122bd223277d7c609f7bdc Mon Sep 17 00:00:00 2001 From: Scott Lystig Fritchie Date: Thu, 17 Nov 2011 00:45:50 -0600 Subject: Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 3/4 Add probes to the virtual machine, except (mostly) the efile_drv.c driver and other file I/O-related source files. --- erts/emulator/beam/beam_emu.c | 228 +++++++++- erts/emulator/beam/copy.c | 9 + erts/emulator/beam/dist.c | 129 ++++++ erts/emulator/beam/erl_async.c | 26 ++ erts/emulator/beam/erl_bif_ddll.c | 2 + erts/emulator/beam/erl_bif_info.c | 3 + erts/emulator/beam/erl_bif_port.c | 27 ++ erts/emulator/beam/erl_gc.c | 46 +- erts/emulator/beam/erl_lock_check.c | 3 + erts/emulator/beam/erl_message.c | 74 +++- erts/emulator/beam/erl_nif.c | 6 + erts/emulator/beam/erl_node_tables.c | 9 + erts/emulator/beam/erl_node_tables.h | 2 +- erts/emulator/beam/erl_port_task.c | 18 +- erts/emulator/beam/erl_process.c | 38 +- erts/emulator/beam/erlang_dtrace.d | 716 ++++++++++++++++++++++++++++++++ erts/emulator/beam/io.c | 118 ++++++ erts/emulator/sys/common/erl_check_io.c | 8 + erts/lib_src/common/erl_printf.c | 4 +- 19 files changed, 1459 insertions(+), 7 deletions(-) create mode 100644 erts/emulator/beam/erlang_dtrace.d diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index c65b2be106..d0beccfda2 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -42,6 +42,9 @@ #include "hipe_bif1.h" #endif +#include +#include "dtrace-wrapper.h" + /* #define HARDDEBUG 1 */ #if defined(NO_JUMP_TABLE) @@ -1050,6 +1053,143 @@ init_emulator(void) # define REG_tmp_arg2 #endif +ERTS_INLINE void +dtrace_proc_str(Process *process, char *process_buf) +{ + dtrace_pid_str(process->id, process_buf); +} + +ERTS_INLINE void +dtrace_pid_str(Eterm pid, char *process_buf) +{ + snprintf(process_buf, DTRACE_TERM_BUF_SIZE, "<%lu.%lu.%lu>", + pid_channel_no(pid), + pid_number(pid), + pid_serial(pid)); +} + +ERTS_INLINE void +dtrace_port_str(Port *port, char *port_buf) +{ + snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>", + port_channel_no(port->id), + port_number(port->id)); +} + +ERTS_INLINE void +dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) +{ + Port *port = erts_drvport2port(drvport); + + snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>", + port_channel_no(port->id), + port_number(port->id)); +} + +ERTS_INLINE void +dtrace_fun_decode(Process *process, + Eterm module, Eterm function, int arity, + char *process_buf, char *mfa_buf) +{ + char funbuf[DTRACE_TERM_BUF_SIZE]; + char *funptr = funbuf; + char *p = NULL; + + if (process_buf) { + dtrace_proc_str(process, process_buf); + } + + erts_snprintf(funbuf, sizeof(funbuf), "%T", function); + /* + * I'm not quite sure how these function names are synthesized, + * but they almost always seem to be in the form of + * '-name/arity-fun-0-' so I'm chopping them up when it's -fun-0- + * (which seems to be the toplevel) + */ + if (funbuf[0] == '\'' && funbuf[1] == '-' + && strlen(funbuf) > 3 && funbuf[strlen(funbuf) - 3] == '0') { + p = strchr(funbuf, '/'); + if (p) { + *p = 0; + } + funptr += 2; + } + + erts_snprintf(mfa_buf, DTRACE_TERM_BUF_SIZE, "%T:%s/%d", + module, funptr, arity); +} + +#ifdef HAVE_DTRACE + +#define DTRACE_CALL(p, m, f, a) \ + if (DTRACE_ENABLED(function_entry)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ + int depth = (STACK_START(p) - STACK_TOP(p)) \ + / sizeof(Eterm*); \ + dtrace_fun_decode(p, m, f, a, \ + process_name, mfa); \ + DTRACE3(function_entry, process_name, mfa, depth); \ + } + +#define DTRACE_RETURN(p, m, f, a) \ + if (DTRACE_ENABLED(function_return)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ + int depth = (STACK_START(p) - STACK_TOP(p)) \ + / sizeof(Eterm*); \ + dtrace_fun_decode(p, m, f, a, \ + process_name, mfa); \ + DTRACE3(function_return, process_name, mfa, depth); \ + } + +#define DTRACE_BIF_ENTRY(p, m, f, a) \ + if (DTRACE_ENABLED(bif_entry)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ + dtrace_fun_decode(p, m, f, a, \ + process_name, mfa); \ + DTRACE2(bif_entry, process_name, mfa); \ + } + +#define DTRACE_BIF_RETURN(p, m, f, a) \ + if (DTRACE_ENABLED(bif_return)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ + dtrace_fun_decode(p, m, f, a, \ + process_name, mfa); \ + DTRACE2(bif_return, process_name, mfa); \ + } + +#define DTRACE_NIF_ENTRY(p, m, f, a) \ + if (DTRACE_ENABLED(nif_entry)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ + dtrace_fun_decode(p, m, f, a, \ + process_name, mfa); \ + DTRACE2(nif_entry, process_name, mfa); \ + } + +#define DTRACE_NIF_RETURN(p, m, f, a) \ + if (DTRACE_ENABLED(nif_return)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ + dtrace_fun_decode(p, m, f, a, \ + process_name, mfa); \ + DTRACE2(nif_return, process_name, mfa); \ + } + +#else /* HAVE_DTRACE */ + +#define DTRACE_CALL(p, m, f, a) do {} while (0) +#define DTRACE_RETURN(p, m, f, a) do {} while (0) +#define DTRACE_BIF_ENTRY(p, m, f, a) do {} while (0) +#define DTRACE_BIF_RETURN(p, m, f, a) do {} while (0) +#define DTRACE_NIF_ENTRY(p, m, f, a) do {} while (0) +#define DTRACE_NIF_RETURN(p, m, f, a) do {} while (0) + +#endif /* HAVE_DTRACE */ + /* * process_main() is called twice: * The first call performs some initialisation, including exporting @@ -1221,6 +1361,28 @@ void process_main(void) #endif SWAPIN; ASSERT(VALID_INSTR(next)); + + if (DTRACE_ENABLED(process_scheduled)) { + DTRACE_CHARBUF(process_buf, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(fun_buf, DTRACE_TERM_BUF_SIZE); + dtrace_proc_str(c_p, process_buf); + + if (ERTS_PROC_IS_EXITING(c_p)) { + strcpy(fun_buf, ""); + } else { + BeamInstr *fptr = find_function_from_pc(c_p->i); + if (fptr) { + dtrace_fun_decode(c_p, (Eterm)fptr[0], + (Eterm)fptr[1], (Uint)fptr[2], + NULL, fun_buf); + } else { + snprintf(fun_buf, sizeof(fun_buf), "", next); + } + } + + DTRACE2(process_scheduled, process_buf, fun_buf); + } + Goto(next); } @@ -1486,7 +1648,13 @@ void process_main(void) OpCase(return): { + BeamInstr* fptr; SET_I(c_p->cp); + + if (DTRACE_ENABLED(function_return) && (fptr = find_function_from_pc(c_p->cp))) { + DTRACE_RETURN(c_p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); + } + /* * We must clear the CP to make sure that a stale value do not * create a false module dependcy preventing code upgrading. @@ -1755,6 +1923,7 @@ void process_main(void) * remove it... */ ASSERT(!msgp->data.attached); + /* TODO: Add DTrace probe for this bad message situation? */ UNLINK_MESSAGE(c_p, msgp); free_message(msgp); goto loop_rec__; @@ -1798,6 +1967,22 @@ void process_main(void) seq_trace_output(SEQ_TRACE_TOKEN(c_p), msg, SEQ_TRACE_RECEIVE, c_p->id, c_p); } + if (DTRACE_ENABLED(message_receive)) { + Eterm token2 = NIL; + DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); + Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + + dtrace_proc_str(c_p, receiver_name); + token2 = SEQ_TRACE_TOKEN(c_p); + if (token2 != NIL) { + tok_label = signed_val(SEQ_TRACE_T_LABEL(token2)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token2)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token2)); + } + DTRACE6(message_receive, + receiver_name, size_object(ERL_MESSAGE_TERM(msgp)), + c_p->msg.len - 1, tok_label, tok_lastcnt, tok_serial); + } UNLINK_MESSAGE(c_p, msgp); JOIN_MESSAGE(c_p); CANCEL_TIMER(c_p); @@ -3157,6 +3342,8 @@ void process_main(void) */ BifFunction vbf; + DTRACE_NIF_ENTRY(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]); + c_p->current = I-3; /* current and vbf set to please handle_error */ SWAPOUT; c_p->fcalls = FCALLS - 1; @@ -3178,6 +3365,9 @@ void process_main(void) ASSERT(!ERTS_PROC_IS_EXITING(c_p) || is_non_value(nif_bif_result)); PROCESS_MAIN_CHK_LOCKS(c_p); ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); + + DTRACE_NIF_RETURN(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]); + goto apply_bif_or_nif_epilogue; OpCase(apply_bif): @@ -3197,6 +3387,8 @@ void process_main(void) c_p->arity = 0; /* To allow garbage collection on ourselves * (check_process_code/2). */ + DTRACE_BIF_ENTRY(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]); + SWAPOUT; c_p->fcalls = FCALLS - 1; vbf = (BifFunction) Arg(0); @@ -3216,6 +3408,8 @@ void process_main(void) PROCESS_MAIN_CHK_LOCKS(c_p); } + DTRACE_BIF_RETURN(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]); + apply_bif_or_nif_epilogue: ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p); ERTS_HOLE_CHECK(c_p); @@ -5899,6 +6093,13 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) save_calls(p, ep); } + if (DTRACE_ENABLED(function_entry) && ep->address) { + BeamInstr *fptr = find_function_from_pc(ep->address); + if (fptr) { + DTRACE_CALL(p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); + } + } + return ep->address; } @@ -5948,6 +6149,13 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) save_calls(p, ep); } + if (DTRACE_ENABLED(function_entry)) { + BeamInstr *fptr = find_function_from_pc(ep->address); + if (fptr) { + DTRACE_CALL(p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); + } + } + return ep->address; } @@ -5997,6 +6205,14 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re c_p->max_arg_reg = sizeof(c_p->def_arg_reg)/sizeof(c_p->def_arg_reg[0]); } + if (DTRACE_ENABLED(process_hibernate)) { + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); + dtrace_fun_decode(c_p, module, function, arity, + process_name, mfa); + DTRACE2(process_hibernate, process_name, mfa); + } + /* * Arrange for the process to be resumed at the given MFA with * the stack cleared. @@ -6071,6 +6287,14 @@ call_fun(Process* p, /* Current process. */ code_ptr = fe->address; actual_arity = (int) code_ptr[-1]; + if (DTRACE_ENABLED(function_entry)) { + BeamInstr *fptr = find_function_from_pc(code_ptr); + + if (fptr) { + DTRACE_CALL(p, fe->module, (Eterm)fptr[1], actual_arity); + } + } + if (actual_arity == arity+num_free) { if (num_free == 0) { return code_ptr; @@ -6089,7 +6313,7 @@ call_fun(Process* p, /* Current process. */ } else { /* * Something wrong here. First build a list of the arguments. - */ + */ if (is_non_value(args)) { Uint sz = 2 * arity; @@ -6164,6 +6388,7 @@ call_fun(Process* p, /* Current process. */ actual_arity = (int) ep->code[2]; if (arity == actual_arity) { + DTRACE_CALL(p, ep->code[0], ep->code[1], (Uint)ep->code[2]); return ep->address; } else { /* @@ -6239,6 +6464,7 @@ call_fun(Process* p, /* Current process. */ reg[1] = function; reg[2] = args; } + DTRACE_CALL(p, module, function, arity); return ep->address; } else { badfun: diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index 1d968fb147..4ee60807d9 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -30,6 +30,7 @@ #include "big.h" #include "erl_binary.h" #include "erl_bits.h" +#include "dtrace-wrapper.h" #ifdef HYBRID MA_STACK_DECLARE(src); @@ -59,6 +60,12 @@ copy_object(Eterm obj, Process* to) Eterm* hp = HAlloc(to, size); Eterm res; + if (DTRACE_ENABLED(copy_object)) { + DTRACE_CHARBUF(proc_name, 64); + + erts_snprintf(proc_name, sizeof(proc_name), "%T", to->id); + DTRACE2(copy_object, proc_name, size); + } res = copy_struct(obj, size, &hp, &to->off_heap); #ifdef DEBUG if (eq(obj, res) == 0) { @@ -213,6 +220,8 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) if (IS_CONST(obj)) return obj; + DTRACE1(copy_struct, (int32_t)sz); + hp = htop = *hpp; hbot = htop + sz; hstart = (char *)htop; diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index bee61e7273..6f6b04d278 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -42,6 +42,7 @@ #include "external.h" #include "erl_binary.h" #include "erl_thr_progress.h" +#include "dtrace-wrapper.h" /* Turn this on to get printouts of all distribution messages * which go on the line @@ -740,6 +741,11 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) Eterm token = NIL; Process *sender = dsdp->proc; int res; + Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + Uint msize = 0; + DTRACE_CHARBUF(node_name, 64); + DTRACE_CHARBUF(sender_name, 64); + DTRACE_CHARBUF(receiver_name, 64); UseTmpHeapNoproc(5); if (SEQ_TRACE_TOKEN(sender) != NIL) { @@ -747,12 +753,28 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) token = SEQ_TRACE_TOKEN(sender); seq_trace_output(token, message, SEQ_TRACE_SEND, remote, sender); } + *node_name = *sender_name = *receiver_name = '\0'; + if (DTRACE_ENABLED(message_send) || DTRACE_ENABLED(message_send_remote)) { + erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname); + erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id); + erts_snprintf(receiver_name, sizeof(receiver_name), "%T", remote); + msize = size_object(message); + if (token != NIL) { + tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); + } + } if (token != NIL) ctl = TUPLE4(&ctl_heap[0], make_small(DOP_SEND_TT), am_Cookie, remote, token); else ctl = TUPLE3(&ctl_heap[0], make_small(DOP_SEND), am_Cookie, remote); + DTRACE6(message_send, sender_name, receiver_name, + msize, tok_label, tok_lastcnt, tok_serial); + DTRACE7(message_send_remote, sender_name, node_name, receiver_name, + msize, tok_label, tok_lastcnt, tok_serial); res = dsig_send(dsdp, ctl, message, 0); UnUseTmpHeapNoproc(5); return res; @@ -766,6 +788,11 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) Eterm token = NIL; Process *sender = dsdp->proc; int res; + Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + Uint32 msize = 0; + DTRACE_CHARBUF(node_name, 64); + DTRACE_CHARBUF(sender_name, 64); + DTRACE_CHARBUF(receiver_name, 128); UseTmpHeapNoproc(6); if (SEQ_TRACE_TOKEN(sender) != NIL) { @@ -773,6 +800,19 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) token = SEQ_TRACE_TOKEN(sender); seq_trace_output(token, message, SEQ_TRACE_SEND, remote_name, sender); } + *node_name = *sender_name = *receiver_name = '\0'; + if (DTRACE_ENABLED(message_send) || DTRACE_ENABLED(message_send_remote)) { + erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname); + erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id); + erts_snprintf(receiver_name, sizeof(receiver_name), + "{%T,%s}", remote_name, node_name); + msize = size_object(message); + if (token != NIL) { + tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); + } + } if (token != NIL) ctl = TUPLE5(&ctl_heap[0], make_small(DOP_REG_SEND_TT), @@ -780,6 +820,10 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) else ctl = TUPLE4(&ctl_heap[0], make_small(DOP_REG_SEND), sender->id, am_Cookie, remote_name); + DTRACE6(message_send, sender_name, receiver_name, + msize, tok_label, tok_lastcnt, tok_serial); + DTRACE7(message_send_remote, sender_name, node_name, receiver_name, + msize, tok_label, tok_lastcnt, tok_serial); res = dsig_send(dsdp, ctl, message, 0); UnUseTmpHeapNoproc(6); return res; @@ -793,6 +837,12 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, Eterm ctl; DeclareTmpHeapNoproc(ctl_heap,6); int res; + Process *sender = dsdp->proc; + Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + DTRACE_CHARBUF(node_name, 64); + DTRACE_CHARBUF(sender_name, 64); + DTRACE_CHARBUF(remote_name, 128); + DTRACE_CHARBUF(reason_str, 128); UseTmpHeapNoproc(6); if (token != NIL) { @@ -803,6 +853,21 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, } else { ctl = TUPLE4(&ctl_heap[0], make_small(DOP_EXIT), local, remote, reason); } + *node_name = *sender_name = *remote_name = '\0'; + if (DTRACE_ENABLED(process_exit_signal_remote)) { + erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname); + erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id); + erts_snprintf(remote_name, sizeof(remote_name), + "{%T,%s}", remote, node_name); + erts_snprintf(reason_str, sizeof(reason), "%T", reason); + if (token != NIL) { + tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); + } + } + DTRACE7(process_exit_signal_remote, sender_name, node_name, + remote_name, reason_str, tok_label, tok_lastcnt, tok_serial); /* forced, i.e ignore busy */ res = dsig_send(dsdp, ctl, THE_NON_VALUE, 1); UnUseTmpHeapNoproc(6); @@ -1619,6 +1684,16 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy) if (!(dep->qflgs & ERTS_DE_QFLG_BUSY)) { if (suspended) resume = 1; /* was busy when we started, but isn't now */ + if (resume && DTRACE_ENABLED(dist_port_not_busy)) { + DTRACE_CHARBUF(port_str, 64); + DTRACE_CHARBUF(remote_str, 64); + + erts_snprintf(port_str, sizeof(port_str), "%T", cid); + erts_snprintf(remote_str, sizeof(remote_str), + "%T", dep->sysname); + DTRACE3(dist_port_not_busy, erts_this_node_sysname, + port_str, remote_str); + } } else { /* Enqueue suspended process on dist entry */ @@ -1668,6 +1743,17 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy) } if (suspended) { + if (!resume && DTRACE_ENABLED(dist_port_busy)) { + DTRACE_CHARBUF(port_str, 64); + DTRACE_CHARBUF(remote_str, 64); + DTRACE_CHARBUF(pid_str, 16); + + erts_snprintf(port_str, sizeof(port_str), "%T", cid); + erts_snprintf(remote_str, sizeof(remote_str), "%T", dep->sysname); + erts_snprintf(pid_str, sizeof(pid_str), "%T", c_p->id); + DTRACE4(dist_port_busy, erts_this_node_sysname, + port_str, remote_str, pid_str); + } if (!resume && erts_system_monitor_flags.busy_dist_port) monitor_generic(c_p, am_busy_dist_port, cid); return ERTS_DSIG_SEND_YIELD; @@ -1691,6 +1777,16 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf) "(%beu bytes) passed.\n", size); + if (DTRACE_ENABLED(dist_output)) { + DTRACE_CHARBUF(port_str, 64); + DTRACE_CHARBUF(remote_str, 64); + + erts_snprintf(port_str, sizeof(port_str), "%T", prt->id); + erts_snprintf(remote_str, sizeof(remote_str), + "%T", prt->dist_entry->sysname); + DTRACE4(dist_output, erts_this_node_sysname, port_str, + remote_str, size); + } prt->caller = NIL; fpe_was_unmasked = erts_block_fpe(); (*prt->drv_ptr->output)((ErlDrvData) prt->drv_data, @@ -1733,6 +1829,16 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf) ASSERT(prt->drv_ptr->outputv); + if (DTRACE_ENABLED(dist_outputv)) { + DTRACE_CHARBUF(port_str, 64); + DTRACE_CHARBUF(remote_str, 64); + + erts_snprintf(port_str, sizeof(port_str), "%T", prt->id); + erts_snprintf(remote_str, sizeof(remote_str), + "%T", prt->dist_entry->sysname); + DTRACE4(dist_outputv, erts_this_node_sysname, port_str, + remote_str, size); + } prt->caller = NIL; fpe_was_unmasked = erts_block_fpe(); (*prt->drv_ptr->outputv)((ErlDrvData) prt->drv_data, &eiov); @@ -2052,6 +2158,16 @@ erts_dist_command(Port *prt, int reds_limit) void erts_dist_port_not_busy(Port *prt) { + if (DTRACE_ENABLED(dist_port_not_busy)) { + DTRACE_CHARBUF(port_str, 64); + DTRACE_CHARBUF(remote_str, 64); + + erts_snprintf(port_str, sizeof(port_str), "%T", prt->id); + erts_snprintf(remote_str, sizeof(remote_str), + "%T", prt->dist_entry->sysname); + DTRACE3(dist_port_not_busy, erts_this_node_sysname, + port_str, remote_str); + } erts_schedule_dist_command(prt, NULL); } @@ -2985,6 +3101,19 @@ send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, Eterm type, Eterm reas ASSERT(is_immed(what)); ASSERT(is_immed(node)); ASSERT(is_immed(type)); + if (DTRACE_ENABLED(dist_monitor)) { + DTRACE_CHARBUF(what_str, 12); + DTRACE_CHARBUF(node_str, 64); + DTRACE_CHARBUF(type_str, 12); + DTRACE_CHARBUF(reason_str, 64); + + erts_snprintf(what_str, sizeof(what_str), "%T", what); + erts_snprintf(node_str, sizeof(node_str), "%T", node); + erts_snprintf(type_str, sizeof(type_str), "%T", type); + erts_snprintf(reason_str, sizeof(reason_str), "%T", reason); + DTRACE5(dist_monitor, erts_this_node_sysname, + what_str, node_str, type_str, reason_str); + } ERTS_SMP_LC_ASSERT(!c_p || (erts_proc_lc_my_proc_locks(c_p) diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index 8bca9ae582..72dcc99f4f 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -26,6 +26,7 @@ #include "erl_threads.h" #include "erl_thr_queue.h" #include "erl_async.h" +#include "dtrace-wrapper.h" #define ERTS_MAX_ASYNC_READY_CALLS_IN_SEQ 20 @@ -121,6 +122,14 @@ typedef struct { #endif } ErtsAsyncData; +/* + * Some compilers, e.g. GCC 4.2.1 and -O3, will optimize away DTrace + * calls if they're the last thing in the function. :-( + * Many thanks to Trond Norbye, via: + * https://github.com/memcached/memcached/commit/6298b3978687530bc9d219b6ac707a1b681b2a46 + */ +static unsigned gcc_optimizer_hack = 0; + int erts_async_max_threads; /* Initialized by erl_init.c */ int erts_async_thread_suggested_stack_size; /* Initialized by erl_init.c */ @@ -244,6 +253,9 @@ erts_get_async_ready_queue(Uint sched_id) static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) { + /* DTRACE TODO: Get the queue length from erts_thr_q_enqueue() */ + int len = -1; + if (is_internal_port(a->port)) { #if ERTS_USE_ASYNC_READY_Q ErtsAsyncReadyQ *arq = async_ready_q(a->sched_id); @@ -259,6 +271,13 @@ static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) #endif erts_thr_q_enqueue(&q->thr_q, a); + if (DTRACE_ENABLED(aio_pool_add)) { + DTRACE_CHARBUF(port_str, 16); + + erts_snprintf(port_str, sizeof(port_str), "%T", a->port); + DTRACE2(aio_pool_add, port_str, len); + } + gcc_optimizer_hack++; } static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, @@ -269,6 +288,8 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, int saved_fin_deq = 0; ErtsThrQFinDeQ_t fin_deq; #endif + /* DTRACE TODO: Get the queue length from erts_thr_q_dequeue() somehow? */ + int len = -1; while (1) { ErtsAsync *a = (ErtsAsync *) erts_thr_q_dequeue(q); @@ -280,7 +301,12 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, if (saved_fin_deq) erts_thr_q_append_finalize_dequeue_data(&a->q.fin_deq, &fin_deq); #endif + if (DTRACE_ENABLED(aio_pool_get)) { + DTRACE_CHARBUF(port_str, 16); + erts_snprintf(port_str, sizeof(port_str), "%T", a->port); + DTRACE2(aio_pool_get, port_str, len); + } return a; } diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index 37d540b41b..3326fd84df 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -45,6 +45,7 @@ #include "big.h" #include "dist.h" #include "erl_version.h" +#include "dtrace-wrapper.h" #ifdef ERTS_SMP #define DDLL_SMP 1 @@ -1647,6 +1648,7 @@ static int do_unload_driver_entry(DE_Handle *dh, Eterm *save_name) diver_list lock here!*/ if (q->finish) { int fpe_was_unmasked = erts_block_fpe(); + DTRACE1(driver_finish, q->name); (*(q->finish))(); erts_unblock_fpe(fpe_was_unmasked); } diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index ebd475f73a..90bbb34927 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -114,6 +114,9 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE #endif #ifdef VALGRIND " [valgrind-compiled]" +#endif +#ifdef HAVE_DTRACE + " [dtrace]" #endif "\n"); diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index cd423eb200..8caa64b97d 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -40,6 +40,7 @@ #include "external.h" #include "packet_parser.h" #include "erl_bits.h" +#include "dtrace-wrapper.h" static int open_port(Process* p, Eterm name, Eterm settings, int *err_nump); static byte* convert_environment(Process* p, Eterm env); @@ -343,6 +344,14 @@ port_call(Process* c_p, Eterm arg1, Eterm arg2, Eterm arg3) __FILE__, __LINE__, endp - (bytes + size)); } erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); + if (DTRACE_ENABLED(driver_call)) { + DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); + + dtrace_pid_str(p->connected, process_str); + dtrace_port_str(p, port_str); + DTRACE5(driver_call, process_str, port_str, p->name, op, real_size); + } prc = (char *) port_resp; fpe_was_unmasked = erts_block_fpe(); ret = drv->call((ErlDrvData)p->drv_data, @@ -539,6 +548,16 @@ BIF_RETTYPE port_connect_2(BIF_ALIST_2) prt->connected = pid; /* internal pid */ erts_smp_port_unlock(prt); + if (DTRACE_ENABLED(port_connect)) { + DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(newprocess_str, DTRACE_TERM_BUF_SIZE); + + dtrace_pid_str(prt->connected, process_str); + erts_snprintf(port_str, sizeof(port_str), "%T", prt->id); + dtrace_proc_str(rp, newprocess_str); + DTRACE4(port_connect, process_str, port_str, prt->name, newprocess_str); + } BIF_RET(am_true); } @@ -904,6 +923,14 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump) erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); port_num = erts_open_driver(driver, p->id, name_buf, &opts, err_nump); + if (port_num >= 0 && DTRACE_ENABLED(port_open)) { + DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); + + dtrace_proc_str(p, process_str); + erts_snprintf(port_str, sizeof(port_str), "%T", erts_port[port_num].id); + DTRACE3(port_open, process_str, name_buf, port_str); + } erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index bde87b8346..858ae32ad5 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -35,6 +35,7 @@ #include "hipe_stack.h" #include "hipe_mode_switch.h" #endif +#include "dtrace-wrapper.h" #define ERTS_INACT_WR_PB_LEAVE_MUCH_LIMIT 1 #define ERTS_INACT_WR_PB_LEAVE_MUCH_PERCENTAGE 20 @@ -349,6 +350,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) Uint reclaimed_now = 0; int done = 0; Uint ms1, s1, us1; + DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); if (IS_TRACED_FL(p, F_TRACE_GC)) { trace_gc(p, am_gc_start); @@ -370,14 +372,26 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) FLAGS(p) |= F_NEED_FULLSWEEP; } + *pidbuf = '\0'; + if (DTRACE_ENABLED(gc_major_start) + || DTRACE_ENABLED(gc_major_end) + || DTRACE_ENABLED(gc_minor_start) + || DTRACE_ENABLED(gc_minor_end)) { + dtrace_proc_str(p, pidbuf); + } + /* * Test which type of GC to do. */ while (!done) { if ((FLAGS(p) & F_NEED_FULLSWEEP) != 0) { + DTRACE2(gc_major_start, pidbuf, need); done = major_collection(p, need, objv, nobj, &reclaimed_now); + DTRACE2(gc_major_end, pidbuf, reclaimed_now); } else { + DTRACE2(gc_minor_start, pidbuf, need); done = minor_collection(p, need, objv, nobj, &reclaimed_now); + DTRACE2(gc_minor_end, pidbuf, reclaimed_now); } } @@ -1118,6 +1132,13 @@ do_minor(Process *p, Uint new_sz, Eterm* objv, int nobj) sys_memcpy(n_heap + new_sz - n, p->stop, n * sizeof(Eterm)); p->stop = n_heap + new_sz - n; + if (HEAP_SIZE(p) != new_sz && DTRACE_ENABLED(process_heap_grow)) { + DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); + + dtrace_proc_str(p, pidbuf); + DTRACE3(process_heap_grow, pidbuf, HEAP_SIZE(p), new_sz); + } + ERTS_HEAP_FREE(ERTS_ALC_T_HEAP, (void*)HEAP_START(p), HEAP_SIZE(p) * sizeof(Eterm)); @@ -1339,6 +1360,13 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl) sys_memcpy(n_heap + new_sz - n, p->stop, n * sizeof(Eterm)); p->stop = n_heap + new_sz - n; + if (HEAP_SIZE(p) != new_sz && DTRACE_ENABLED(process_heap_grow)) { + DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); + + dtrace_proc_str(p, pidbuf); + DTRACE3(process_heap_grow, pidbuf, HEAP_SIZE(p), new_sz); + } + ERTS_HEAP_FREE(ERTS_ALC_T_HEAP, (void *) HEAP_START(p), (HEAP_END(p) - HEAP_START(p)) * sizeof(Eterm)); @@ -2009,6 +2037,14 @@ grow_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj) HEAP_TOP(p) = new_heap + heap_size; HEAP_START(p) = new_heap; } + + if (DTRACE_ENABLED(process_heap_grow)) { + DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); + + dtrace_proc_str(p, pidbuf); + DTRACE3(process_heap_grow, pidbuf, HEAP_SIZE(p), new_sz); + } + HEAP_SIZE(p) = new_sz; } @@ -2018,8 +2054,8 @@ shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj) Eterm* new_heap; Uint heap_size = HEAP_TOP(p) - HEAP_START(p); Sint offs; - Uint stack_size = p->hend - p->stop; + char pidbuf[DTRACE_TERM_BUF_SIZE]; ASSERT(new_sz < p->heap_sz); sys_memmove(p->heap + new_sz - stack_size, p->stop, stack_size * @@ -2047,6 +2083,14 @@ shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj) HEAP_TOP(p) = new_heap + heap_size; HEAP_START(p) = new_heap; } + + if (DTRACE_ENABLED(process_heap_shrink)) { + DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); + + dtrace_proc_str(p, pidbuf); + DTRACE3(process_heap_shrink, pidbuf, HEAP_SIZE(p), new_sz); + } + HEAP_SIZE(p) = new_sz; } diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 09e85893c3..561570c30e 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -182,6 +182,9 @@ static erts_lc_lock_order_t erts_lock_order[] = { #ifdef DEBUG { "save_ops_lock", NULL }, #endif +#endif +#ifdef HAVE_DTRACE + { "efile_drv dtrace mutex", NULL }, #endif { "mtrace_buf", NULL }, { "erts_alloc_hard_debug", NULL } diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index ab1ab7b1ea..8489353c9e 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -31,6 +31,7 @@ #include "erl_process.h" #include "erl_nmgc.h" #include "erl_binary.h" +#include "dtrace-wrapper.h" ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(message, ErlMessage, @@ -335,6 +336,7 @@ erts_queue_dist_message(Process *rcvr, Eterm token) { ErlMessage* mp; + Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; #ifdef ERTS_SMP ErtsProcLocks need_locks; #endif @@ -376,6 +378,19 @@ erts_queue_dist_message(Process *rcvr, message_free(mp); msg = erts_msg_distext2heap(rcvr, rcvr_locks, &mbuf, &token, dist_ext); if (is_value(msg)) + if (DTRACE_ENABLED(message_queued)) { + DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); + + dtrace_proc_str(rcvr, receiver_name); + if (token != NIL) { + tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); + } + DTRACE6(message_queued, + receiver_name, size_object(msg), rcvr->msg.len, + tok_label, tok_lastcnt, tok_serial); + } erts_queue_message(rcvr, rcvr_locks, mbuf, msg, token); } else { @@ -385,6 +400,22 @@ erts_queue_dist_message(Process *rcvr, ERL_MESSAGE_TOKEN(mp) = token; mp->next = NULL; + if (DTRACE_ENABLED(message_queued)) { + DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); + + dtrace_proc_str(rcvr, receiver_name); + if (token != NIL) { + tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); + } + /* + * TODO: We don't know the real size of the external message here. + * -1 will appear to a D script as 4294967295. + */ + DTRACE6(message_queued, receiver_name, -1, rcvr->msg.len + 1, + tok_label, tok_lastcnt, tok_serial); + } mp->data.dist_ext = dist_ext; LINK_MESSAGE(rcvr, mp); @@ -462,12 +493,27 @@ erts_queue_message(Process* receiver, LINK_MESSAGE(receiver, mp); #endif + if (DTRACE_ENABLED(message_queued)) { + DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); + Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + + dtrace_proc_str(receiver, receiver_name); + if (seq_trace_token != NIL && is_tuple(seq_trace_token)) { + tok_label = signed_val(SEQ_TRACE_T_LABEL(seq_trace_token)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(seq_trace_token)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(seq_trace_token)); + } + DTRACE6(message_queued, + receiver_name, size_object(message), receiver->msg.len, + tok_label, tok_lastcnt, tok_serial); + } + notify_new_message(receiver); if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) { trace_receive(receiver, message); } - + #ifndef ERTS_SMP ERTS_HOLE_CHECK(receiver); #endif @@ -774,11 +820,19 @@ erts_send_message(Process* sender, Uint msize; ErlHeapFragment* bp = NULL; Eterm token = NIL; + DTRACE_CHARBUF(sender_name, 64); + DTRACE_CHARBUF(receiver_name, 64); + Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; BM_STOP_TIMER(system); BM_MESSAGE(message,sender,receiver); BM_START_TIMER(send); + *sender_name = *receiver_name = '\0'; + if (DTRACE_ENABLED(message_send)) { + erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id); + erts_snprintf(receiver_name, sizeof(receiver_name), "%T", receiver->id); + } if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) { Eterm* hp; @@ -802,6 +856,16 @@ erts_send_message(Process* sender, BM_MESSAGE_COPIED(msize); BM_SWAP_TIMER(copy,send); + if (DTRACE_ENABLED(message_send)) { + Eterm token2 = NIL; + + token2 = SEQ_TRACE_TOKEN(sender); + tok_label = signed_val(SEQ_TRACE_T_LABEL(token2)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token2)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token2)); + DTRACE6(message_send, sender_name, receiver_name, + msize, tok_label, tok_lastcnt, tok_serial); + } erts_queue_message(receiver, receiver_locks, bp, @@ -835,6 +899,8 @@ erts_send_message(Process* sender, #endif LAZY_COPY(sender,message); BM_SWAP_TIMER(copy,send); + DTRACE6(message_send, sender_name, receiver_name, + size_object(message)msize, tok_label, tok_lastcnt, tok_serial); ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; mp->next = NULL; @@ -874,6 +940,8 @@ erts_send_message(Process* sender, { ErlMessage* mp = message_alloc(); + DTRACE6(message_send, sender_name, receiver_name, + size_object(message), tok_label, tok_lastcnt, tok_serial); mp->data.attached = NULL; ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; @@ -908,6 +976,8 @@ erts_send_message(Process* sender, message = copy_struct(message, msize, &hp, ohp); BM_MESSAGE_COPIED(msz); BM_SWAP_TIMER(copy,send); + DTRACE6(message_send, sender_name, receiver_name, + msize, tok_label, tok_lastcnt, tok_serial); erts_queue_message(receiver, receiver_locks, bp, message, token); BM_SWAP_TIMER(send,system); #else @@ -928,6 +998,8 @@ erts_send_message(Process* sender, message = copy_struct(message, msize, &hp, &receiver->off_heap); BM_MESSAGE_COPIED(msize); BM_SWAP_TIMER(copy,send); + DTRACE6(message_send, sender_name, receiver_name, + (uint32_t)msize, tok_label, tok_lastcnt, tok_serial); ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; mp->next = NULL; diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 58a09986d2..dc4049327d 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -66,6 +66,7 @@ static void add_readonly_check(ErlNifEnv*, unsigned char* ptr, unsigned sz); static int is_offheap(const ErlOffHeap* off_heap); #endif +void dtrace_nifenv_str(ErlNifEnv *, char *); #define MIN_HEAP_FRAG_SZ 200 static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp); @@ -1779,6 +1780,11 @@ void erl_nif_init() resource_type_list.name = THE_NON_VALUE; } +void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf) +{ + dtrace_pid_str(env->proc->id, process_buf); +} + #ifdef READONLY_CHECK /* Use checksums to assert that NIFs do not write into inspected binaries */ diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index 908ba755ed..1481f66b55 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -27,6 +27,7 @@ #include "big.h" #include "error.h" #include "erl_thr_progress.h" +#include "dtrace-wrapper.h" Hash erts_dist_table; Hash erts_node_table; @@ -42,6 +43,8 @@ Sint erts_no_of_not_connected_dist_entries; DistEntry *erts_this_dist_entry; ErlNode *erts_this_node; +char erts_this_node_sysname_BUFFER[256], + *erts_this_node_sysname = "uninitialized yet"; static Uint node_entries; static Uint dist_entries; @@ -702,6 +705,9 @@ erts_set_this_node(Eterm sysname, Uint creation) (void) hash_erase(&erts_node_table, (void *) erts_this_node); erts_this_node->sysname = sysname; erts_this_node->creation = creation; + erts_this_node_sysname = erts_this_node_sysname_BUFFER; + erts_snprintf(erts_this_node_sysname, sizeof(erts_this_node_sysname), + "%T", sysname); (void) hash_put(&erts_node_table, (void *) erts_this_node); erts_smp_rwmtx_rwunlock(&erts_dist_table_rwmtx); @@ -789,6 +795,9 @@ void erts_init_node_tables(void) erts_this_node->sysname = am_Noname; erts_this_node->creation = 0; erts_this_node->dist_entry = erts_this_dist_entry; + erts_this_node_sysname = erts_this_node_sysname_BUFFER; + erts_snprintf(erts_this_node_sysname, sizeof(erts_this_node_sysname), + "%T", erts_this_node->sysname); (void) hash_put(&erts_node_table, (void *) erts_this_node); diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h index 8abb748a78..5cfd0ac641 100644 --- a/erts/emulator/beam/erl_node_tables.h +++ b/erts/emulator/beam/erl_node_tables.h @@ -169,7 +169,7 @@ extern Sint erts_no_of_not_connected_dist_entries; extern DistEntry *erts_this_dist_entry; extern ErlNode *erts_this_node; -extern char erts_this_node_sysname[256]; /* must match erl_node_tables.c */ +extern char *erts_this_node_sysname; /* must match erl_node_tables.c */ DistEntry *erts_channel_no_to_dist_entry(Uint); DistEntry *erts_sysname_to_connected_dist_entry(Eterm); diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index a2b08fcf56..25bba5cf17 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -32,6 +32,7 @@ #include "global.h" #include "erl_port_task.h" #include "dist.h" +#include "dtrace-wrapper.h" #if defined(DEBUG) && 0 #define HARD_DEBUG @@ -61,6 +62,16 @@ do { \ (P)->sched.next = NULL; \ } while (0) +#define DTRACE_DRIVER(PROBE_NAME, PP) \ + if (DTRACE_ENABLED(driver_ready_input)) { \ + DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); \ + \ + dtrace_pid_str(PP->connected, process_str); \ + dtrace_port_str(PP, port_str); \ + DTRACE3(PROBE_NAME, process_str, port_str, PP->name); \ + } + erts_smp_atomic_t erts_port_task_outstanding_io_tasks; struct ErtsPortTaskQueue_ { @@ -823,12 +834,15 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) goto tasks_done; case ERTS_PORT_TASK_TIMEOUT: reds += ERTS_PORT_REDS_TIMEOUT; - if (!(pp->status & ERTS_PORT_SFLGS_DEAD)) + if (!(pp->status & ERTS_PORT_SFLGS_DEAD)) { + DTRACE_DRIVER(driver_timeout, pp); (*pp->drv_ptr->timeout)((ErlDrvData) pp->drv_data); + } break; case ERTS_PORT_TASK_INPUT: reds += ERTS_PORT_REDS_INPUT; ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0); + DTRACE_DRIVER(driver_ready_input, pp); /* NOTE some windows drivers use ->ready_input for input and output */ (*pp->drv_ptr->ready_input)((ErlDrvData) pp->drv_data, ptp->event); io_tasks_executed++; @@ -836,12 +850,14 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) case ERTS_PORT_TASK_OUTPUT: reds += ERTS_PORT_REDS_OUTPUT; ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0); + DTRACE_DRIVER(driver_ready_output, pp); (*pp->drv_ptr->ready_output)((ErlDrvData) pp->drv_data, ptp->event); io_tasks_executed++; break; case ERTS_PORT_TASK_EVENT: reds += ERTS_PORT_REDS_EVENT; ASSERT((pp->status & ERTS_PORT_SFLGS_DEAD) == 0); + DTRACE_DRIVER(driver_event, pp); (*pp->drv_ptr->event)((ErlDrvData) pp->drv_data, ptp->event, ptp->event_data); io_tasks_executed++; break; diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 45f6dc800c..1173624f51 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -42,6 +42,7 @@ #include "erl_thr_progress.h" #include "erl_thr_queue.h" #include "erl_async.h" +#include "dtrace-wrapper.h" #define ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED (2000*CONTEXT_REDS) #define ERTS_RUNQ_CALL_CHECK_BALANCE_REDS \ @@ -6214,6 +6215,13 @@ Process *schedule(Process *p, int calls) int actual_reds; int reds; + if (p != NULL && DTRACE_ENABLED(process_unscheduled)) { + DTRACE_CHARBUF(process_buf, DTRACE_TERM_BUF_SIZE); + + dtrace_proc_str(p, process_buf); + DTRACE1(process_unscheduled, process_buf); + } + if (ERTS_USE_MODIFIED_TIMING()) { context_reds = ERTS_MODIFIED_TIMING_CONTEXT_REDS; input_reductions = ERTS_MODIFIED_TIMING_INPUT_REDS; @@ -7384,6 +7392,14 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->id)); + if (DTRACE_ENABLED(process_spawn)) { + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); + + dtrace_fun_decode(p, mod, func, arity, process_name, mfa); + DTRACE2(process_spawn, process_name, mfa); + } + error: erts_smp_proc_unlock(parent, ERTS_PROC_LOCKS_ALL_MINOR); @@ -7952,6 +7968,17 @@ send_exit_signal(Process *c_p, /* current process if and only ASSERT(reason != THE_NON_VALUE); + if(DTRACE_ENABLED(process_exit_signal) && is_pid(from)) { + DTRACE_CHARBUF(sender_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(receiver_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(reason_buf, DTRACE_TERM_BUF_SIZE); + + dtrace_pid_str(from, sender_str); + dtrace_proc_str(rp, receiver_str); + erts_snprintf(reason_buf, sizeof(reason_buf) - 1, "%T", reason); + DTRACE3(process_exit_signal, sender_str, receiver_str, reason_buf); + } + if (ERTS_PROC_IS_TRAPPING_EXITS(rp) && (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) { if (is_not_nil(token) && token_update) @@ -8378,7 +8405,16 @@ erts_do_exit_process(Process* p, Eterm reason) p->arity = 0; /* No live registers */ p->fvalue = reason; - + + if (DTRACE_ENABLED(process_exit)) { + DTRACE_CHARBUF(process_buf, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(reason_buf, 256); + + dtrace_proc_str(p, process_buf); + erts_snprintf(reason_buf, sizeof(reason_buf) - 1, "%T", reason); + DTRACE2(process_exit, process_buf, reason_buf); + } + #ifdef ERTS_SMP ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); /* By locking all locks (main lock is already locked) when going diff --git a/erts/emulator/beam/erlang_dtrace.d b/erts/emulator/beam/erlang_dtrace.d new file mode 100644 index 0000000000..d8508426f4 --- /dev/null +++ b/erts/emulator/beam/erlang_dtrace.d @@ -0,0 +1,716 @@ +/* + * %CopyrightBegin% + * + * Copyright Dustin Sallings, Michal Ptaszek, Scott Lystig Fritchie 2011. + * All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * 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. + */ + +provider erlang { + /** + * Fired when a message is sent from one local process to another. + * + * NOTE: The 'size' parameter is in machine-dependent words and + * that the actual size of any binary terms in the message + * are not included. + * + * @param sender the PID (string form) of the sender + * @param receiver the PID (string form) of the receiver + * @param size the size of the message being delivered (words) + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe message__send(char *sender, char *receiver, uint32_t size, + int token_label, int token_previous, int token_current); + + /** + * Fired when a message is sent from a local process to a remote process. + * + * NOTE: The 'size' parameter is in machine-dependent words and + * that the actual size of any binary terms in the message + * are not included. + * + * @param sender the PID (string form) of the sender + * @param node_name the Erlang node name (string form) of the receiver + * @param receiver the PID/name (string form) of the receiver + * @param size the size of the message being delivered (words) + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe message__send__remote(char *sender, char *node_name, char *receiver, + uint32_t size, + int token_label, int token_previous, int token_current); + + /** + * Fired when a message is queued to a local process. This probe + * will not fire if the sender's pid == receiver's pid. + * + * NOTE: The 'size' parameter is in machine-dependent words and + * that the actual size of any binary terms in the message + * are not included. + * + * NOTE: In cases of messages in external format (i.e. from another + * Erlang node), we probably don't know the message size + * without performing substantial extra computation. To + * avoid the extra CPU overhead, the message size may be + * reported as -1, which can appear to a D script as 4294967295. + * + * @param receiver the PID (string form) of the receiver + * @param size the size of the message being delivered (words) + * @param queue_len length of the queue of the receiving process + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe message__queued(char *receiver, uint32_t size, uint32_t queue_len, + int token_label, int token_previous, int token_current); + + /** + * Fired when a message is 'receive'd by a local process and removed + * from its mailbox. + * + * NOTE: The 'size' parameter is in machine-dependent words and + * that the actual size of any binary terms in the message + * are not included. + * + * NOTE: In cases of messages in external format (i.e. from another + * Erlang node), we probably don't know the message size + * without performing substantial extra computation. To + * avoid the extra CPU overhead, the message size may be + * reported as -1, which can appear to a D script as 4294967295. + * + * @param receiver the PID (string form) of the receiver + * @param size the size of the message being delivered (words) + * @param queue_len length of the queue of the receiving process + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe message__receive(char *receiver, uint32_t size, uint32_t queue_len, + int token_label, int token_previous, int token_current); + + /** + * Fired when an Eterm structure is being copied. + * + * NOTE: Due to the placement of this probe, the process ID of + * owner of the Eterm is not available. + * + * @param size the size of the structure + */ + probe copy__struct(uint32_t size); + + /** + * Fired when an Eterm is being copied onto a process. + * + * @param proc the PID (string form) of the recipient process + * @param size the size of the structure + */ + probe copy__object(char *proc, uint32_t size); + + /* PID, Module, Function, Arity */ + + /** + * Fired whenever a user function is being called. + * + * @param p the PID (string form) of the process + * @param mfa the m:f/a of the function + * @param depth the stack depth + */ + probe function__entry(char *p, char *mfa, int depth); + + /** + * Fired whenever a user function returns. + * + * @param p the PID (string form) of the process + * @param mfa the m:f/a of the function + * @param depth the stack depth + */ + probe function__return(char *p, char *mfa, int depth); + + /** + * Fired whenever a Built In Function is called. + * + * @param p the PID (string form) of the process + * @param mfa the m:f/a of the function + */ + probe bif__entry(char *p, char *mfa); + + /** + * Fired whenever a Built In Function returns. + * + * @param p the PID (string form) of the process + * @param mfa the m:f/a of the function + */ + probe bif__return(char *p, char *mfa); + + /** + * Fired whenever a Native Function is called. + * + * @param p the PID (string form) of the process + * @param mfa the m:f/a of the function + */ + probe nif__entry(char *p, char *mfa); + + /** + * Fired whenever a Native Function returns. + * + * @param p the PID (string form) of the process + * @param mfa the m:f/a of the function + */ + probe nif__return(char *p, char *mfa); + + /** + * Fired when a major GC is starting. + * + * @param p the PID (string form) of the exiting process + * @param need the number of words needed on the heap + */ + probe gc_major__start(char *p, int need); + + /** + * Fired when a minor GC is starting. + * + * @param p the PID (string form) of the exiting process + * @param need the number of words needed on the heap + */ + probe gc_minor__start(char *p, int need); + + /** + * Fired when a major GC is starting. + * + * @param p the PID (string form) of the exiting process + * @param reclaimed the amount of space reclaimed + */ + probe gc_major__end(char *p, int reclaimed); + + /** + * Fired when a minor GC is starting. + * + * @param p the PID (string form) of the exiting process + * @param reclaimed the amount of space reclaimed + */ + probe gc_minor__end(char *p, int reclaimed); + + /** + * Fired when a process is spawned. + * + * @param p the PID (string form) of the new process. + * @param mfa the m:f/a of the function + */ + probe process__spawn(char *p, char *mfa); + + /** + * Fired when a process is exiting. + * + * @param p the PID (string form) of the exiting process + * @param reason the reason for the exit (may be truncated) + */ + probe process__exit(char *p, char *reason); + + /** + * Fired when exit signal is delivered to a local process. + * + * @param sender the PID (string form) of the exiting process + * @param receiver the PID (string form) of the process receiving EXIT signal + * @param reason the reason for the exit (may be truncated) + */ + probe process__exit_signal(char *sender, char *receiver, char *reason); + + /** + * Fired when exit signal is delivered to a remote process. + * + * @param sender the PID (string form) of the exiting process + * @param node_name the Erlang node name (string form) of the receiver + * @param receiver the PID (string form) of the process receiving EXIT signal + * @param reason the reason for the exit (may be truncated) + * @param token_label for the sender's sequential trace token + * @param token_previous count for the sender's sequential trace token + * @param token_current count for the sender's sequential trace token + */ + probe process__exit_signal__remote(char *sender, char *node_name, + char *receiver, char *reason, + int token_label, int token_previous, int token_current); + + /** + * Fired when a process is scheduled. + * + * @param p the PID (string form) of the newly scheduled process + * @param mfa the m:f/a of the function it should run next + */ + probe process__scheduled(char *p, char *mfa); + + /** + * Fired when a process is unscheduled. + * + * @param p the PID (string form) of the process that has been + * unscheduled. + */ + probe process__unscheduled(char *p); + + /** + * Fired when a process goes into hibernation. + * + * @param p the PID (string form) of the process entering hibernation + * @param mfa the m:f/a of the location to resume + */ + probe process__hibernate(char *p, char *mfa); + + /** + * Fired when a process is unblocked after a port has been unblocked. + * + * @param p the PID (string form) of the process that has been + * unscheduled. + * @param port the port that is no longer busy (i.e., is now unblocked) + */ + probe process__port_unblocked(char *p, char *port); + + /** + * Fired when process' heap is growing. + * + * @param p the PID (string form) + * @param old_size the size of the old heap + * @param new_size the size of the new heap + */ + probe process__heap_grow(char *p, int old_size, int new_size); + + /** + * Fired when process' heap is shrinking. + * + * @param p the PID (string form) + * @param old_size the size of the old heap + * @param new_size the size of the new heap + */ + probe process__heap_shrink(char *p, int old_size, int new_size); + + /* network distribution */ + + /** + * Fired when network distribution event monitor events are triggered. + * + * @param node the name of the reporting node + * @param what the type of event, e.g., nodeup, nodedown + * @param monitored_node the name of the monitored node + * @param type the type of node, e.g., visible, hidden + * @param reason the reason term, e.g., normal, connection_closed, term() + */ + probe dist__monitor(char *node, char *what, char *monitored_node, + char *type, char *reason); + + /** + * Fired when network distribution port is busy (i.e. blocked), + * usually due to the remote node not consuming distribution + * data quickly enough. + * + * @param node the name of the reporting node + * @param port the port ID of the busy port + * @param remote_node the name of the remote node. + * @param pid the PID (string form) of the local process that has + * become unschedulable until the port becomes unblocked. + */ + probe dist__port_busy(char *node, char *port, char *remote_node, + char *pid); + + /** + * Fired when network distribution's driver's "output" callback is called + * + * @param node the name of the reporting node + * @param port the port ID of the busy port + * @param remote_node the name of the remote node. + * @param bytes the number of bytes written + */ + probe dist__output(char *node, char *port, char *remote_node, int bytes); + + /** + * Fired when network distribution's driver's "outputv" callback is called + * + * @param node the name of the reporting node + * @param port the port ID of the busy port + * @param remote_node the name of the remote node. + * @param bytes the number of bytes written + */ + probe dist__outputv(char *node, char *port, char *remote_node, int bytes); + + /** + * Fired when network distribution port is no longer busy (i.e. blocked). + * + * NOTE: This probe may fire multiple times after the same single + * dist-port_busy probe firing. + * + * @param node the name of the reporting node + * @param port the port ID of the busy port + * @param remote_node the name of the remote node. + */ + probe dist__port_not_busy(char *node, char *port, char *remote_node); + + /* ports */ + + /** + * Fired when new port is opened. + * + * @param process the PID (string form) + * @param port_name the string used when the port was opened + * @param port the Port (string form) of the new port + */ + probe port__open(char *process, char *port_name, char *port); + + /** + * Fired when port_command is issued. + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + * @param command_type type of the issued command, one of: "close", "command" or "connect" + */ + probe port__command(char *process, char *port, char *port_name, char *command_type); + + /** + * Fired when port_control is issued. + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + * @param command_no command number that has been issued to the port + */ + probe port__control(char *process, char *port, char *port_name, int command_no); + + /** + * Fired when port is closed via port_close/1 (reason = 'normal') + * or is sent an exit signal. + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + * @param reason Erlang term representing the exit signal, e.g. 'normal' + */ + probe port__exit(char *process, char *port, char *port_name, + char *new_process); + + /** + * Fired when port_connect is issued. + * + * @param process the PID (string form) of the current port owner + * @param port the Port (string form) + * @param port_name the string used when the port was opened + * @param new_process the PID (string form) of the new port owner + */ + probe port__connect(char *process, char *port, char *port_name, + char *new_process); + + /** + * Fired when a port is busy (i.e. blocked) + * + * @param port the port ID of the busy port + */ + probe port__busy(char *port); + + /** + * Fired when a port is no longer busy (i.e. no longer blocked) + * + * @param port the port ID of the not busy port + */ + probe port__not_busy(char *port); + + /* drivers */ + + /** + * Fired when drivers's "init" callback is called. + * + * @param name the name of the driver + * @param major the major version number + * @param minor the minor version number + * @param flags the flags argument + */ + probe driver__init(char *name, int major, int minor, int flags); + + /** + * Fired when drivers's "start" callback is called. + * + * @param process the PID (string form) of the calling process + * @param name the name of the driver + * @param port the Port (string form) of the driver's port + */ + probe driver__start(char *process, char *name, char *port); + + /** + * Fired when drivers's "stop" callback is called. + * + * @param process the PID (string form) of the calling process + * @param name the name of the driver + * @param port the Port (string form) of the driver's port + */ + probe driver__stop(char *process, char *name, char *port); + + /** + * Fired when drivers's "finish" callback is called. + * + * @param name the name of the driver + */ + probe driver__finish(char *name); + + /** + * Fired when drivers's "flush" callback is called. + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + */ + probe driver__flush(char *process, char *port, char *port_name); + + /** + * Fired when driver's "output" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + * @param bytes the number of bytes written + */ + probe driver__output(char *node, char *port, char *port_name, int bytes); + + /** + * Fired when driver's "outputv" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + * @param bytes the number of bytes written + */ + probe driver__outputv(char *node, char *port, char *port_name, int bytes); + + /** + * Fired when driver's "control" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + * @param command the command # + * @param bytes the number of bytes written + */ + probe driver__control(char *node, char *port, char *port_name, + int command, int bytes); + + /** + * Fired when driver's "call" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + * @param command the command # + * @param bytes the number of bytes written + */ + probe driver__call(char *node, char *port, char *port_name, + int command, int bytes); + + /** + * Fired when driver's "event" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + */ + probe driver__event(char *node, char *port, char *port_name); + + /** + * Fired when driver's "ready_input" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + */ + probe driver__ready_input(char *node, char *port, char *port_name); + + /** + * Fired when driver's "read_output" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + */ + probe driver__ready_output(char *node, char *port, char *port_name); + + /** + * Fired when driver's "timeout" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + */ + probe driver__timeout(char *node, char *port, char *port_name); + + /** + * Fired when drivers's "ready_async" callback is called. + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + */ + probe driver__ready_async(char *process, char *port, char *port_name); + + /** + * Fired when driver's "process_exit" callback is called + * + * @param process the PID (string form) + * @param port the Port (string form) + * @param port_name the string used when the port was opened + */ + probe driver__process_exit(char *node, char *port, char *port_name); + + /** + * Fired when driver's "stop_select" callback is called + * + * @param name the name of the driver + */ + probe driver__stop_select(char *name); + + + /* Async driver pool */ + + /** + * Show the post-add length of the async driver thread pool member's queue. + * + * NOTE: The port name is not available: additional lock(s) must + * be acquired in order to get the port name safely in an SMP + * environment. The same is true for the aio__pool_get probe. + * + * @param port the Port (string form) + * @param new queue length + */ + probe aio_pool__add(char *, int); + + /** + * Show the post-get length of the async driver thread pool member's queue. + * + * @param port the Port (string form) + * @param new queue length + */ + probe aio_pool__get(char *, int); + + /* Probes for efile_drv.c */ + + /** + * Entry into the efile_drv.c file I/O driver + * + * For a list of command numbers used by this driver, see the section + * "Guide to probe arguments" in ../../../README.md. That section + * also contains explanation of the various integer and string + * arguments that may be present when any particular probe fires. + * + * NOTE: Not all Linux platforms (using SystemTap) can support + * arguments beyond arg9. + * + * + * TODO: Adding the port string, args[10], is a pain. Making that + * port string available to all the other efile_drv.c probes + * will be more pain. Is the pain worth it? If yes, then + * add them everywhere else and grit our teeth. If no, then + * rip it out. + * + * @param thread-id number of the scheduler Pthread arg0 + * @param tag number: {thread-id, tag} uniquely names a driver operation + * @param user-tag string arg2 + * @param command number arg3 + * @param string argument 1 arg4 + * @param string argument 2 arg5 + * @param integer argument 1 arg6 + * @param integer argument 2 arg7 + * @param integer argument 3 arg8 + * @param integer argument 4 arg9 + * @param port the port ID of the busy port args[10] + */ + probe efile_drv__entry(int, int, char *, int, char *, char *, + int64_t, int64_t, int64_t, int64_t, char *); + + /** + * Entry into the driver's internal work function. Computation here + * is performed by a async worker pool Pthread. + * + * @param thread-id number + * @param tag number + * @param command number + */ + probe efile_drv__int_entry(int, int, int); + + /** + * Return from the driver's internal work function. + * + * @param thread-id number + * @param tag number + * @param command number + */ + probe efile_drv__int_return(int, int, int); + + /** + * Return from the efile_drv.c file I/O driver + * + * @param thread-id number arg0 + * @param tag number arg1 + * @param user-tag string arg2 + * @param command number arg3 + * @param Success? 1 is success, 0 is failure arg4 + * @param If failure, the errno of the error. arg5 + */ + probe efile_drv__return(int, int, char *, int, int, int); + +/* + * NOTE: + * For formatting int64_t arguments within a D script, see: + * + * http://mail.opensolaris.org/pipermail/dtrace-discuss/2006-November/002830.html + * Summary: + * "1) you don't need the 'l' printf() modifiers with DTrace ever" + */ + +/* + * NOTE: For file_drv_return + SMP + R14B03 (and perhaps other + * releases), the sched-thread-id will be the same as the + * work-thread-id: erl_async.c's async_main() function + * will call the asynchronous invoke function and then + * immediately call the drivers ready_async function while + * inside the same I/O worker pool thread. + * For R14B03's source, see erl_async.c lines 302-317. + */ +}; + +#pragma D attributes Evolving/Evolving/Common provider erlang provider +#pragma D attributes Private/Private/Common provider erlang module +#pragma D attributes Private/Private/Common provider erlang function +#pragma D attributes Evolving/Evolving/Common provider erlang name +#pragma D attributes Evolving/Evolving/Common provider erlang args diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index fb1514a147..81f79b8f85 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -43,6 +43,7 @@ #include "erl_version.h" #include "error.h" #include "erl_async.h" +#include "dtrace-wrapper.h" extern ErlDrvEntry fd_driver_entry; extern ErlDrvEntry vanilla_driver_entry; @@ -180,6 +181,19 @@ typedef struct line_buf_context { #define LINEBUF_INITIAL 100 +#define DTRACE_FORMAT_COMMON_PID_AND_PORT(PID, PORT) \ + DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); \ + \ + dtrace_pid_str((PID), process_str); \ + dtrace_port_str((PORT), port_str); +#define DTRACE_FORMAT_COMMON_PROC_AND_PORT(PID, PORT) \ + DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); \ + \ + dtrace_proc_str((PID), process_str); \ + dtrace_port_str((PORT), port_str); + /* The 'number' field in a port now has two parts: the lowest bits contain the index in the port table, and the higher bits are a counter @@ -639,6 +653,10 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ trace_sched_ports_where(port, am_in, am_start); } port->caller = pid; + if (DTRACE_ENABLED(driver_start)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(pid, port) + DTRACE3(driver_start, process_str, driver->name, port_str); + } fpe_was_unmasked = erts_block_fpe(); drv_data = (*driver->start)((ErlDrvPort)(port_ix), name, opts); @@ -1170,6 +1188,10 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) ev.size = size; /* total size */ ev.iov = ivp; ev.binv = bvp; + if (DTRACE_ENABLED(driver_outputv)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p) + DTRACE4(driver_outputv, process_str, port_str, p->name, size); + } fpe_was_unmasked = erts_block_fpe(); (*drv->outputv)((ErlDrvData)p->drv_data, &ev); erts_unblock_fpe(fpe_was_unmasked); @@ -1189,8 +1211,17 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) buf = erts_alloc(ERTS_ALC_T_TMP, size+1); r = io_list_to_buf(list, buf, size); + if(DTRACE_ENABLED(port_command)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p) + DTRACE4(port_command, process_str, port_str, p->name, "command"); + } + if (r >= 0) { size -= r; + if (DTRACE_ENABLED(driver_output)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p) + DTRACE4(driver_output, process_str, port_str, p->name, size); + } fpe_was_unmasked = erts_block_fpe(); (*drv->output)((ErlDrvData)p->drv_data, buf, size); erts_unblock_fpe(fpe_was_unmasked); @@ -1214,6 +1245,10 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) */ buf = erts_alloc(ERTS_ALC_T_TMP, size+1); r = io_list_to_buf(list, buf, size); + if (DTRACE_ENABLED(driver_output)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p) + DTRACE4(driver_output, process_str, port_str, p->name, size); + } fpe_was_unmasked = erts_block_fpe(); (*drv->output)((ErlDrvData)p->drv_data, buf, size); erts_unblock_fpe(fpe_was_unmasked); @@ -1810,6 +1845,10 @@ static void flush_port(Port *p) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p)); if (p->drv_ptr->flush != NULL) { + if (DTRACE_ENABLED(driver_flush)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(p->connected, p) + DTRACE3(driver_flush, process_str, port_str, p->name); + } if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) { trace_sched_ports_where(p, am_in, am_flush); } @@ -1865,6 +1904,10 @@ terminate_port(Port *prt) drv = prt->drv_ptr; if ((drv != NULL) && (drv->stop != NULL)) { int fpe_was_unmasked = erts_block_fpe(); + if (DTRACE_ENABLED(driver_stop)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(prt->connected, prt) + DTRACE3(driver_stop, process_str, drv->name, port_str); + } (*drv->stop)((ErlDrvData)prt->drv_data); erts_unblock_fpe(fpe_was_unmasked); #ifdef ERTS_SMP @@ -2026,6 +2069,17 @@ erts_do_exit_port(Port *p, Eterm from, Eterm reason) rreason = (reason == am_kill) ? am_killed : reason; + if (DTRACE_ENABLED(port_exit)) { + DTRACE_CHARBUF(from_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); + DTRACE_CHARBUF(rreason_str, 64); + + erts_snprintf(from_str, sizeof(from_str), "%T", from); + dtrace_port_str(p, port_str); + erts_snprintf(rreason_str, sizeof(rreason_str), "%T", rreason); + DTRACE4(port_exit, from_str, port_str, p->name, rreason_str); + } + if ((p->status & (ERTS_PORT_SFLGS_DEAD | ERTS_PORT_SFLG_EXITING | ERTS_PORT_SFLG_IMMORTAL)) @@ -2126,6 +2180,11 @@ void erts_port_command(Process *proc, if (tp[2] == am_close) { erts_port_status_bor_set(port, ERTS_PORT_SFLG_SEND_CLOSED); erts_do_exit_port(port, pid, am_normal); + + if(DTRACE_ENABLED(port_command)) { + DTRACE_FORMAT_COMMON_PROC_AND_PORT(proc, port) + DTRACE4(port_command, process_str, port_str, port->name, "close"); + } goto done; } else if (is_tuple_arity(tp[2], 2)) { tp = tuple_val(tp[2]); @@ -2133,6 +2192,10 @@ void erts_port_command(Process *proc, if (erts_write_to_port(caller_id, port, tp[2]) == 0) goto done; } else if ((tp[1] == am_connect) && is_internal_pid(tp[2])) { + if(DTRACE_ENABLED(port_command)) { + DTRACE_FORMAT_COMMON_PROC_AND_PORT(proc, port) + DTRACE4(port_command, process_str, port_str, port->name, "connect"); + } port->connected = tp[2]; deliver_result(port->id, pid, am_connected); goto done; @@ -2235,6 +2298,13 @@ erts_port_control(Process* p, Port* prt, Uint command, Eterm iolist) erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); ERTS_SMP_CHK_NO_PROC_LOCKS; + if (DTRACE_ENABLED(port_control) || DTRACE_ENABLED(driver_control)) { + DTRACE_FORMAT_COMMON_PROC_AND_PORT(p, prt); + DTRACE4(port_control, process_str, port_str, prt->name, command); + DTRACE5(driver_control, process_str, port_str, prt->name, + command, to_len); + } + /* * Call the port's control routine. */ @@ -2375,6 +2445,8 @@ print_port_info(int to, void *arg, int i) void set_busy_port(ErlDrvPort port_num, int on) { + DTRACE_CHARBUF(port_str, 16); + ERTS_SMP_CHK_NO_PROC_LOCKS; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(&erts_port[port_num])); @@ -2382,12 +2454,22 @@ set_busy_port(ErlDrvPort port_num, int on) if (on) { erts_port_status_bor_set(&erts_port[port_num], ERTS_PORT_SFLG_PORT_BUSY); + if (DTRACE_ENABLED(port_busy)) { + erts_snprintf(port_str, sizeof(port_str), + "%T", erts_port[port_num].id); + DTRACE1(port_busy, port_str); + } } else { ErtsProcList* plp = erts_port[port_num].suspended; erts_port_status_band_set(&erts_port[port_num], ~ERTS_PORT_SFLG_PORT_BUSY); erts_port[port_num].suspended = NULL; + if (DTRACE_ENABLED(port_not_busy)) { + erts_snprintf(port_str, sizeof(port_str), + "%T", erts_port[port_num].id); + DTRACE1(port_not_busy, port_str); + } if (erts_port[port_num].dist_entry) { /* * Processes suspended on distribution ports are @@ -2405,6 +2487,26 @@ set_busy_port(ErlDrvPort port_num, int on) */ if (plp) { + /* + * Hrm, for blocked dist ports, plp always seems to be NULL. + * That's not so fun. + * Well, another way to get the same info is using a D + * script to correlate an earlier process-port_blocked+pid + * event with a later process-scheduled event. That's + * subject to the multi-CPU races with how events are + * handled, but hey, that way works most of the time. + */ + if (DTRACE_ENABLED(process_port_unblocked)) { + DTRACE_CHARBUF(pid_str, 16); + ErtsProcList* plp2 = plp; + + erts_snprintf(port_str, sizeof(port_str), + "%T", erts_port[port_num]); + while (plp2 != NULL) { + erts_snprintf(pid_str, sizeof(pid_str), "%T", plp2->pid); + DTRACE2(process_port_unblocked, pid_str, port_str); + } + } /* First proc should be resumed last */ if (plp->next) { erts_resume_processes(plp->next); @@ -2451,6 +2553,12 @@ void erts_raw_port_command(Port* p, byte* buf, Uint len) p->drv_ptr->name ? p->drv_ptr->name : "unknown"); p->caller = NIL; + if (DTRACE_ENABLED(driver_output)) { + DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); + + dtrace_port_str(p, port_str); + DTRACE4(driver_output, "-raw-", port_str, p->name, len); + } fpe_was_unmasked = erts_block_fpe(); (*p->drv_ptr->output)((ErlDrvData)p->drv_data, (char*) buf, (int) len); erts_unblock_fpe(fpe_was_unmasked); @@ -2466,6 +2574,10 @@ int async_ready(Port *p, void* data) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p)); ASSERT(!(p->status & ERTS_PORT_SFLGS_DEAD)); if (p->drv_ptr->ready_async != NULL) { + if (DTRACE_ENABLED(driver_ready_async)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(p->connected, p) + DTRACE3(driver_ready_async, process_str, port_str, p->name); + } (*p->drv_ptr->ready_async)((ErlDrvData)p->drv_data, data); need_free = 0; #ifdef ERTS_SMP @@ -4441,6 +4553,10 @@ void erts_fire_port_monitor(Port *prt, Eterm ref) ASSERT(callback != NULL); ref_to_driver_monitor(ref,&drv_monitor); DRV_MONITOR_UNLOCK_PDL(prt); + if (DTRACE_ENABLED(driver_process_exit)) { + DTRACE_FORMAT_COMMON_PID_AND_PORT(prt->connected, prt) + DTRACE3(driver_process_exit, process_str, port_str, prt->name); + } fpe_was_unmasked = erts_block_fpe(); (*callback)((ErlDrvData) (prt->drv_data), &drv_monitor); erts_unblock_fpe(fpe_was_unmasked); @@ -4884,6 +5000,8 @@ init_driver(erts_driver_t *drv, ErlDrvEntry *de, DE_Handle *handle) else { int res; int fpe_was_unmasked = erts_block_fpe(); + DTRACE4(driver_init, drv->name, drv->version.major, drv->version.minor, + drv->flags); res = (*de->init)(); erts_unblock_fpe(fpe_was_unmasked); return res; diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index 23a4bf1b04..cb7ef95f00 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -36,6 +36,7 @@ #include "global.h" #include "erl_check_io.h" #include "erl_thr_progress.h" +#include "dtrace-wrapper.h" #ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS # define ERTS_DRV_EV_STATE_EXTRA_SIZE 128 @@ -314,6 +315,7 @@ forget_removed(struct pollset_info* psi) erts_smp_mtx_unlock(mtx); if (drv_ptr) { int was_unmasked = erts_block_fpe(); + DTRACE1(driver_stop_select, drv_ptr->name); (*drv_ptr->stop_select) ((ErlDrvEvent) fd, NULL); erts_unblock_fpe(was_unmasked); if (drv_ptr->handle) { @@ -496,6 +498,7 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, ErtsDrvEventState *state; int wake_poller; int ret; + DTRACE_CHARBUF(name, 64); ERTS_SMP_LC_ASSERT(erts_drvport2port(ix) && erts_lc_is_port_locked(erts_drvport2port(ix))); @@ -525,6 +528,8 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, if (IS_FD_UNKNOWN(state)) { /* fast track to stop_select callback */ stop_select_fn = erts_drvport2port(ix)->drv_ptr->stop_select; + strncpy(name, erts_drvport2port(ix)->drv_ptr->name, sizeof(name)-1); + name[sizeof(name)-1] = '\0'; ret = 0; goto done_unknown; } @@ -661,6 +666,8 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, /* Safe to close fd now as it is not in pollset or there was no need to eject fd (kernel poll) */ stop_select_fn = drv_ptr->stop_select; + strncpy(name, erts_drvport2port(ix)->drv_ptr->name, sizeof(name)-1); + name[sizeof(name)-1] = '\0'; } else { /* Not safe to close fd, postpone stop_select callback. */ @@ -686,6 +693,7 @@ done_unknown: erts_smp_mtx_unlock(fd_mtx(fd)); if (stop_select_fn) { int was_unmasked = erts_block_fpe(); + DTRACE1(driver_stop_select, name); (*stop_select_fn)(e, NULL); erts_unblock_fpe(was_unmasked); } diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c index 108a8bb531..afb9c0abb7 100644 --- a/erts/lib_src/common/erl_printf.c +++ b/erts/lib_src/common/erl_printf.c @@ -176,16 +176,18 @@ write_sn(void *vwsnap, char* buf, size_t len) write_sn_arg_t *wsnap = (write_sn_arg_t *) vwsnap; ASSERT(wsnap); ASSERT(len > 0); + int rv = 0; if (wsnap->len > 0) { size_t sz = len; if (sz >= wsnap->len) sz = wsnap->len; + rv = (int)sz; memcpy((void *) wsnap->buf, (void *) buf, sz); wsnap->buf += sz; wsnap->len -= sz; return sz; } - return 0; + return rv; } static int -- cgit v1.2.3 From ad6387b0242caa2b3c64d62a133752e10546211b Mon Sep 17 00:00:00 2001 From: Scott Lystig Fritchie Date: Thu, 17 Nov 2011 00:47:23 -0600 Subject: Add DTrace support for OS X, Solaris, and Linux (via SystemTap), 4/4 Add probes to (mostly) the efile_drv.c driver and other file I/O-related source files. --- erts/emulator/drivers/common/efile_drv.c | 569 ++++++++++++++++++++++++----- erts/preloaded/ebin/prim_file.beam | Bin 39536 -> 46840 bytes erts/preloaded/src/prim_file.erl | 600 +++++++++++++++++++------------ lib/kernel/src/file.erl | 149 +++++--- lib/kernel/src/file_io_server.erl | 15 +- lib/kernel/src/file_server.erl | 106 +++--- lib/kernel/test/prim_file_SUITE.erl | 108 +++--- 7 files changed, 1061 insertions(+), 486 deletions(-) diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index a251b064da..b72f95792c 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -112,6 +112,8 @@ #include "erl_threads.h" #include "zlib.h" #include "gzio.h" +#define DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS +#include "dtrace-wrapper.h" #include #include @@ -119,6 +121,40 @@ void erl_exit(int n, char *fmt, ...); static ErlDrvSysInfo sys_info; +/* For explanation of this var, see comment for same var in erl_async.c */ +static unsigned gcc_optimizer_hack = 0; + +#ifdef HAVE_DTRACE + +#define DTRACE_INVOKE_SETUP(op) \ + do { DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2, op); } while (0) +#define DTRACE_INVOKE_SETUP_BY_NAME(op) \ + struct t_data *d = (struct t_data *) data ; \ + DTRACE_INVOKE_SETUP(op) +#define DTRACE_INVOKE_RETURN(op) \ + do { DTRACE3(efile_drv_int_return, d->sched_i1, d->sched_i2, \ + op); } while (0) ; gcc_optimizer_hack++ ; + +/* Assign human-friendlier id numbers to scheduler & I/O worker threads */ +int dt_driver_idnum = 0; +int dt_driver_io_worker_base = 5000; +erts_mtx_t dt_driver_mutex; +pthread_key_t dt_driver_key; + +typedef struct { + int thread_num; + Uint64 tag; +} dt_private; + +dt_private *get_dt_private(int); +#else /* HAVE_DTRACE */ +typedef struct { +} dt_private; + +#define DTRACE_INVOKE_SETUP(op) do {} while (0) +#define DTRACE_INVOKE_SETUP_BY_NAME(op) do {} while (0) +#define DTRACE_INVOKE_RETURN(op) do {} while (0) +#endif /* HAVE_DTRACE */ /* #define TRACE 1 */ #ifdef TRACE @@ -289,6 +325,10 @@ typedef struct { ErlDrvPDL q_mtx; /* Mutex for the driver queue, known by the emulator. Also used for mutual exclusion when accessing field(s) below. */ size_t write_buffered; +#ifdef HAVE_DTRACE + int idnum; /* Unique ID # for this driver thread/desc */ + char port_str[DTRACE_TERM_BUF_SIZE]; +#endif } file_descriptor; @@ -386,6 +426,13 @@ struct t_data void (*free)(void *); int again; int reply; +#ifdef HAVE_DTRACE + int sched_i1; + Uint64 sched_i2; + char sched_utag[128+1]; +#else + char sched_utag[1]; +#endif int result_ok; Efile_error errInfo; int flags; @@ -458,8 +505,6 @@ struct t_data char b[1]; }; - - #define EF_ALLOC(S) driver_alloc((S)) #define EF_REALLOC(P, S) driver_realloc((P), (S)) #define EF_SAFE_ALLOC(S) ef_safe_alloc((S)) @@ -488,7 +533,7 @@ static void *ef_safe_realloc(void *op, Uint s) * ErlIOVec manipulation functions. */ -/* char EV_CHAR(ErlIOVec *ev, int p, int q) */ +/* char EV_CHAR_P(ErlIOVec *ev, int p, int q) */ #define EV_CHAR_P(ev, p, q) \ (((char *)(ev)->iov[(q)].iov_base) + (p)) @@ -683,6 +728,11 @@ file_init(void) : 0); driver_system_info(&sys_info, sizeof(ErlDrvSysInfo)); +#ifdef HAVE_DTRACE + erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex"); + pthread_key_create(&dt_driver_key, NULL); +#endif /* HAVE_DTRACE */ + return 0; } @@ -722,6 +772,10 @@ file_start(ErlDrvPort port, char* command) desc->write_error = 0; MUTEX_INIT(desc->q_mtx, port); /* Refc is one, referenced by emulator now */ desc->write_buffered = 0; +#ifdef HAVE_DTRACE + dtrace_drvport_str(port, desc->port_str); + get_dt_private(0); /* throw away return value */ +#endif /* HAVE_DTRACE */ return (ErlDrvData) desc; } @@ -741,8 +795,10 @@ static void do_close(int flags, SWord fd) { static void invoke_close(void *data) { struct t_data *d = (struct t_data *) data; + DTRACE_INVOKE_SETUP(FILE_CLOSE); d->again = 0; do_close(d->flags, d->fd); + DTRACE_INVOKE_RETURN(FILE_CLOSE); } /********************************************************************* @@ -972,49 +1028,63 @@ static void invoke_name(void *data, int (*f)(Efile_error *, char *)) static void invoke_mkdir(void *data) { + DTRACE_INVOKE_SETUP_BY_NAME(FILE_MKDIR); invoke_name(data, efile_mkdir); + DTRACE_INVOKE_RETURN(FILE_MKDIR); } static void invoke_rmdir(void *data) { + DTRACE_INVOKE_SETUP_BY_NAME(FILE_RMDIR); invoke_name(data, efile_rmdir); + DTRACE_INVOKE_RETURN(FILE_RMDIR); } static void invoke_delete_file(void *data) { + DTRACE_INVOKE_SETUP_BY_NAME(FILE_DELETE); invoke_name(data, efile_delete_file); + DTRACE_INVOKE_RETURN(FILE_DELETE); } static void invoke_chdir(void *data) { + DTRACE_INVOKE_SETUP_BY_NAME(FILE_CHDIR); invoke_name(data, efile_chdir); + DTRACE_INVOKE_RETURN(FILE_CHDIR); } static void invoke_fdatasync(void *data) { struct t_data *d = (struct t_data *) data; int fd = (int) d->fd; + DTRACE_INVOKE_SETUP(FILE_FDATASYNC); d->again = 0; d->result_ok = efile_fdatasync(&d->errInfo, fd); + DTRACE_INVOKE_RETURN(FILE_FDATASYNC); } static void invoke_fsync(void *data) { struct t_data *d = (struct t_data *) data; int fd = (int) d->fd; + DTRACE_INVOKE_SETUP(FILE_FSYNC); d->again = 0; d->result_ok = efile_fsync(&d->errInfo, fd); + DTRACE_INVOKE_RETURN(FILE_FSYNC); } static void invoke_truncate(void *data) { struct t_data *d = (struct t_data *) data; int fd = (int) d->fd; + DTRACE_INVOKE_SETUP(FILE_TRUNCATE); d->again = 0; d->result_ok = efile_truncate_file(&d->errInfo, &fd, d->flags); + DTRACE_INVOKE_RETURN(FILE_TRUNCATE); } static void invoke_read(void *data) @@ -1022,6 +1092,7 @@ static void invoke_read(void *data) struct t_data *d = (struct t_data *) data; int status, segment; size_t size, read_size; + DTRACE_INVOKE_SETUP(FILE_READ); segment = d->again && d->c.read.bin_size >= 2*FILE_SEGMENT_READ; if (segment) { @@ -1056,6 +1127,7 @@ static void invoke_read(void *data) } else { d->again = 0; } + DTRACE_INVOKE_RETURN(FILE_READ); } static void free_read(void *data) @@ -1072,6 +1144,7 @@ static void invoke_read_line(void *data) int status; size_t read_size; int local_loop = (d->again == 0); + DTRACE_INVOKE_SETUP(FILE_READ_LINE); do { size_t size = (d->c.read_line.binp)->orig_size - @@ -1163,6 +1236,7 @@ static void invoke_read_line(void *data) break; } } while (local_loop); + DTRACE_INVOKE_RETURN(FILE_READ_LINE); } static void free_read_line(void *data) @@ -1178,6 +1252,7 @@ static void invoke_read_file(void *data) struct t_data *d = (struct t_data *) data; size_t read_size; int chop; + DTRACE_INVOKE_SETUP(FILE_READ_FILE); if (! d->c.read_file.binp) { /* First invocation only */ int fd; @@ -1214,12 +1289,14 @@ static void invoke_read_file(void *data) &read_size); if (d->result_ok) { d->c.read_file.offset += read_size; - if (chop) return; /* again */ + if (chop) goto chop_done; /* again */ } close: efile_closefile((int) d->fd); done: d->again = 0; + chop_done: + DTRACE_INVOKE_RETURN(FILE_READ_FILE); } static void free_read_file(void *data) @@ -1239,6 +1316,7 @@ static void invoke_preadv(void *data) ErlIOVec *ev = &c->eiov; size_t bytes_read_so_far = 0; unsigned char *p = (unsigned char *)ev->iov[0].iov_base + 4+4+8*c->cnt; + DTRACE_INVOKE_SETUP(FILE_PREADV); while (c->cnt < c->n) { size_t read_size = ev->iov[1 + c->cnt].iov_len - c->size; @@ -1260,7 +1338,7 @@ static void invoke_preadv(void *data) bytes_read_so_far += bytes_read; if (chop && bytes_read == read_size) { c->size += bytes_read; - return; + goto done; } ASSERT(bytes_read <= read_size); ev->iov[1 + c->cnt].iov_len = bytes_read + c->size; @@ -1271,7 +1349,7 @@ static void invoke_preadv(void *data) if (d->again && bytes_read_so_far >= FILE_SEGMENT_READ && c->cnt < c->n) { - return; + goto done; } } else { /* In case of a read error, ev->size will not be correct, @@ -1282,6 +1360,8 @@ static void invoke_preadv(void *data) } } d->again = 0; + done: + DTRACE_INVOKE_RETURN(FILE_PREADV); } static void free_preadv(void *data) { @@ -1303,6 +1383,7 @@ static void invoke_ipread(void *data) size_t bytes_read = 0; char buf[2*sizeof(Uint32)]; Uint32 offset, size; + DTRACE_INVOKE_SETUP(FILE_IPREAD); /* Read indirection header */ if (! efile_pread(&d->errInfo, (int) d->fd, c->offsets[0], @@ -1341,14 +1422,17 @@ static void invoke_ipread(void *data) /* Read data block */ d->invoke = invoke_preadv; invoke_preadv(data); + DTRACE_INVOKE_RETURN(FILE_IPREAD); return; error: d->result_ok = 0; d->again = 0; + DTRACE_INVOKE_RETURN(FILE_IPREAD); return; done: d->result_ok = !0; d->again = 0; + DTRACE_INVOKE_RETURN(FILE_IPREAD); } /* invoke_writev and invoke_pwritev are the only thread functions that @@ -1371,6 +1455,7 @@ static void invoke_writev(void *data) { size_t size; size_t p; int segment; + DTRACE_INVOKE_SETUP(FILE_WRITE); segment = d->again && d->c.writev.size >= 2*FILE_SEGMENT_WRITE; if (segment) { @@ -1444,6 +1529,7 @@ static void invoke_writev(void *data) { TRACE_F(("w%lu", (unsigned long)size)); } + DTRACE_INVOKE_RETURN(FILE_WRITE); } static void free_writev(void *data) { @@ -1457,34 +1543,40 @@ static void free_writev(void *data) { static void invoke_pwd(void *data) { struct t_data *d = (struct t_data *) data; + DTRACE_INVOKE_SETUP(FILE_PWD); d->again = 0; d->result_ok = efile_getdcwd(&d->errInfo,d->drive, d->b+1, RESBUFSIZE-1); + DTRACE_INVOKE_RETURN(FILE_PWD); } static void invoke_readlink(void *data) { struct t_data *d = (struct t_data *) data; char resbuf[RESBUFSIZE]; /* Result buffer. */ + DTRACE_INVOKE_SETUP(FILE_READLINK); d->again = 0; d->result_ok = efile_readlink(&d->errInfo, d->b, resbuf+1, RESBUFSIZE-1); if (d->result_ok != 0) FILENAME_COPY((char *) d->b + 1, resbuf+1); + DTRACE_INVOKE_RETURN(FILE_READLINK); } static void invoke_altname(void *data) { struct t_data *d = (struct t_data *) data; char resbuf[RESBUFSIZE]; /* Result buffer. */ + DTRACE_INVOKE_SETUP(FILE_ALTNAME); d->again = 0; d->result_ok = efile_altname(&d->errInfo, d->b, resbuf+1, RESBUFSIZE-1); if (d->result_ok != 0) FILENAME_COPY((char *) d->b + 1, resbuf+1); + DTRACE_INVOKE_RETURN(FILE_ALTNAME); } static void invoke_pwritev(void *data) { @@ -1497,6 +1589,7 @@ static void invoke_pwritev(void *data) { size_t p; int segment; size_t size, write_size; + DTRACE_INVOKE_SETUP(FILE_PWRITEV); segment = d->again && c->size >= 2*FILE_SEGMENT_WRITE; if (segment) { @@ -1576,6 +1669,7 @@ static void invoke_pwritev(void *data) { } done: EF_FREE(iov); /* Free our copy of the vector, nothing to restore */ + DTRACE_INVOKE_RETURN(FILE_PWRITEV); } static void free_pwritev(void *data) { @@ -1591,9 +1685,14 @@ static void invoke_flstat(void *data) { struct t_data *d = (struct t_data *) data; + DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2, + d->command == FILE_LSTAT ? FILE_LSTAT : FILE_FSTAT); d->again = 0; d->result_ok = efile_fileinfo(&d->errInfo, &d->info, d->b, d->command == FILE_LSTAT); + DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2, + d->command == FILE_LSTAT ? FILE_LSTAT : FILE_FSTAT); + gcc_optimizer_hack++; } static void invoke_link(void *data) @@ -1601,10 +1700,12 @@ static void invoke_link(void *data) struct t_data *d = (struct t_data *) data; char *name = d->b; char *new_name; + DTRACE_INVOKE_SETUP(FILE_LINK); d->again = 0; new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE; d->result_ok = efile_link(&d->errInfo, name, new_name); + DTRACE_INVOKE_RETURN(FILE_LINK); } static void invoke_symlink(void *data) @@ -1612,10 +1713,12 @@ static void invoke_symlink(void *data) struct t_data *d = (struct t_data *) data; char *name = d->b; char *new_name; + DTRACE_INVOKE_SETUP(FILE_SYMLINK); d->again = 0; new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE; d->result_ok = efile_symlink(&d->errInfo, name, new_name); + DTRACE_INVOKE_RETURN(FILE_SYMLINK); } static void invoke_rename(void *data) @@ -1623,24 +1726,29 @@ static void invoke_rename(void *data) struct t_data *d = (struct t_data *) data; char *name = d->b; char *new_name; + DTRACE_INVOKE_SETUP(FILE_RENAME); d->again = 0; new_name = name+FILENAME_BYTELEN(name)+FILENAME_CHARSIZE; d->result_ok = efile_rename(&d->errInfo, name, new_name); + DTRACE_INVOKE_RETURN(FILE_RENAME); } static void invoke_write_info(void *data) { struct t_data *d = (struct t_data *) data; + DTRACE_INVOKE_SETUP(FILE_WRITE_INFO); d->again = 0; d->result_ok = efile_write_info(&d->errInfo, &d->info, d->b); + DTRACE_INVOKE_RETURN(FILE_WRITE_INFO); } static void invoke_lseek(void *data) { struct t_data *d = (struct t_data *) data; int status; + DTRACE_INVOKE_SETUP(FILE_LSEEK); d->again = 0; if (d->flags & EFILE_COMPRESSED) { @@ -1665,6 +1773,7 @@ static void invoke_lseek(void *data) &d->c.lseek.location); } d->result_ok = status; + DTRACE_INVOKE_RETURN(FILE_LSEEK); } static void invoke_readdir(void *data) @@ -1675,6 +1784,7 @@ static void invoke_readdir(void *data) size_t n = 0, total = 0; struct t_readdir_buf *b = NULL; int res = 0; + DTRACE_INVOKE_SETUP(FILE_READDIR); d->again = 0; d->errInfo.posix_errno = 0; @@ -1710,13 +1820,14 @@ static void invoke_readdir(void *data) } while(res); d->result_ok = (d->errInfo.posix_errno == 0); + DTRACE_INVOKE_RETURN(FILE_READDIR); } static void invoke_open(void *data) { struct t_data *d = (struct t_data *) data; - int status = 1; /* Status of open call. */ + DTRACE_INVOKE_SETUP(FILE_OPEN); d->again = 0; if ((d->flags & EFILE_COMPRESSED) == 0) { @@ -1749,6 +1860,7 @@ static void invoke_open(void *data) } d->result_ok = status; + DTRACE_INVOKE_RETURN(FILE_OPEN); } static void invoke_fadvise(void *data) @@ -1758,9 +1870,11 @@ static void invoke_fadvise(void *data) off_t offset = (off_t) d->c.fadvise.offset; off_t length = (off_t) d->c.fadvise.length; int advise = (int) d->c.fadvise.advise; + DTRACE_INVOKE_SETUP(FILE_FADVISE); d->again = 0; d->result_ok = efile_fadvise(&d->errInfo, fd, offset, length, advise); + DTRACE_INVOKE_RETURN(FILE_FADVISE); } #ifdef HAVE_SENDFILE @@ -1841,6 +1955,7 @@ static void free_readdir(void *data) { struct t_data *d = (struct t_data *) data; struct t_readdir_buf *b1 = d->c.read_dir.first_buf; + while (b1) { struct t_readdir_buf *b2 = b1; b1 = b1->next; @@ -1909,12 +2024,13 @@ static void cq_execute(file_descriptor *desc) { DRIVER_ASYNC(d->level, desc, d->invoke, void_ptr=d, d->free); } -static int async_write(file_descriptor *desc, int *errp, - int reply, Uint32 reply_size) { +static struct t_data *async_write(file_descriptor *desc, int *errp, + int reply, Uint32 reply_size, + Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3) { struct t_data *d; if (! (d = EF_ALLOC(sizeof(struct t_data) - 1))) { if (errp) *errp = ENOMEM; - return -1; + return NULL; } TRACE_F(("w%lu", (unsigned long)desc->write_buffered)); d->command = FILE_WRITE; @@ -1923,6 +2039,11 @@ static int async_write(file_descriptor *desc, int *errp, d->c.writev.port = desc->port; d->c.writev.q_mtx = desc->q_mtx; d->c.writev.size = desc->write_buffered; + if (dt_i1 != NULL) { + *dt_i1 = d->fd; + *dt_i2 = d->flags; + *dt_i3 = d->c.writev.size; + } d->reply = reply; d->c.writev.free_size = 0; d->c.writev.reply_size = reply_size; @@ -1931,18 +2052,41 @@ static int async_write(file_descriptor *desc, int *errp, d->level = 1; cq_enq(desc, d); desc->write_buffered = 0; - return 0; + return d; } -static int flush_write(file_descriptor *desc, int *errp) { - int result; +static int flush_write(file_descriptor *desc, int *errp, + dt_private *dt_priv, char *dt_utag) { + int result = 0; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; + struct t_data *d = NULL; + MUTEX_LOCK(desc->q_mtx); if (desc->write_buffered > 0) { - result = async_write(desc, errp, 0, 0); - } else { - result = 0; + if ((d = async_write(desc, errp, 0, 0, + &dt_i1, &dt_i2, &dt_i3)) == NULL) { + result = -1; + } } MUTEX_UNLOCK(desc->q_mtx); +#ifdef HAVE_DTRACE + if (d != NULL) { + d->sched_i1 = dt_priv->thread_num; + d->sched_i2 = dt_priv->tag; + d->sched_utag[0] = '\0'; + if (dt_utag != NULL) { + if (dt_utag[0] == '\0') { + dt_utag = NULL; + } else { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } + } + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, FILE_WRITE, + NULL, NULL, dt_i1, dt_i2, dt_i3, 0, desc->port_str); + } +#endif /* HAVE_DTRACE */ return result; } @@ -1955,9 +2099,10 @@ static int check_write_error(file_descriptor *desc, int *errp) { return 0; } -static int flush_write_check_error(file_descriptor *desc, int *errp) { +static int flush_write_check_error(file_descriptor *desc, int *errp, + dt_private *dt_priv, char *dt_utag) { int r; - if ( (r = flush_write(desc, errp)) != 0) { + if ( (r = flush_write(desc, errp, dt_priv, dt_utag)) != 0) { check_write_error(desc, NULL); return r; } else { @@ -1965,12 +2110,13 @@ static int flush_write_check_error(file_descriptor *desc, int *errp) { } } -static int async_lseek(file_descriptor *desc, int *errp, int reply, - Sint64 offset, int origin) { +static struct t_data *async_lseek(file_descriptor *desc, int *errp, int reply, + Sint64 offset, int origin, + Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3) { struct t_data *d; if (! (d = EF_ALLOC(sizeof(struct t_data)))) { *errp = ENOMEM; - return -1; + return NULL; } d->flags = desc->flags; d->fd = desc->fd; @@ -1978,11 +2124,16 @@ static int async_lseek(file_descriptor *desc, int *errp, int reply, d->reply = reply; d->c.lseek.offset = offset; d->c.lseek.origin = origin; + if (dt_i1 != NULL) { + *dt_i1 = d->fd; + *dt_i2 = d->c.lseek.offset; + *dt_i3 = d->c.lseek.origin; + } d->invoke = invoke_lseek; d->free = free_data; d->level = 1; cq_enq(desc, d); - return 0; + return d; } static void flush_read(file_descriptor *desc) { @@ -1994,18 +2145,37 @@ static void flush_read(file_descriptor *desc) { } } -static int lseek_flush_read(file_descriptor *desc, int *errp) { +static int lseek_flush_read(file_descriptor *desc, int *errp, + dt_private *dt_priv, char *dt_utag) { int r = 0; size_t read_size = desc->read_size; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; + struct t_data *d; + + flush_read(desc); if (read_size != 0) { - flush_read(desc); - if ((r = async_lseek(desc, errp, 0, - -((ssize_t)read_size), EFILE_SEEK_CUR)) - < 0) { - return r; - } - } else { - flush_read(desc); + if ((d = async_lseek(desc, errp, 0, + -((ssize_t)read_size), EFILE_SEEK_CUR, + &dt_i1, &dt_i2, &dt_i3)) == NULL) { + r = -1; + } else { +#ifdef HAVE_DTRACE + d->sched_i1 = dt_priv->thread_num; + d->sched_i2 = dt_priv->tag; + d->sched_utag[0] = '\0'; + if (dt_utag != NULL) { + if (dt_utag[0] == '\0') { + dt_utag = NULL; + } else { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } + } + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, FILE_LSEEK, + NULL, NULL, dt_i1, dt_i2, dt_i3, 0, desc->port_str); +#endif /* HAVE_DTRACE */ + } } return r; } @@ -2022,11 +2192,23 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) struct t_data *d = (struct t_data *) data; char header[5]; /* result code + count */ char resbuf[RESBUFSIZE]; /* Result buffer. */ - +#ifdef HAVE_DTRACE + int sched_i1 = d->sched_i1, sched_i2 = d->sched_i2, command = d->command, + result_ok = d->result_ok, + posix_errno = d->result_ok ? 0 : d->errInfo.posix_errno; + DTRACE_CHARBUF(sched_utag, 128+1); + + sched_utag[0] = '\0'; + if (DTRACE_ENABLED(efile_drv_return)) { + strncpy(sched_utag, d->sched_utag, sizeof(sched_utag) - 1); + sched_utag[sizeof(sched_utag) - 1] = '\0'; + } +#endif /* HAVE_DTRACE */ TRACE_C('r'); if (try_again(desc, d)) { + /* DTRACE TODO: what kind of probe makes sense here? */ return; } @@ -2224,6 +2406,9 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) if (d->reply) { TRACE_C('K'); reply_ok(desc); +#ifdef HAVE_DTRACE + result_ok = 1; +#endif } free_data(data); break; @@ -2279,6 +2464,8 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) default: abort(); } + DTRACE6(efile_drv_return, sched_i1, sched_i2, sched_utag, + command, result_ok, posix_errno); if (desc->write_buffered != 0 && desc->timer_state == timer_idle) { desc->timer_state = timer_write; driver_set_timer(desc->port, desc->write_delay); @@ -2301,7 +2488,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) char* name; /* Points to the filename in buf. */ int command; struct t_data *d = NULL; - + char *dt_utag = NULL, *dt_s1 = NULL, *dt_s2 = NULL; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0, dt_i4 = 0; +#ifdef HAVE_DTRACE + dt_private *dt_priv = get_dt_private(0); +#endif /* HAVE_DTRACE */ TRACE_C('o'); @@ -2316,6 +2507,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_mkdir; d->free = free_data; @@ -2327,6 +2520,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_rmdir; d->free = free_data; @@ -2338,6 +2533,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_delete_file; d->free = free_data; @@ -2354,7 +2551,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); + dt_s2 = d->b + namelen; + dt_utag = buf + namelen + strlen(dt_s2) + 1; d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2368,6 +2568,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_chdir; d->free = free_data; @@ -2379,6 +2581,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); d->drive = *(uchar*)buf; + dt_utag = buf + 1; d->command = command; d->invoke = invoke_pwd; d->free = free_data; @@ -2394,6 +2597,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->dir_handle = NULL; d->command = command; d->invoke = invoke_readdir; @@ -2418,6 +2623,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) dir_handle = NULL; resbuf[0] = FILE_RESP_LFNAME; + dt_s1 = name; + dt_utag = name + strlen(dt_s1) + 1; + /* Fill the buffer with multiple directory listings before sending it to the * receiving process. READDIR_CHUNKS is minimum number of files sent to the * receiver. @@ -2451,6 +2659,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) reply_error(desc, &errInfo); return; } +#ifdef HAVE_DTRACE + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, command, name, dt_s2, + dt_i1, dt_i2, dt_i3, dt_i4, desc->port_str); +#endif TRACE_C('R'); driver_output2(desc->port, resbuf, 1, NULL, 0); return; @@ -2461,8 +2674,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); d->flags = get_int32((uchar*)buf); + dt_i1 = d->flags; name = buf+4; FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_open; d->free = free_data; @@ -2474,7 +2690,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); + dt_utag = name; d->fd = fd; + dt_i1 = fd; d->command = command; d->invoke = invoke_fdatasync; d->free = free_data; @@ -2486,7 +2704,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); + dt_utag = name; d->fd = fd; + dt_i1 = fd; d->command = command; d->invoke = invoke_fsync; d->free = free_data; @@ -2502,7 +2722,13 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_utag = name + strlen(d->b) + 1; d->fd = fd; + if (command == FILE_LSTAT) { + dt_s1 = d->b; + } else { + dt_i1 = fd; + } d->command = command; d->invoke = invoke_flstat; d->free = free_data; @@ -2514,8 +2740,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); + dt_utag = name; d->flags = desc->flags; d->fd = fd; + dt_i1 = fd; + dt_i2 = d->flags; d->command = command; d->invoke = invoke_truncate; d->free = free_data; @@ -2529,13 +2758,18 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE); d->info.mode = get_int32(buf + 0 * 4); + dt_i1 = d->info.mode; d->info.uid = get_int32(buf + 1 * 4); + dt_i2 = d->info.uid; d->info.gid = get_int32(buf + 2 * 4); + dt_i3 = d->info.gid; d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4)); d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4)); d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4)); FILENAME_COPY(d->b, buf + 9*4); + dt_s1 = d->b; + dt_utag = buf + 9 * 4 + strlen(d->b) + 1; d->command = command; d->invoke = invoke_write_info; d->free = free_data; @@ -2548,6 +2782,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_readlink; d->free = free_data; @@ -2559,6 +2795,8 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); FILENAME_COPY(d->b, name); + dt_s1 = d->b; + dt_utag = name + strlen(d->b) + 1; d->command = command; d->invoke = invoke_altname; d->free = free_data; @@ -2578,7 +2816,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); + dt_s2 = d->b + namelen; + dt_utag = buf + namelen + strlen(dt_s2) + 1; d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2599,7 +2840,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); + dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); + dt_s2 = d->b + namelen; + dt_utag = buf + namelen + strlen(dt_s2) + 1; d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2614,13 +2858,18 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data)); d->fd = fd; + dt_i1 = d->fd; d->command = command; d->invoke = invoke_fadvise; d->free = free_data; d->level = 2; d->c.fadvise.offset = get_int64((uchar*) buf); + dt_i2 = d->c.fadvise.offset; d->c.fadvise.length = get_int64(((uchar*) buf) + sizeof(Sint64)); + dt_i3 = d->c.fadvise.length; d->c.fadvise.advise = get_int32(((uchar*) buf) + 2 * sizeof(Sint64)); + dt_i4 = d->c.fadvise.advise; + dt_utag = buf + 3 * sizeof(Sint64); goto done; } @@ -2634,6 +2883,22 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) done: if (d) { +#ifdef HAVE_DTRACE + d->sched_i1 = dt_priv->thread_num; + d->sched_i2 = dt_priv->tag; + d->sched_utag[0] = '\0'; + if (dt_utag != NULL) { + if (dt_utag[0] == '\0') { + dt_utag = NULL; + } else { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } + } + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, command, dt_s1, dt_s2, + dt_i1, dt_i2, dt_i3, dt_i4, desc->port_str); +#endif cq_enq(desc, d); } } @@ -2647,6 +2912,11 @@ file_flush(ErlDrvData e) { #ifdef DEBUG int r; #endif +#ifdef HAVE_DTRACE + dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); +#else + dt_private *dt_priv = NULL; +#endif TRACE_C('f'); @@ -2657,7 +2927,8 @@ file_flush(ErlDrvData e) { #ifdef DEBUG r = #endif - flush_write(desc, NULL); + flush_write(desc, NULL, dt_priv, + (desc->d == NULL) ? NULL : desc->d->sched_utag); /* Only possible reason for bad return value is ENOMEM, and * there is nobody to tell... */ @@ -2699,6 +2970,11 @@ static void file_timeout(ErlDrvData e) { file_descriptor *desc = (file_descriptor *)e; enum e_timer timer_state = desc->timer_state; +#ifdef HAVE_DTRACE + dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); +#else + dt_private *dt_priv = NULL; +#endif TRACE_C('t'); @@ -2716,7 +2992,8 @@ file_timeout(ErlDrvData e) { #ifdef DEBUG int r = #endif - flush_write(desc, NULL); + flush_write(desc, NULL, dt_priv, + (desc->d == NULL) ? NULL : desc->d->sched_utag); /* Only possible reason for bad return value is ENOMEM, and * there is nobody to tell... */ @@ -2737,7 +3014,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { char command; int p, q; int err; - + struct t_data *d = NULL; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0, dt_i4 = 0; + char *dt_utag = NULL, *dt_s1 = NULL; +#ifdef HAVE_DTRACE + dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); +#else + dt_private *dt_priv = NULL; +#endif TRACE_C('v'); p = 0; q = 1; @@ -2756,25 +3040,22 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { switch (command) { case FILE_CLOSE: { + dt_utag = EV_CHAR_P(ev, p, q); flush_read(desc); - if (flush_write_check_error(desc, &err) < 0) { + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size != 1) { - /* Wrong command length */ - reply_posix_error(desc, EINVAL); - goto done; - } if (desc->fd != FILE_FD_INVALID) { - struct t_data *d; if (! (d = EF_ALLOC(sizeof(struct t_data)))) { reply_posix_error(desc, ENOMEM); } else { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->invoke = invoke_close; d->free = free_data; d->level = 2; @@ -2790,8 +3071,15 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_READ: { Uint32 sizeH, sizeL; size_t size, alloc_size; - struct t_data *d; - if (flush_write_check_error(desc, &err) < 0) { + + if (!EV_GET_UINT32(ev, &sizeH, &p, &q) + || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { + /* Wrong buffer length to contain the read count */ + reply_posix_error(desc, EINVAL); + goto done; + } + dt_utag = EV_CHAR_P(ev, p, q); + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } @@ -2799,19 +3087,12 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { if (desc->read_bufsize == 0 && desc->read_binp != NULL && desc->read_size > 0) { /* We have allocated a buffer for line mode but should not really have a read-ahead buffer... */ - if (lseek_flush_read(desc, &err) < 0) { + if (lseek_flush_read(desc, &err, dt_priv) < 0) { reply_posix_error(desc, err); goto done; } } #endif - if (ev->size != 1+8 - || !EV_GET_UINT32(ev, &sizeH, &p, &q) - || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { - /* Wrong buffer length to contain the read count */ - reply_posix_error(desc, EINVAL); - goto done; - } #if SIZEOF_SIZE_T == 4 if (sizeH != 0) { reply_posix_error(desc, EINVAL); @@ -2882,11 +3163,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.read.binp = desc->read_binp; d->c.read.bin_offset = desc->read_offset + desc->read_size; d->c.read.bin_size = desc->read_binp->orig_size - d->c.read.bin_offset; d->c.read.size = size; + dt_i3 = d->c.read.size; driver_binary_inc_refc(d->c.read.binp); d->invoke = invoke_read; d->free = free_read; @@ -2904,12 +3188,12 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { * allocated binary + dealing with offsets and lengts are done in file_async ready * for this OP. */ - struct t_data *d; - if (flush_write_check_error(desc, &err) < 0) { + dt_utag = EV_CHAR_P(ev, p, q); + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size != 1) { + if (ev->size != 1+strlen(dt_utag)+1) { /* Wrong command length */ reply_posix_error(desc, EINVAL); goto done; @@ -2961,13 +3245,17 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.read_line.binp = desc->read_binp; d->c.read_line.read_offset = desc->read_offset; d->c.read_line.read_size = desc->read_size; + dt_i3 = d->c.read_line.read_offset; #if !ALWAYS_READ_LINE_AHEAD d->c.read_line.read_ahead = (desc->read_bufsize > 0); #endif + dt_i4 = d->c.read_line.read_ahead; driver_binary_inc_refc(d->c.read.binp); d->invoke = invoke_read_line; d->free = free_read_line; @@ -2977,7 +3265,21 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_WRITE: { ErlDrvSizeT skip = 1; ErlDrvSizeT size = ev->size - skip; - if (lseek_flush_read(desc, &err) < 0) { + + dt_utag = EV_CHAR_P(ev, p, q); + skip += strlen(dt_utag) + 1; + size = ev->size - skip; + /* + * Interesting dependency on using port # for key to async + * I/O worker pool thread: lseek_flush_read() can enqueue a + * lseek() op. If that lseek() were scheduled on a different + * thread than the write that we'll enqueue later in this case, + * then Bad Things could happen. This DTrace work is probably + * well worthwhile to get a sense of how often there's head-of- + * line blocking/unfairness during busy file I/O because of the + * mapping of port #/key -> thread. + */ + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } @@ -3004,7 +3306,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { driver_set_timer(desc->port, desc->write_delay); } } else { - if (async_write(desc, &err, !0, size) != 0) { + if ((d = async_write(desc, &err, !0, size, + &dt_i1, &dt_i2, &dt_i3)) == NULL) { MUTEX_UNLOCK(desc->q_mtx); reply_posix_error(desc, err); goto done; @@ -3017,19 +3320,25 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_PWRITEV: { Uint32 i, j, n; size_t total; - struct t_data *d; - if (lseek_flush_read(desc, &err) < 0) { - reply_Uint_posix_error(desc, 0, err); + char tmp; + int dt_utag_bytes = 1; + + dt_utag = EV_CHAR_P(ev, p, q); + while (EV_GET_CHAR(ev, &tmp, &p, &q) && tmp != '\0') { + dt_utag_bytes++; + } + if (ev->size < 1+4+dt_utag_bytes + || !EV_GET_UINT32(ev, &n, &p, &q)) { + /* Buffer too short to contain even the number of pos/size specs */ + reply_Uint_posix_error(desc, 0, EINVAL); goto done; } - if (flush_write_check_error(desc, &err) < 0) { + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_Uint_posix_error(desc, 0, err); goto done; } - if (ev->size < 1+4 - || !EV_GET_UINT32(ev, &n, &p, &q)) { - /* Buffer too short to contain even the number of pos/size specs */ - reply_Uint_posix_error(desc, 0, EINVAL); + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + reply_Uint_posix_error(desc, 0, err); goto done; } if (n == 0) { @@ -3041,7 +3350,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } goto done; } - if (ev->size < 1+4+8*(2*n)) { + if (ev->size < 1+4+8*(2*n)+dt_utag_bytes) { /* Buffer too short to contain even the pos/size specs */ reply_Uint_posix_error(desc, 0, EINVAL); goto done; @@ -3055,7 +3364,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.pwritev.port = desc->port; d->c.pwritev.q_mtx = desc->q_mtx; d->c.pwritev.n = n; @@ -3093,13 +3404,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } } d->c.pwritev.size = total; + dt_i3 = d->c.pwritev.size; d->c.pwritev.free_size = 0; if (j == 0) { /* Trivial case - nothing to write */ EF_FREE(d); reply_Uint(desc, 0); } else { - ErlDrvSizeT skip = 1 + 4 + 8*(2*n); + ErlDrvSizeT skip = 1 + 4 + 8 * (2*n) + dt_utag_bytes; if (skip + total != ev->size) { /* Actual amount of data does not match * total of all pos/size specs @@ -3123,24 +3435,30 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_PREADV: { register void * void_ptr; Uint32 i, n; - struct t_data *d; ErlIOVec *res_ev; - if (lseek_flush_read(desc, &err) < 0) { + char tmp; + int dt_utag_bytes = 1; + + dt_utag = EV_CHAR_P(ev, p, q); + while (EV_GET_CHAR(ev, &tmp, &p, &q) && tmp != '\0') { + dt_utag_bytes++; + } + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (flush_write_check_error(desc, &err) < 0) { + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size < 1+8 + if (ev->size < 1+8+dt_utag_bytes || !EV_GET_UINT32(ev, &n, &p, &q) || !EV_GET_UINT32(ev, &n, &p, &q)) { /* Buffer too short to contain even the number of pos/size specs */ reply_posix_error(desc, EINVAL); goto done; } - if (ev->size != 1+8+8*(2*n)) { + if (ev->size < 1+8+8*(2*n)+dt_utag_bytes) { /* Buffer wrong length to contain the pos/size specs */ reply_posix_error(desc, EINVAL); goto done; @@ -3159,7 +3477,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.preadv.n = n; d->c.preadv.cnt = 0; d->c.preadv.size = 0; @@ -3187,6 +3507,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else size = ((size_t)sizeH<<32) | sizeL; #endif + dt_i3 += size; if (! (res_ev->binv[i] = driver_alloc_binary(size))) { reply_posix_error(desc, ENOMEM); break; @@ -3233,31 +3554,33 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } goto done; /* case FILE_PREADV: */ case FILE_LSEEK: { - Sint64 offset; /* Offset for seek */ + Sint64 offset; /* Offset for seek */ Uint32 origin; /* Origin of seek. */ - if (lseek_flush_read(desc, &err) < 0) { - reply_posix_error(desc, err); + + if (ev->size < 1+8+4 + || !EV_GET_UINT64(ev, &offset, &p, &q) + || !EV_GET_UINT32(ev, &origin, &p, &q)) { + /* Wrong length of buffer to contain offset and origin */ + reply_posix_error(desc, EINVAL); goto done; } - if (flush_write_check_error(desc, &err) < 0) { + dt_utag = EV_CHAR_P(ev, p, q); + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size != 1+8+4 - || !EV_GET_UINT64(ev, &offset, &p, &q) - || !EV_GET_UINT32(ev, &origin, &p, &q)) { - /* Wrong length of buffer to contain offset and origin */ - reply_posix_error(desc, EINVAL); + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + reply_posix_error(desc, err); goto done; } - if (async_lseek(desc, &err, !0, offset, origin) < 0) { + if ((d = async_lseek(desc, &err, !0, offset, origin, + &dt_i1, &dt_i2, &dt_i3)) == NULL) { reply_posix_error(desc, err); goto done; } } goto done; case FILE_READ_FILE: { - struct t_data *d; char *filename; if (ev->size < 1+1) { /* Buffer contains empty name */ @@ -3279,6 +3602,8 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->reply = !0; /* Copy name */ FILENAME_COPY(d->b, filename); + dt_s1 = d->b; + dt_utag = filename + strlen(d->b) + 1; d->c.read_file.binp = NULL; d->invoke = invoke_read_file; d->free = free_read_file; @@ -3298,7 +3623,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { char mode; Sint64 hdr_offset; Uint32 max_size; - struct t_data *d; ErlIOVec *res_ev; int vsize; if (! EV_GET_CHAR(ev, &mode, &p, &q)) { @@ -3310,14 +3634,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } - if (lseek_flush_read(desc, &err) < 0) { - reply_posix_error(desc, err); - goto done; - } - if (flush_write_check_error(desc, &err) < 0) { - reply_posix_error(desc, err); - goto done; - } if (ev->size < 1+1+8+4 || !EV_GET_UINT64(ev, &hdr_offset, &p, &q) || !EV_GET_UINT32(ev, &max_size, &p, &q)) { @@ -3326,6 +3642,15 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } + dt_utag = EV_CHAR_P(ev, p, q); + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { + reply_posix_error(desc, err); + goto done; + } + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + reply_posix_error(desc, err); + goto done; + } /* Create the thread data structure with the contained ErlIOVec * and corresponding binaries for the response */ @@ -3339,9 +3664,13 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; + dt_i1 = d->fd; d->flags = desc->flags; + dt_i2 = d->flags; d->c.preadv.offsets[0] = hdr_offset; + dt_i3 = d->c.preadv.offsets[0]; d->c.preadv.size = max_size; + dt_i4 = d->c.preadv.size; res_ev = &d->c.preadv.eiov; /* XXX possible alignment problems here for weird machines */ res_ev->iov = void_ptr = d + 1; @@ -3356,16 +3685,19 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_SETOPT: { char opt; + if (ev->size < 1+1 || !EV_GET_CHAR(ev, &opt, &p, &q)) { /* Buffer too short to contain even the option type */ reply_posix_error(desc, EINVAL); goto done; } + dt_i1 = opt; + dt_utag = EV_CHAR_P(ev, p, q); switch (opt) { case FILE_OPT_DELAYED_WRITE: { Uint32 sizeH, sizeL, delayH, delayL; - if (ev->size != 1+1+4*sizeof(Uint32) + if (ev->size != 1+1+4*sizeof(Uint32)+strlen(dt_utag)+1 || !EV_GET_UINT32(ev, &sizeH, &p, &q) || !EV_GET_UINT32(ev, &sizeL, &p, &q) || !EV_GET_UINT32(ev, &delayH, &p, &q) @@ -3392,12 +3724,13 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else desc->write_delay = ((unsigned long)delayH << 32) | delayL; #endif + dt_i2 = desc->write_delay; TRACE_C('K'); reply_ok(desc); } goto done; case FILE_OPT_READ_AHEAD: { Uint32 sizeH, sizeL; - if (ev->size != 1+1+2*sizeof(Uint32) + if (ev->size != 1+1+2*sizeof(Uint32)+strlen(dt_utag)+1 || !EV_GET_UINT32(ev, &sizeH, &p, &q) || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { /* Buffer has wrong length to contain the option values */ @@ -3413,6 +3746,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else desc->read_bufsize = ((size_t)sizeH << 32) | sizeL; #endif + dt_i2 = desc->read_bufsize; TRACE_C('K'); reply_ok(desc); } goto done; @@ -3499,11 +3833,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } /* switch(command) */ - if (lseek_flush_read(desc, &err) < 0) { + if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } - if (flush_write_check_error(desc, &err) < 0) { + if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { reply_posix_error(desc, err); goto done; } else { @@ -3521,5 +3855,46 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } done: + if (d != NULL) { +#ifdef HAVE_DTRACE + /* + * If d == NULL, then either: + * 1). There was an error of some sort, or + * 2). The command given to us is actually implemented + * by file_output() instead. + * + * Case #1 is probably a TODO item, perhaps? + * Case #2 we definitely don't want to activate a probe. + */ + d->sched_i1 = dt_priv->thread_num; + d->sched_i2 = dt_priv->tag; + d->sched_utag[0] = '\0'; + if (dt_utag != NULL) { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + dt_utag, command, dt_s1, NULL, dt_i1, dt_i2, dt_i3, dt_i4, + desc->port_str); +#endif + } cq_execute(desc); } + +#ifdef HAVE_DTRACE +dt_private * +get_dt_private(int base) +{ + dt_private *dt_priv = (dt_private *) pthread_getspecific(dt_driver_key); + + if (dt_priv == NULL) { + dt_priv = EF_SAFE_ALLOC(sizeof(dt_private)); + erts_mtx_lock(&dt_driver_mutex); + dt_priv->thread_num = (base + dt_driver_idnum++); + erts_mtx_unlock(&dt_driver_mutex); + dt_priv->tag = 0; + pthread_setspecific(dt_driver_key, dt_priv); + } + return dt_priv; +} +#endif /* HAVE_DTRACE */ diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index 87e80aae9b..9d6c47ffc1 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 36cbe329e8..5c9cad3a2c 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -25,39 +25,59 @@ %%% Interface towards a single file's contents. Uses ?FD_DRV. %% Generic file contents operations --export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1, - write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3, - copy/3, sendfile/10]). + +-export([ + open/2, open/3, + close/1, close/2, + datasync/1, datasync/2, + sync/1, sync/2, + advise/4, advise/5, + position/2, position/3, + truncate/1, truncate/2, + write/2, write/3, + pwrite/2, pwrite/3, pwrite/4, + read/2, read/3, + read_line/1, read_line/2, + pread/2, pread/3, pread/4, + copy/3, copy/4, + sendfile/10 + ]). %% Specialized file operations --export([open/1, open/3]). --export([read_file/1, read_file/2, write_file/2]). --export([ipread_s32bu_p32bu/3]). +-export([open/1]). +-export([read_file/1, read_file/2, read_file/3, write_file/2, write_file/3]). +-export([ipread_s32bu_p32bu/3, ipread_s32bu_p32bu/4]). %%% Interface towards file system and metadata. Uses ?DRV. %% Takes an optional port (opens a ?DRV port per default) as first argument. --export([get_cwd/0, get_cwd/1, get_cwd/2, - set_cwd/1, set_cwd/2, - delete/1, delete/2, - rename/2, rename/3, - make_dir/1, make_dir/2, - del_dir/1, del_dir/2, - read_file_info/1, read_file_info/2, read_file_info/3, - altname/1, altname/2, - write_file_info/2, write_file_info/3, write_file_info/4, - make_link/2, make_link/3, - make_symlink/2, make_symlink/3, - read_link/1, read_link/2, - read_link_info/1, read_link_info/2, read_link_info/3, - list_dir/1, list_dir/2]). + +-export([ + get_cwd/0, get_cwd/1, get_cwd/3, + set_cwd/1, set_cwd/3, + delete/1, delete/2, delete/3, + rename/2, rename/3, rename/4, + make_dir/1, make_dir/3, + del_dir/1, del_dir/3, + read_file_info/1, read_file_info/2, read_file_info/3, read_file_info/4, + altname/1, altname/3, + write_file_info/2, write_file_info/4, write_file_info/5, + make_link/2, make_link/3, make_link/4, + make_symlink/2, make_symlink/3, make_symlink/4, + read_link/1, read_link/3, + read_link_info/1, read_link_info/2, read_link_info/3, read_link_info/4, + list_dir/1, list_dir/3 + ]). %% How to start and stop the ?DRV port. -export([start/0, stop/1]). %% Debug exports --export([open_int/4, open_mode/1, open_mode/4]). +-export([open_int/4, open_int/5, open_mode/1, open_mode/4]). + +%% For DTrace/Systemtap tracing +-export([get_dtrace_utag/0]). %%%----------------------------------------------------------------- %%% Includes and defines @@ -155,30 +175,21 @@ %%% Supposed to be called by applications through module file. -%% Opens a file using the driver port Port. Returns {error, Reason} -%% | {ok, FileDescriptor} -open(Port, File, ModeList) when is_port(Port), - (is_list(File) orelse is_binary(File)), - is_list(ModeList) -> - case open_mode(ModeList) of - {Mode, _Portopts, _Setopts} -> - open_int(Port, File, Mode, []); - Reason -> - {error, Reason} - end; -open(_,_,_) -> - {error, badarg}. - %% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}. -open(File, ModeList) when (is_list(File) orelse is_binary(File)), - is_list(ModeList) -> +open(File, ModeList) -> + open(File, ModeList, get_dtrace_utag()). + +open(File, ModeList, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + is_list(ModeList), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> case open_mode(ModeList) of {Mode, Portopts, Setopts} -> - open_int({?FD_DRV, Portopts},File, Mode, Setopts); + open_int({?FD_DRV, Portopts}, File, Mode, Setopts, DTraceUtag); Reason -> {error, Reason} end; -open(_, _) -> +open(_, _, _) -> {error, badarg}. %% Opens a port that can be used for open/3 or read_file/2. @@ -193,29 +204,34 @@ open(Portopts) when is_list(Portopts) -> open(_) -> {error, badarg}. -open_int({Driver, Portopts}, File, Mode, Setopts) -> +open_int(Arg, File, Mode, Setopts) -> + open_int(Arg, File, Mode, Setopts, get_dtrace_utag()). + +open_int({Driver, Portopts}, File, Mode, Setopts, DTraceUtag) -> + %% TODO: add DTraceUtag to drv_open()? case drv_open(Driver, Portopts) of {ok, Port} -> - open_int(Port, File, Mode, Setopts); + open_int(Port, File, Mode, Setopts, DTraceUtag); {error, _} = Error -> Error end; -open_int(Port, File, Mode, Setopts) -> +open_int(Port, File, Mode, Setopts, DTraceUtag) -> M = Mode band ?EFILE_MODE_MASK, - case drv_command(Port, [<>, pathname(File)]) of + case drv_command(Port, [<>, + pathname(File), enc_utag(DTraceUtag)]) of {ok, Number} -> - open_int_setopts(Port, Number, Setopts); + open_int_setopts(Port, Number, Setopts, DTraceUtag); Error -> drv_close(Port), Error end. -open_int_setopts(Port, Number, []) -> +open_int_setopts(Port, Number, [], _DTraceUtag) -> {ok, #file_descriptor{module = ?MODULE, data = {Port, Number}}}; -open_int_setopts(Port, Number, [Cmd | Tail]) -> - case drv_command(Port, Cmd) of +open_int_setopts(Port, Number, [Cmd | Tail], DTraceUtag) -> + case drv_command(Port, [Cmd, enc_utag(DTraceUtag)]) of ok -> - open_int_setopts(Port, Number, Tail); + open_int_setopts(Port, Number, Tail, DTraceUtag); Error -> drv_close(Port), Error @@ -225,50 +241,64 @@ open_int_setopts(Port, Number, [Cmd | Tail]) -> %% Returns ok. -close(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - case drv_command(Port, <>) of +close(Arg) -> + close(Arg, get_dtrace_utag()). + +close(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + case drv_command(Port, [<>, enc_utag(DTraceUtag)]) of ok -> drv_close(Port); Error -> Error end; %% Closes a port opened with open/1. -close(Port) when is_port(Port) -> +close(Port, _DTraceUtag) when is_port(Port) -> drv_close(Port). --define(ADVISE(Offs, Len, Adv), +-define(ADVISE(Offs, Len, Adv, BUtag), <>). + Adv:32/signed, BUtag/binary>>). %% Returns {error, Reason} | ok. +advise(FD, Offset, Length, Advise) -> + advise(FD, Offset, Length, Advise, get_dtrace_utag()). + advise(#file_descriptor{module = ?MODULE, data = {Port, _}}, - Offset, Length, Advise) -> + Offset, Length, Advise, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + BUtag = term_to_binary(enc_utag(DTraceUtag)), case Advise of normal -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL, BUtag), drv_command(Port, Cmd); random -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM, BUtag), drv_command(Port, Cmd); sequential -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL, BUtag), drv_command(Port, Cmd); will_need -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED, BUtag), drv_command(Port, Cmd); dont_need -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED, BUtag), drv_command(Port, Cmd); no_reuse -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE, BUtag), drv_command(Port, Cmd); _ -> {error, einval} end. %% Returns {error, Reason} | ok. -write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> - case drv_command(Port, [?FILE_WRITE,Bytes]) of +write(Desc, Bytes) -> + write(Desc, Bytes, get_dtrace_utag()). + +write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + %% This is rare case where DTraceUtag is not at end of command list. + case drv_command(Port, [?FILE_WRITE,enc_utag(DTraceUtag),Bytes]) of {ok, _Size} -> ok; Error -> @@ -278,39 +308,40 @@ write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> %% Returns ok | {error, {WrittenCount, Reason}} pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) when is_list(L) -> - pwrite_int(Port, L, 0, [], []). + pwrite_int(Port, L, 0, [], [], get_dtrace_utag()). -pwrite_int(_, [], 0, [], []) -> +pwrite_int(_, [], 0, [], [], _DTraceUtag) -> ok; -pwrite_int(Port, [], N, Spec, Data) -> - Header = list_to_binary([<> | reverse(Spec)]), +pwrite_int(Port, [], N, Spec, Data, DTraceUtag) -> + Header = list_to_binary([<>, enc_utag(DTraceUtag), + <>, reverse(Spec)]), case drv_command_raw(Port, [Header | reverse(Data)]) of {ok, _Size} -> ok; Error -> Error end; -pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data) +pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data, DTraceUtag) when is_integer(Offs) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - pwrite_int(Port, T, N, Spec, Data, Offs, Bytes); + pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag); true -> {error, einval} end; -pwrite_int(_, [_|_], _N, _Spec, _Data) -> +pwrite_int(_, [_|_], _N, _Spec, _Data, _DTraceUtag) -> {error, badarg}. -pwrite_int(Port, T, N, Spec, Data, Offs, Bin) +pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag) when is_binary(Bin) -> Size = byte_size(Bin), pwrite_int(Port, T, N+1, [<> | Spec], - [Bin | Data]); -pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) -> + [Bin | Data], DTraceUtag); +pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag) -> try list_to_binary(Bytes) of Bin -> - pwrite_int(Port, T, N, Spec, Data, Offs, Bin) + pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag) catch error:Reason -> {error, Reason} @@ -319,11 +350,28 @@ pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) -> %% Returns {error, Reason} | ok. -pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag) + when is_list(L), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pwrite_int(Port, L, 0, [], [], DTraceUtag); + +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) when is_integer(Offs) -> + pwrite_int2(Port, Offs, Bytes, get_dtrace_utag()); +pwrite(#file_descriptor{module = ?MODULE}, _, _) -> + {error, badarg}. + +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes, DTraceUtag) + when is_integer(Offs), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pwrite_int2(Port, Offs, Bytes, DTraceUtag); +pwrite(#file_descriptor{module = ?MODULE}, _, _, _DTraceUtag) -> + {error, badarg}. + +pwrite_int2(Port, Offs, Bytes, DTraceUtag) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - case pwrite_int(Port, [], 0, [], [], Offs, Bytes) of + case pwrite_int(Port, [], 0, [], [], Offs, Bytes, DTraceUtag) of {error, {_, Reason}} -> {error, Reason}; Result -> @@ -331,22 +379,30 @@ pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) end; true -> {error, einval} - end; -pwrite(#file_descriptor{module = ?MODULE}, _, _) -> - {error, badarg}. - + end. %% Returns {error, Reason} | ok. -datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, [?FILE_FDATASYNC]). +datasync(FD) -> + datasync(FD, get_dtrace_utag()). + +datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [?FILE_FDATASYNC, enc_utag(DTraceUtag)]). %% Returns {error, Reason} | ok. -sync(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, [?FILE_FSYNC]). +sync(FD) -> + sync(FD, get_dtrace_utag()). + +sync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [?FILE_FSYNC, enc_utag(DTraceUtag)]). %% Returns {ok, Data} | eof | {error, Reason}. -read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - case drv_command(Port, <>) of +read_line(FD) -> + read_line(FD, get_dtrace_utag()). + +read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) -> + case drv_command(Port, [<>, enc_utag(DTraceUtag)]) of {ok, {0, _Data}} -> eof; {ok, {_Size, Data}} -> @@ -366,11 +422,17 @@ read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> end. %% Returns {ok, Data} | eof | {error, Reason}. -read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) - when is_integer(Size), 0 =< Size -> +read(FD, Size) -> + read(FD, Size, get_dtrace_utag()). + +read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size, DTraceUtag) + when is_integer(Size), + 0 =< Size, + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if Size < ?LARGEFILESIZE -> - case drv_command(Port, <>) of + case drv_command(Port, [<>, + enc_utag(DTraceUtag)]) of {ok, {0, _Data}} when Size =/= 0 -> eof; {ok, {_Size, Data}} -> @@ -379,7 +441,8 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) %% Garbage collecting here might help if %% the current processes have some old binaries left. erlang:garbage_collect(), - case drv_command(Port, <>) of + case drv_command(Port, [<>, + enc_utag(DTraceUtag)]) of {ok, {0, _Data}} when Size =/= 0 -> eof; {ok, {_Size, Data}} -> @@ -397,35 +460,43 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) %% Returns {ok, [Data|eof, ...]} | {error, Reason} pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) when is_list(L) -> - pread_int(Port, L, 0, []). + pread_int(Port, L, 0, [], get_dtrace_utag()). -pread_int(_, [], 0, []) -> +pread_int(_, [], 0, [], _DTraceUtag) -> {ok, []}; -pread_int(Port, [], N, Spec) -> - drv_command(Port, [<> | reverse(Spec)]); -pread_int(Port, [{Offs, Size} | T], N, Spec) +pread_int(Port, [], N, Spec, DTraceUtag) -> + drv_command(Port, [<>, enc_utag(DTraceUtag), + <<0:32, N:32>>, reverse(Spec)]); +pread_int(Port, [{Offs, Size} | T], N, Spec, DTraceUtag) when is_integer(Offs), is_integer(Size), 0 =< Size -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> - pread_int(Port, T, N+1, [<> | Spec]); + pread_int(Port, T, N+1, [<> | Spec], + DTraceUtag); true -> {error, einval} end; -pread_int(_, [_|_], _N, _Spec) -> +pread_int(_, [_|_], _N, _Spec, _DTraceUtag) -> {error, badarg}. - - %% Returns {ok, Data} | eof | {error, Reason}. -pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) +pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag) + when is_list(L), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + pread_int(Port, L, 0, [], get_dtrace_utag()); +pread(FD, Offs, Size) when is_integer(Offs), is_integer(Size), 0 =< Size -> + pread(FD, Offs, Size, get_dtrace_utag()). + +pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> case drv_command(Port, - <>) of + [<>, enc_utag(DTraceUtag), + <<0:32, 1:32, Offs:64/signed, Size:64>>]) of {ok, [eof]} -> eof; {ok, [Data]} -> @@ -436,17 +507,22 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) true -> {error, einval} end; -pread(#file_descriptor{module = ?MODULE, data = {_, _}}, _, _) -> +pread(_, _, _, _) -> {error, badarg}. %% Returns {ok, Position} | {error, Reason}. -position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) -> +position(FD, At) -> + position(FD, At, get_dtrace_utag()). + +position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> case lseek_position(At) of {Offs, Whence} when -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - drv_command(Port, <>); + drv_command(Port, [<>, + enc_utag(DTraceUtag)]); {_, _} -> {error, einval}; Reason -> @@ -454,63 +530,89 @@ position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) -> end. %% Returns {error, Reaseon} | ok. -truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> - drv_command(Port, <>). +truncate(FD) -> + truncate(FD, get_dtrace_utag()). + +truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) + when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + drv_command(Port, [<>, enc_utag(DTraceUtag)]). %% Returns {error, Reason} | {ok, BytesCopied} +copy(Source, Dest, Length) -> + copy(Source, Dest, Length, get_dtrace_utag()). + copy(#file_descriptor{module = ?MODULE} = Source, #file_descriptor{module = ?MODULE} = Dest, - Length) + Length, DTraceUtag) when is_integer(Length), Length >= 0; - is_atom(Length) -> + is_atom(Length), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> %% XXX Should be moved down to the driver for optimization. - file:copy_opened(Source, Dest, Length). + file:copy_opened(Source, Dest, Length, DTraceUtag). + +ipread_s32bu_p32bu(FD, Offs, Arg) -> + ipread_s32bu_p32bu(FD, Offs, Arg, get_dtrace_utag()). ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}} = Handle, Offs, - Infinity) when is_atom(Infinity) -> + Infinity, + DTraceUtag) + when is_atom(Infinity), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> ipread_s32bu_p32bu(Handle, Offs, (1 bsl 31)-1); ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, - MaxSize) - when is_integer(Offs), is_integer(MaxSize) -> + MaxSize, + DTraceUtag) + when is_integer(Offs), + is_integer(MaxSize), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, 0 =< MaxSize, MaxSize < (1 bsl 31) -> - drv_command(Port, <>); + drv_command(Port, [<>, enc_utag(DTraceUtag)]); true -> {error, einval} end; ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}}, _Offs, - _MaxSize) -> + _MaxSize, + _DTraceUtag) -> {error, badarg}. %% Returns {ok, Contents} | {error, Reason} read_file(File) when (is_list(File) orelse is_binary(File)) -> + read_file(File, get_dtrace_utag()); +read_file(_) -> + {error, badarg}. + +read_file(File, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag))-> case drv_open(?FD_DRV, [binary]) of {ok, Port} -> - Result = read_file(Port, File), + Result = read_file(Port, File, DTraceUtag), close(Port), Result; {error, _} = Error -> Error end; -read_file(_) -> +read_file(_, _) -> {error, badarg}. %% Takes a Port opened with open/1. -read_file(Port, File) when is_port(Port), +read_file(Port, File, DTraceUtag) when is_port(Port), (is_list(File) orelse is_binary(File)) -> - Cmd = [?FILE_READ_FILE | pathname(File)], + Cmd = [?FILE_READ_FILE | + list_to_binary([pathname(File), enc_utag(DTraceUtag)])], case drv_command(Port, Cmd) of {error, enomem} -> %% It could possibly help to do a @@ -522,22 +624,30 @@ read_file(Port, File) when is_port(Port), Result -> Result end; -read_file(_,_) -> +read_file(_,_,_) -> {error, badarg}. %% Returns {error, Reason} | ok. -write_file(File, Bin) when (is_list(File) orelse is_binary(File)) -> +write_file(File, Bin) -> + write_file(File, Bin, get_dtrace_utag()). + +write_file(File, Bin, DTraceUtag) + when (is_list(File) orelse is_binary(File)), + (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + OldUtag = put(dtrace_utag, DTraceUtag), % TODO: API? case open(File, [binary, write]) of {ok, Handle} -> Result = write(Handle, Bin), close(Handle), + put(dtrace_utag, OldUtag), Result; Error -> + put(dtrace_utag, OldUtag), Error end; -write_file(_, _) -> +write_file(_, _, _) -> {error, badarg}. @@ -601,54 +711,56 @@ stop(Port) when is_port(Port) -> -%% get_cwd/{0,1,2} +%% get_cwd/{0,1,3} get_cwd() -> - get_cwd_int(0). + get_cwd_int(0, get_dtrace_utag()). get_cwd(Port) when is_port(Port) -> - get_cwd_int(Port, 0); + get_cwd_int(Port, 0, get_dtrace_utag()); get_cwd([]) -> - get_cwd_int(0); + get_cwd_int(0, get_dtrace_utag()); get_cwd([Letter, $: | _]) when $a =< Letter, Letter =< $z -> - get_cwd_int(Letter - $a + 1); + get_cwd_int(Letter - $a + 1, get_dtrace_utag()); get_cwd([Letter, $: | _]) when $A =< Letter, Letter =< $Z -> - get_cwd_int(Letter - $A + 1); + get_cwd_int(Letter - $A + 1, get_dtrace_utag()); get_cwd([_|_]) -> {error, einval}; get_cwd(_) -> {error, badarg}. -get_cwd(Port, []) when is_port(Port) -> - get_cwd_int(Port, 0); -get_cwd(Port, [Letter, $: | _]) +get_cwd(Port, [], DTraceUtag) when is_port(Port) -> + get_cwd_int(Port, 0, DTraceUtag); +get_cwd(Port, no_drive, DTraceUtag) when is_port(Port) -> + get_cwd_int(Port, 0, DTraceUtag); +get_cwd(Port, [Letter, $: | _], DTraceUtag) when is_port(Port), $a =< Letter, Letter =< $z -> - get_cwd_int(Port, Letter - $a + 1); -get_cwd(Port, [Letter, $: | _]) + get_cwd_int(Port, Letter - $a + 1, DTraceUtag); +get_cwd(Port, [Letter, $: | _], DTraceUtag) when is_port(Port), $A =< Letter, Letter =< $Z -> - get_cwd_int(Port, Letter - $A + 1); -get_cwd(Port, [_|_]) when is_port(Port) -> + get_cwd_int(Port, Letter - $A + 1, DTraceUtag); +get_cwd(Port, [_|_], _DTraceUtag) when is_port(Port) -> {error, einval}; -get_cwd(_, _) -> +get_cwd(_, _, _DTraceUtag) -> {error, badarg}. -get_cwd_int(Drive) -> - get_cwd_int({?DRV, [binary]}, Drive). +get_cwd_int(Drive, DTraceUtag) -> + get_cwd_int({?DRV, [binary]}, Drive, DTraceUtag). -get_cwd_int(Port, Drive) -> - drv_command(Port, <>). +get_cwd_int(Port, Drive, DTraceUtag) -> + drv_command(Port, list_to_binary([?FILE_PWD, Drive, enc_utag(DTraceUtag)])). -%% set_cwd/{1,2} +%% set_cwd/{1,3} set_cwd(Dir) -> - set_cwd_int({?DRV, [binary]}, Dir). + set_cwd_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -set_cwd(Port, Dir) when is_port(Port) -> - set_cwd_int(Port, Dir). +set_cwd(Port, Dir, DTraceUtag) when is_port(Port) -> + set_cwd_int(Port, Dir, DTraceUtag). -set_cwd_int(Port, Dir0) -> +set_cwd_int(Port, Dir0, DTraceUtag) -> Dir = (catch case os:type() of @@ -658,7 +770,7 @@ set_cwd_int(Port, Dir0) -> %% must call get_cwd from here and use %% absname/2, since %% absname/1 uses file:get_cwd ... - case get_cwd_int(Port, 0) of + case get_cwd_int(Port, 0, "") of {ok, AbsPath} -> filename:absname(Dir0, AbsPath); _Badcwd -> @@ -669,78 +781,86 @@ set_cwd_int(Port, Dir0) -> end), %% Dir is now either a string or an EXIT tuple. %% An EXIT tuple will fail in the following catch. - drv_command(Port, [?FILE_CHDIR, pathname(Dir)]). + drv_command(Port, [?FILE_CHDIR, pathname(Dir), enc_utag(DTraceUtag)]). -%% delete/{1,2} +%% delete/{1,2,3} delete(File) -> - delete_int({?DRV, [binary]}, File). + delete_int({?DRV, [binary]}, File, get_dtrace_utag()). delete(Port, File) when is_port(Port) -> - delete_int(Port, File). + delete_int(Port, File, get_dtrace_utag()). + +delete(Port, File, DTraceUtag) when is_port(Port) -> + delete_int(Port, File, DTraceUtag). -delete_int(Port, File) -> - drv_command(Port, [?FILE_DELETE, pathname(File)]). +delete_int(Port, File, DTraceUtag) -> + drv_command(Port, [?FILE_DELETE, pathname(File), enc_utag(DTraceUtag)]). -%% rename/{2,3} +%% rename/{2,3,4} rename(From, To) -> - rename_int({?DRV, [binary]}, From, To). + rename_int({?DRV, [binary]}, From, To, get_dtrace_utag()). rename(Port, From, To) when is_port(Port) -> - rename_int(Port, From, To). + rename_int(Port, From, To, get_dtrace_utag()). + +rename(Port, From, To, DTraceUtag) when is_port(Port) -> + rename_int(Port, From, To, DTraceUtag). -rename_int(Port, From, To) -> - drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To)]). +rename_int(Port, From, To, DTraceUtag) -> + drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To), + enc_utag(DTraceUtag)]). -%% make_dir/{1,2} +%% make_dir/{1,3} make_dir(Dir) -> - make_dir_int({?DRV, [binary]}, Dir). + make_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -make_dir(Port, Dir) when is_port(Port) -> - make_dir_int(Port, Dir). +make_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + make_dir_int(Port, Dir, DTraceUtag). -make_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_MKDIR, pathname(Dir)]). +make_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_MKDIR, pathname(Dir), enc_utag(DTraceUtag)]). -%% del_dir/{1,2} +%% del_dir/{1,3} del_dir(Dir) -> - del_dir_int({?DRV, [binary]}, Dir). + del_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -del_dir(Port, Dir) when is_port(Port) -> - del_dir_int(Port, Dir). +del_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + del_dir_int(Port, Dir, DTraceUtag). -del_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_RMDIR, pathname(Dir)]). +del_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_RMDIR, pathname(Dir), enc_utag(DTraceUtag)]). - - -%% read_file_info/{1,2,3} +%% read_file_info/{1,2,3,4} read_file_info(File) -> - read_file_info_int({?DRV, [binary]}, File, local). + read_file_info_int({?DRV, [binary]}, File, local, get_dtrace_utag()). read_file_info(Port, File) when is_port(Port) -> - read_file_info_int(Port, File, local); + read_file_info_int(Port, File, local, get_dtrace_utag()); read_file_info(File, Opts) -> - read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local)). + read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local), get_dtrace_utag()). -read_file_info(Port, File, Opts) when is_port(Port) -> - read_file_info_int(Port, File, plgv(time, Opts, local)). +read_file_info(Port, File, Opts) when is_port(Port), is_list(Opts) -> + read_file_info_int(Port, File, plgv(time, Opts, local), get_dtrace_utag()). -read_file_info_int(Port, File, TimeType) -> +read_file_info(Port, File, Opts, DTraceUtag) when is_port(Port) -> + read_file_info_int(Port, File, plgv(time, Opts, local), DTraceUtag). + +read_file_info_int(Port, File, TimeType, DTraceUtag) -> try - case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of + case drv_command(Port, [?FILE_FSTAT, pathname(File), enc_utag(DTraceUtag)]) of {ok, FI} -> {ok, FI#file_info{ ctime = from_seconds(FI#file_info.ctime, TimeType), mtime = from_seconds(FI#file_info.mtime, TimeType), @@ -752,30 +872,33 @@ read_file_info_int(Port, File, TimeType) -> error:_ -> {error, badarg} end. - -%% altname/{1,2} +%% altname/{1,3} altname(File) -> - altname_int({?DRV, [binary]}, File). + altname_int({?DRV, [binary]}, File, get_dtrace_utag()). -altname(Port, File) when is_port(Port) -> - altname_int(Port, File). +altname(Port, File, DTraceUtag) when is_port(Port) -> + altname_int(Port, File, DTraceUtag). -altname_int(Port, File) -> - drv_command(Port, [?FILE_ALTNAME, pathname(File)]). +altname_int(Port, File, DTraceUtag) -> + drv_command(Port, [?FILE_ALTNAME, pathname(File), enc_utag(DTraceUtag)]). -%% write_file_info/{2,3,4} + +%% write_file_info/{2,3,4,5} write_file_info(File, Info) -> - write_file_info_int({?DRV, [binary]}, File, Info, local). + write_file_info_int({?DRV, [binary]}, File, Info, local, get_dtrace_utag()). write_file_info(Port, File, Info) when is_port(Port) -> - write_file_info_int(Port, File, Info, local); + write_file_info_int(Port, File, Info, local, get_dtrace_utag()); write_file_info(File, Info, Opts) -> - write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local)). + write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local), get_dtrace_utag()). write_file_info(Port, File, Info, Opts) when is_port(Port) -> - write_file_info_int(Port, File, Info, plgv(time, Opts, local)). + write_file_info_int(Port, File, Info, plgv(time, Opts, local), get_dtrace_utag()). + +write_file_info(Port, File, Info, Opts, DTraceUtag) when is_port(Port) -> + write_file_info_int(Port, File, Info, plgv(time, Opts, local), DTraceUtag). write_file_info_int(Port, File, #file_info{mode=Mode, @@ -784,7 +907,8 @@ write_file_info_int(Port, File, atime=Atime0, mtime=Mtime0, ctime=Ctime0}, - TimeType) -> + TimeType, + DTraceUtag) -> % Atime and/or Mtime might be undefined % - use localtime() for atime, if atime is undefined @@ -803,12 +927,13 @@ write_file_info_int(Port, File, int_to_int64bytes(to_seconds(Atime, TimeType)), int_to_int64bytes(to_seconds(Mtime, TimeType)), int_to_int64bytes(to_seconds(Ctime, TimeType)), - pathname(File)]) + pathname(File), + enc_utag(DTraceUtag) + ]) catch error:_ -> {error, badarg} end. - file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; file_info_validate_atime(undefined, local) -> erlang:localtime(); file_info_validate_atime(undefined, universal) -> erlang:universaltime(); @@ -820,63 +945,72 @@ file_info_validate_mtime(Mtime, _) -> Mtime. file_info_validate_ctime(undefined, Mtime) -> Mtime; file_info_validate_ctime(Ctime, _) -> Ctime. -%% make_link/{2,3} +%% make_link/{2,3,4} make_link(Old, New) -> - make_link_int({?DRV, [binary]}, Old, New). + make_link_int({?DRV, [binary]}, Old, New, get_dtrace_utag()). make_link(Port, Old, New) when is_port(Port) -> - make_link_int(Port, Old, New). + make_link_int(Port, Old, New, get_dtrace_utag()). -make_link_int(Port, Old, New) -> - drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New)]). +make_link(Port, Old, New, DTraceUtag) when is_port(Port) -> + make_link_int(Port, Old, New, DTraceUtag). +make_link_int(Port, Old, New, DTraceUtag) -> + drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New), + enc_utag(DTraceUtag)]). -%% make_symlink/{2,3} + +%% make_symlink/{2,3,4} make_symlink(Old, New) -> - make_symlink_int({?DRV, [binary]}, Old, New). + make_symlink_int({?DRV, [binary]}, Old, New, get_dtrace_utag()). make_symlink(Port, Old, New) when is_port(Port) -> - make_symlink_int(Port, Old, New). + make_symlink_int(Port, Old, New, get_dtrace_utag()). + +make_symlink(Port, Old, New, DTraceUtag) when is_port(Port) -> + make_symlink_int(Port, Old, New, DTraceUtag). -make_symlink_int(Port, Old, New) -> - drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New)]). +make_symlink_int(Port, Old, New, DTraceUtag) -> + drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New), + enc_utag(DTraceUtag)]). -%% read_link/{2,3} +%% read_link/{1,3} read_link(Link) -> - read_link_int({?DRV, [binary]}, Link). + read_link_int({?DRV, [binary]}, Link, get_dtrace_utag()). -read_link(Port, Link) when is_port(Port) -> - read_link_int(Port, Link). +read_link(Port, Link, DTraceUtag) when is_port(Port) -> + read_link_int(Port, Link, DTraceUtag). -read_link_int(Port, Link) -> - drv_command(Port, [?FILE_READLINK, pathname(Link)]). +read_link_int(Port, Link, DTraceUtag) -> + drv_command(Port, [?FILE_READLINK, pathname(Link), enc_utag(DTraceUtag)]). -%% read_link_info/{2,3} +%% read_link_info/{1,2,3,4} read_link_info(Link) -> - read_link_info_int({?DRV, [binary]}, Link, local). + read_link_info_int({?DRV, [binary]}, Link, local, get_dtrace_utag()). read_link_info(Port, Link) when is_port(Port) -> - read_link_info_int(Port, Link, local); - + read_link_info_int(Port, Link, local, get_dtrace_utag()); read_link_info(Link, Opts) -> - read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local)). + read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local), get_dtrace_utag()). read_link_info(Port, Link, Opts) when is_port(Port) -> - read_link_info_int(Port, Link, plgv(time, Opts, local)). + read_link_info_int(Port, Link, plgv(time, Opts, local), get_dtrace_utag()). +read_link_info(Port, Link, Opts, DTraceUtag) when is_port(Port) -> + read_link_info_int(Port, Link, plgv(time, Opts, local), DTraceUtag). -read_link_info_int(Port, Link, TimeType) -> +read_link_info_int(Port, Link, TimeType, DTraceUtag) -> try - case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of + case drv_command(Port, [?FILE_LSTAT, pathname(Link), enc_utag(DTraceUtag)]) of {ok, FI} -> {ok, FI#file_info{ ctime = from_seconds(FI#file_info.ctime, TimeType), mtime = from_seconds(FI#file_info.mtime, TimeType), @@ -888,16 +1022,16 @@ read_link_info_int(Port, Link, TimeType) -> error:_ -> {error, badarg} end. -%% list_dir/{1,2} +%% list_dir/{1,3} list_dir(Dir) -> - list_dir_int({?DRV, [binary]}, Dir). + list_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). -list_dir(Port, Dir) when is_port(Port) -> - list_dir_int(Port, Dir). +list_dir(Port, Dir, DTraceUtag) when is_port(Port) -> + list_dir_int(Port, Dir, DTraceUtag). -list_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_READDIR, pathname(Dir)], []). +list_dir_int(Port, Dir, DTraceUtag) -> + drv_command(Port, [?FILE_READDIR, pathname(Dir), enc_utag(DTraceUtag)], []). @@ -1335,7 +1469,6 @@ reverse(L, T) -> lists:reverse(L, T). pathname(File) -> (catch prim_file:internal_name2native(File)). - %% proplist:get_value/3 plgv(K, [{K, V}|_], _) -> V; plgv(K, [_|KVs], D) -> plgv(K, KVs, D); @@ -1359,3 +1492,20 @@ to_seconds({_,_} = Datetime, universal) -> erlang:universaltime_to_posixtime(Datetime); to_seconds({_,_} = Datetime, local) -> erlang:universaltime_to_posixtime(erlang:localtime_to_universaltime(Datetime)). + +%% TODO: Duplicate code! +get_dtrace_utag() -> + case get(dtrace_utag) of + X when is_list(X) -> + X; + _ -> + "" + end. + +%% TODO: Measure if it's worth checking (re:run()?) for NUL byte first? +enc_utag([0|Cs]) -> + enc_utag(Cs); +enc_utag([C|Cs]) -> + [C|enc_utag(Cs)]; +enc_utag([]) -> + [0]. diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 4028dd4f0b..a2e0d261ee 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -39,7 +39,7 @@ -export([ipread_s32bu_p32bu/3]). %% Generic file contents. -export([open/2, close/1, advise/4, - read/2, write/2, + read/2, write/2, pread/2, pread/3, pwrite/2, pwrite/3, read_line/1, position/2, truncate/1, datasync/1, sync/1, @@ -62,7 +62,7 @@ %% Internal export to prim_file and ram_file until they implement %% an efficient copy themselves. --export([copy_opened/3]). +-export([copy_opened/4]). -export([ipread_s32bu_p32bu_int/3]). @@ -166,7 +166,7 @@ pid2name(Pid) when is_pid(Pid) -> Reason :: posix(). get_cwd() -> - call(get_cwd, []). + call(get_cwd, [no_drive, get_dtrace_utag()]). -spec get_cwd(Drive) -> {ok, Dir} | {error, Reason} when Drive :: string(), @@ -174,21 +174,21 @@ get_cwd() -> Reason :: posix() | badarg. get_cwd(Drive) -> - check_and_call(get_cwd, [file_name(Drive)]). + check_and_call(get_cwd, [file_name(Drive), get_dtrace_utag()]). -spec set_cwd(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. set_cwd(Dirname) -> - check_and_call(set_cwd, [file_name(Dirname)]). + check_and_call(set_cwd, [file_name(Dirname), get_dtrace_utag()]). -spec delete(Filename) -> ok | {error, Reason} when Filename :: name(), Reason :: posix() | badarg. delete(Name) -> - check_and_call(delete, [file_name(Name)]). + check_and_call(delete, [file_name(Name), get_dtrace_utag()]). -spec rename(Source, Destination) -> ok | {error, Reason} when Source :: name(), @@ -196,21 +196,21 @@ delete(Name) -> Reason :: posix() | badarg. rename(From, To) -> - check_and_call(rename, [file_name(From), file_name(To)]). + check_and_call(rename, [file_name(From), file_name(To), get_dtrace_utag()]). -spec make_dir(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. make_dir(Name) -> - check_and_call(make_dir, [file_name(Name)]). + check_and_call(make_dir, [file_name(Name), get_dtrace_utag()]). -spec del_dir(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. del_dir(Name) -> - check_and_call(del_dir, [file_name(Name)]). + check_and_call(del_dir, [file_name(Name), get_dtrace_utag()]). -spec read_file_info(Filename) -> {ok, FileInfo} | {error, Reason} when Filename :: name(), @@ -218,7 +218,7 @@ del_dir(Name) -> Reason :: posix() | badarg. read_file_info(Name) -> - check_and_call(read_file_info, [file_name(Name)]). + check_and_call(read_file_info, [file_name(Name), get_dtrace_utag()]). -spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when Filename :: name(), @@ -232,7 +232,7 @@ read_file_info(Name, Opts) when is_list(Opts) -> -spec altname(Name :: name()) -> any(). altname(Name) -> - check_and_call(altname, [file_name(Name)]). + check_and_call(altname, [file_name(Name), get_dtrace_utag()]). -spec read_link_info(Name) -> {ok, FileInfo} | {error, Reason} when Name :: name(), @@ -240,7 +240,7 @@ altname(Name) -> Reason :: posix() | badarg. read_link_info(Name) -> - check_and_call(read_link_info, [file_name(Name)]). + check_and_call(read_link_info, [file_name(Name), get_dtrace_utag()]). -spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when Name :: name(), @@ -258,7 +258,7 @@ read_link_info(Name, Opts) when is_list(Opts) -> Reason :: posix() | badarg. read_link(Name) -> - check_and_call(read_link, [file_name(Name)]). + check_and_call(read_link, [file_name(Name), get_dtrace_utag()]). -spec write_file_info(Filename, FileInfo) -> ok | {error, Reason} when Filename :: name(), @@ -266,7 +266,7 @@ read_link(Name) -> Reason :: posix() | badarg. write_file_info(Name, Info = #file_info{}) -> - check_and_call(write_file_info, [file_name(Name), Info]). + check_and_call(write_file_info, [file_name(Name), Info, get_dtrace_utag()]). -spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when Filename :: name(), @@ -283,7 +283,7 @@ write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> Reason :: posix() | badarg. list_dir(Name) -> - check_and_call(list_dir, [file_name(Name)]). + check_and_call(list_dir, [file_name(Name), get_dtrace_utag()]). -spec read_file(Filename) -> {ok, Binary} | {error, Reason} when Filename :: name(), @@ -291,7 +291,7 @@ list_dir(Name) -> Reason :: posix() | badarg | terminated | system_limit. read_file(Name) -> - check_and_call(read_file, [file_name(Name)]). + check_and_call(read_file, [file_name(Name), get_dtrace_utag()]). -spec make_link(Existing, New) -> ok | {error, Reason} when Existing :: name(), @@ -299,7 +299,7 @@ read_file(Name) -> Reason :: posix() | badarg. make_link(Old, New) -> - check_and_call(make_link, [file_name(Old), file_name(New)]). + check_and_call(make_link, [file_name(Old), file_name(New), get_dtrace_utag()]). -spec make_symlink(Existing, New) -> ok | {error, Reason} when Existing :: name(), @@ -307,7 +307,7 @@ make_link(Old, New) -> Reason :: posix() | badarg. make_symlink(Old, New) -> - check_and_call(make_symlink, [file_name(Old), file_name(New)]). + check_and_call(make_symlink, [file_name(Old), file_name(New), get_dtrace_utag()]). -spec write_file(Filename, Bytes) -> ok | {error, Reason} when Filename :: name(), @@ -315,7 +315,7 @@ make_symlink(Old, New) -> Reason :: posix() | badarg | terminated | system_limit. write_file(Name, Bin) -> - check_and_call(write_file, [file_name(Name), make_binary(Bin)]). + check_and_call(write_file, [file_name(Name), make_binary(Bin), get_dtrace_utag()]). %% This whole operation should be moved to the file_server and prim_file %% when it is time to change file server protocol again. @@ -367,7 +367,7 @@ raw_write_file_info(Name, #file_info{} = Info) -> case check_args(Args) of ok -> [FileName] = Args, - ?PRIM_FILE:write_file_info(FileName, Info); + ?PRIM_FILE:write_file_info(FileName, Info, get_dtrace_utag()); Error -> Error end. @@ -400,7 +400,7 @@ open(Item, ModeList) when is_list(ModeList) -> [FileName | _] = Args, %% We rely on the returned Handle (in {ok, Handle}) %% being a pid() or a #file_descriptor{} - ?PRIM_FILE:open(FileName, ModeList); + ?PRIM_FILE:open(FileName, ModeList, get_dtrace_utag()); Error -> Error end @@ -421,7 +421,7 @@ open(Item, ModeList) when is_list(ModeList) -> case check_args(Args) of ok -> [FileName | _] = Args, - call(open, [FileName, ModeList]); + call(open, [FileName, ModeList, get_dtrace_utag()]); Error -> Error end @@ -466,7 +466,10 @@ close(_) -> advise(File, Offset, Length, Advise) when is_pid(File) -> R = file_request(File, {advise, Offset, Length, Advise}), wait_file_reply(File, R); +advise(#file_descriptor{module = prim_file = Module} = Handle, Offset, Length, Advise) -> + Module:advise(Handle, Offset, Length, Advise, get_dtrace_utag()); advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:advise(Handle, Offset, Length, Advise); advise(_, _, _, _) -> {error, badarg}. @@ -477,17 +480,25 @@ advise(_, _, _, _) -> Data :: string() | binary(), Reason :: posix() | badarg | terminated. -read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 -> +read(File, Sz) -> + read(File, Sz, get_dtrace_utag()). + +read(File, Sz, _DTraceUtag) + when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 -> case io:request(File, {get_chars, '', Sz}) of Data when is_list(Data); is_binary(Data) -> {ok, Data}; Other -> Other end; -read(#file_descriptor{module = Module} = Handle, Sz) +read(#file_descriptor{module = prim_file = Module} = Handle, Sz, DTraceUtag) + when is_integer(Sz), Sz >= 0 -> + Module:read(Handle, Sz, DTraceUtag); +read(#file_descriptor{module = Module} = Handle, Sz, _DTraceUtag) when is_integer(Sz), Sz >= 0 -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:read(Handle, Sz); -read(_, _) -> +read(_, _, _) -> {error, badarg}. -spec read_line(IoDevice) -> {ok, Data} | eof | {error, Reason} when @@ -502,7 +513,10 @@ read_line(File) when (is_pid(File) orelse is_atom(File)) -> Other -> Other end; +read_line(#file_descriptor{module = prim_file = Module} = Handle) -> + Module:read_line(Handle, get_dtrace_utag()); read_line(#file_descriptor{module = Module} = Handle) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:read_line(Handle); read_line(_) -> {error, badarg}. @@ -516,7 +530,10 @@ read_line(_) -> pread(File, L) when is_pid(File), is_list(L) -> pread_int(File, L, []); +pread(#file_descriptor{module = prim_file = Module} = Handle, L) when is_list(L) -> + Module:pread(Handle, L, get_dtrace_utag()); pread(#file_descriptor{module = Module} = Handle, L) when is_list(L) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pread(Handle, L); pread(_, _) -> {error, badarg}. @@ -548,6 +565,7 @@ pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 -> wait_file_reply(File, R); pread(#file_descriptor{module = Module} = Handle, Offs, Sz) when is_integer(Sz), Sz >= 0 -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pread(Handle, Offs, Sz); pread(_, _, _) -> {error, badarg}. @@ -557,16 +575,22 @@ pread(_, _, _) -> Bytes :: iodata(), Reason :: posix() | badarg | terminated. -write(File, Bytes) when (is_pid(File) orelse is_atom(File)) -> +write(File, Bytes) -> + write(File, Bytes, get_dtrace_utag()). + +write(File, Bytes, _DTraceUtag) when (is_pid(File) orelse is_atom(File)) -> case make_binary(Bytes) of Bin when is_binary(Bin) -> io:request(File, {put_chars,Bin}); Error -> Error end; -write(#file_descriptor{module = Module} = Handle, Bytes) -> +write(#file_descriptor{module = prim_file = Module} = Handle, Bytes, DTraceUtag) -> + Module:write(Handle, Bytes, DTraceUtag); +write(#file_descriptor{module = Module} = Handle, Bytes, _DTraceUtag) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:write(Handle, Bytes); -write(_, _) -> +write(_, _, _) -> {error, badarg}. -spec pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}} when @@ -577,7 +601,10 @@ write(_, _) -> pwrite(File, L) when is_pid(File), is_list(L) -> pwrite_int(File, L, 0); +pwrite(#file_descriptor{module = prim_file = Module} = Handle, L) when is_list(L) -> + Module:pwrite(Handle, L, get_dtrace_utag()); pwrite(#file_descriptor{module = Module} = Handle, L) when is_list(L) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pwrite(Handle, L); pwrite(_, _) -> {error, badarg}. @@ -604,6 +631,7 @@ pwrite(File, At, Bytes) when is_pid(File) -> R = file_request(File, {pwrite, At, Bytes}), wait_file_reply(File, R); pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pwrite(Handle, Offs, Bytes); pwrite(_, _, _) -> {error, badarg}. @@ -615,7 +643,10 @@ pwrite(_, _, _) -> datasync(File) when is_pid(File) -> R = file_request(File, datasync), wait_file_reply(File, R); +datasync(#file_descriptor{module = prim_file = Module} = Handle) -> + Module:datasync(Handle, get_dtrace_utag()); datasync(#file_descriptor{module = Module} = Handle) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:datasync(Handle); datasync(_) -> {error, badarg}. @@ -627,7 +658,10 @@ datasync(_) -> sync(File) when is_pid(File) -> R = file_request(File, sync), wait_file_reply(File, R); +sync(#file_descriptor{module = prim_file = Module} = Handle) -> + Module:sync(Handle, get_dtrace_utag()); sync(#file_descriptor{module = Module} = Handle) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:sync(Handle); sync(_) -> {error, badarg}. @@ -641,7 +675,10 @@ sync(_) -> position(File, At) when is_pid(File) -> R = file_request(File, {position,At}), wait_file_reply(File, R); +position(#file_descriptor{module = prim_file = Module} = Handle, At) -> + Module:position(Handle, At, get_dtrace_utag()); position(#file_descriptor{module = Module} = Handle, At) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:position(Handle, At); position(_, _) -> {error, badarg}. @@ -653,7 +690,10 @@ position(_, _) -> truncate(File) when is_pid(File) -> R = file_request(File, truncate), wait_file_reply(File, R); +truncate(#file_descriptor{module = prim_file = Module} = Handle) -> + Module:truncate(Handle, get_dtrace_utag()); truncate(#file_descriptor{module = Module} = Handle) -> + %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:truncate(Handle); truncate(_) -> {error, badarg}. @@ -694,7 +734,7 @@ copy_int(Source, Dest, Length) when is_pid(Source), is_pid(Dest); is_pid(Source), is_record(Dest, file_descriptor); is_record(Source, file_descriptor), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, 0); + copy_opened_int(Source, Dest, Length, get_dtrace_utag()); %% Copy between open raw files, both handled by the same module copy_int(#file_descriptor{module = Module} = Source, #file_descriptor{module = Module} = Dest, @@ -703,14 +743,14 @@ copy_int(#file_descriptor{module = Module} = Source, %% Copy between open raw files of different modules copy_int(#file_descriptor{} = Source, #file_descriptor{} = Dest, Length) -> - copy_opened_int(Source, Dest, Length, 0); + copy_opened_int(Source, Dest, Length, get_dtrace_utag()); %% Copy between filenames, let the server do the copy copy_int({SourceName, SourceOpts}, {DestName, DestOpts}, Length) when is_list(SourceOpts), is_list(DestOpts) -> check_and_call(copy, [file_name(SourceName), SourceOpts, file_name(DestName), DestOpts, - Length]); + Length, get_dtrace_utag()]); %% Filename -> open file; must open Source and do client copy copy_int({SourceName, SourceOpts}, Dest, Length) when is_list(SourceOpts), is_pid(Dest); @@ -721,7 +761,8 @@ copy_int({SourceName, SourceOpts}, Dest, Length) Source -> case open(Source, [read | SourceOpts]) of {ok, Handle} -> - Result = copy_opened_int(Handle, Dest, Length, 0), + Result = copy_opened_int(Handle, Dest, Length, + get_dtrace_utag()), close(Handle), Result; {error, _} = Error -> @@ -738,7 +779,8 @@ copy_int(Source, {DestName, DestOpts}, Length) Dest -> case open(Dest, [write | DestOpts]) of {ok, Handle} -> - Result = copy_opened_int(Source, Handle, Length, 0), + Result = copy_opened_int(Source, Handle, Length, + get_dtrace_utag()), close(Handle), Result; {error, _} = Error -> @@ -773,45 +815,46 @@ copy_int(Source, Dest, Length) -> -copy_opened(Source, Dest, Length) +copy_opened(Source, Dest, Length, DTraceUtag) when is_integer(Length), Length >= 0; is_atom(Length) -> - copy_opened_int(Source, Dest, Length); -copy_opened(_, _, _) -> + copy_opened_int(Source, Dest, Length, DTraceUtag); +copy_opened(_, _, _, _) -> {error, badarg}. %% Here we know that Length is either an atom or an integer >= 0 %% (by the way, atoms > integers) -copy_opened_int(Source, Dest, Length) +copy_opened_int(Source, Dest, Length, DTraceUtag) when is_pid(Source), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, 0); -copy_opened_int(Source, Dest, Length) + copy_opened_int(Source, Dest, Length, 0, DTraceUtag); +copy_opened_int(Source, Dest, Length, DTraceUtag) when is_pid(Source), is_record(Dest, file_descriptor) -> - copy_opened_int(Source, Dest, Length, 0); -copy_opened_int(Source, Dest, Length) + copy_opened_int(Source, Dest, Length, 0, DTraceUtag); +copy_opened_int(Source, Dest, Length, DTraceUtag) when is_record(Source, file_descriptor), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, 0); -copy_opened_int(Source, Dest, Length) + copy_opened_int(Source, Dest, Length, 0, DTraceUtag); +copy_opened_int(Source, Dest, Length, DTraceUtag) when is_record(Source, file_descriptor), is_record(Dest, file_descriptor) -> - copy_opened_int(Source, Dest, Length, 0); -copy_opened_int(_, _, _) -> + copy_opened_int(Source, Dest, Length, 0, DTraceUtag); +copy_opened_int(_, _, _, _) -> {error, badarg}. %% Here we know that Source and Dest are handles to open files, Length is %% as above, and Copied is an integer >= 0 %% Copy loop in client process -copy_opened_int(_, _, Length, Copied) when Length =< 0 -> % atom() > integer() +copy_opened_int(_, _, Length, Copied, _DTraceUtag) + when Length =< 0 -> % atom() > integer() {ok, Copied}; -copy_opened_int(Source, Dest, Length, Copied) -> +copy_opened_int(Source, Dest, Length, Copied, DTraceUtag) -> N = if Length > 65536 -> 65536; true -> Length end, % atom() > integer() ! - case read(Source, N) of + case read(Source, N, DTraceUtag) of {ok, Data} -> M = if is_binary(Data) -> byte_size(Data); is_list(Data) -> length(Data) end, - case write(Dest, Data) of + case write(Dest, Data, DTraceUtag) of ok -> if M < N -> %% Got less than asked for - must be end of file @@ -821,7 +864,8 @@ copy_opened_int(Source, Dest, Length, Copied) -> NewLength = if is_atom(Length) -> Length; true -> Length-M end, - copy_opened_int(Source, Dest, NewLength, Copied+M) + copy_opened_int(Source, Dest, NewLength, Copied+M, + DTraceUtag) end; {error, _} = Error -> Error @@ -841,6 +885,8 @@ copy_opened_int(Source, Dest, Length, Copied) -> ipread_s32bu_p32bu(File, Pos, MaxSize) when is_pid(File) -> ipread_s32bu_p32bu_int(File, Pos, MaxSize); +ipread_s32bu_p32bu(#file_descriptor{module = prim_file = Module} = Handle, Pos, MaxSize) -> + Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize, get_dtrace_utag()); ipread_s32bu_p32bu(#file_descriptor{module = Module} = Handle, Pos, MaxSize) -> Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize); ipread_s32bu_p32bu(_, _, _) -> @@ -1456,3 +1502,6 @@ wait_file_reply(From, Ref) -> %% receive {'EXIT', From, _} -> ok after 0 -> ok end, {error, terminated} end. + +get_dtrace_utag() -> + prim_file:get_dtrace_utag(). diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index 14da9c1a55..cc0343031b 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -21,7 +21,7 @@ %% A simple file server for io to one file instance per server instance. -export([format_error/1]). --export([start/3, start_link/3]). +-export([start/4, start_link/4]). -export([count_and_find/3]). @@ -43,18 +43,18 @@ format_error({_Line, Mod, Reason}) -> format_error(ErrorId) -> erl_posix_msg:message(ErrorId). -start(Owner, FileName, ModeList) +start(Owner, FileName, ModeList, DTraceUtag) when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) -> - do_start(spawn, Owner, FileName, ModeList). + do_start(spawn, Owner, FileName, ModeList, DTraceUtag). -start_link(Owner, FileName, ModeList) +start_link(Owner, FileName, ModeList, DTraceUtag) when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) -> - do_start(spawn_link, Owner, FileName, ModeList). + do_start(spawn_link, Owner, FileName, ModeList, DTraceUtag). %%%----------------------------------------------------------------- %%% Server starter, dispatcher and helpers -do_start(Spawn, Owner, FileName, ModeList) -> +do_start(Spawn, Owner, FileName, ModeList, DTraceUtag) -> Self = self(), Ref = make_ref(), Pid = @@ -63,11 +63,12 @@ do_start(Spawn, Owner, FileName, ModeList) -> %% process_flag(trap_exit, true), case parse_options(ModeList) of {ReadMode, UnicodeMode, Opts} -> - case ?PRIM_FILE:open(FileName, Opts) of + case ?PRIM_FILE:open(FileName, Opts, DTraceUtag) of {error, Reason} = Error -> Self ! {Ref, Error}, exit(Reason); {ok, Handle} -> + put(dtrace_utag, DTraceUtag), % TODO: API? %% XXX must I handle R6 nodes here? M = erlang:monitor(process, Owner), Self ! {Ref, ok}, diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl index fc6cd823c9..c917819508 100644 --- a/lib/kernel/src/file_server.erl +++ b/lib/kernel/src/file_server.erl @@ -76,6 +76,7 @@ stop() -> init([]) -> process_flag(trap_exit, true), + put(dtrace_utag, atom_to_list(?FILE_SERVER)), case ?PRIM_FILE:start() of {ok, Handle} -> ets:new(?FILE_IO_SERVER_TABLE, [named_table]), @@ -99,9 +100,9 @@ init([]) -> {'reply', 'eof' | 'ok' | {'error', term()} | {'ok', term()}, state()} | {'stop', 'normal', 'stopped', state()}. -handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle) +handle_call({open, Name, ModeList, DTraceUtag}, {Pid, _Tag} = _From, Handle) when is_list(ModeList) -> - Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList), + Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList, DTraceUtag), case Child of {ok, P} when is_pid(P) -> ets:insert(?FILE_IO_SERVER_TABLE, {P, Name}); @@ -110,87 +111,86 @@ handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle) end, {reply, Child, Handle}; -handle_call({open, _Name, _Mode}, _From, Handle) -> +handle_call({open, _Name, _Mode, _DTraceUtag}, _From, Handle) -> {reply, {error, einval}, Handle}; -handle_call({read_file, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file(Name), Handle}; +handle_call({read_file, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file(Name, DTraceUtag), Handle}; -handle_call({write_file, Name, Bin}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file(Name, Bin), Handle}; +handle_call({write_file, Name, Bin, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file(Name, Bin, DTraceUtag), Handle}; -handle_call({set_cwd, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:set_cwd(Handle, Name), Handle}; +handle_call({set_cwd, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:set_cwd(Handle, Name, DTraceUtag), Handle}; -handle_call({delete, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:delete(Handle, Name), Handle}; +handle_call({delete, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:delete(Handle, Name, DTraceUtag), Handle}; -handle_call({rename, Fr, To}, _From, Handle) -> - {reply, ?PRIM_FILE:rename(Handle, Fr, To), Handle}; +handle_call({rename, Fr, To, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:rename(Handle, Fr, To, DTraceUtag), Handle}; -handle_call({make_dir, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:make_dir(Handle, Name), Handle}; +handle_call({make_dir, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:make_dir(Handle, Name, DTraceUtag), Handle}; -handle_call({del_dir, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:del_dir(Handle, Name), Handle}; +handle_call({del_dir, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:del_dir(Handle, Name, DTraceUtag), Handle}; -handle_call({list_dir, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:list_dir(Handle, Name), Handle}; +handle_call({list_dir, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:list_dir(Handle, Name, DTraceUtag), Handle}; handle_call(get_cwd, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle), Handle}; -handle_call({get_cwd}, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle), Handle}; -handle_call({get_cwd, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle, Name), Handle}; + {reply, ?PRIM_FILE:get_cwd(Handle, no_drive, "TODO-fixme"), Handle}; +handle_call({get_cwd, no_drive, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:get_cwd(Handle, no_drive, DTraceUtag), Handle}; +handle_call({get_cwd, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:get_cwd(Handle, Name, DTraceUtag), Handle}; -handle_call({read_file_info, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file_info(Handle, Name), Handle}; +handle_call({read_file_info, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name, DTraceUtag), Handle}; +handle_call({read_file_info, Name, Opts, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts, DTraceUtag), Handle}; -handle_call({read_file_info, Name, Opts}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts), Handle}; +handle_call({altname, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:altname(Handle, Name, DTraceUtag), Handle}; -handle_call({altname, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:altname(Handle, Name), Handle}; +handle_call({write_file_info, Name, Info, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, DTraceUtag), Handle}; +handle_call({write_file_info, Name, Info, Opts, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts, DTraceUtag), Handle}; -handle_call({write_file_info, Name, Info}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info), Handle}; +handle_call({read_link_info, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name, DTraceUtag), Handle}; +handle_call({read_link_info, Name, Opts, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts, DTraceUtag), Handle}; -handle_call({write_file_info, Name, Info, Opts}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts), Handle}; +handle_call({read_link, Name, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link(Handle, Name, DTraceUtag), Handle}; -handle_call({read_link_info, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link_info(Handle, Name), Handle}; +handle_call({make_link, Old, New, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:make_link(Handle, Old, New, DTraceUtag), Handle}; -handle_call({read_link_info, Name, Opts}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts), Handle}; +handle_call({make_symlink, Old, New, DTraceUtag}, _From, Handle) -> + {reply, ?PRIM_FILE:make_symlink(Handle, Old, New, DTraceUtag), Handle}; -handle_call({read_link, Name}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link(Handle, Name), Handle}; - -handle_call({make_link, Old, New}, _From, Handle) -> - {reply, ?PRIM_FILE:make_link(Handle, Old, New), Handle}; - -handle_call({make_symlink, Old, New}, _From, Handle) -> - {reply, ?PRIM_FILE:make_symlink(Handle, Old, New), Handle}; - -handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length}, +handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length, DTraceUtag}, _From, Handle) -> Reply = - case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts]) of + case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts], + DTraceUtag) of {ok, Source} -> SourceReply = case ?PRIM_FILE:open(DestName, - [write, binary | DestOpts]) of + [write, binary | DestOpts], + DTraceUtag) of {ok, Dest} -> DestReply = - ?PRIM_FILE:copy(Source, Dest, Length), - ?PRIM_FILE:close(Dest), + ?PRIM_FILE:copy(Source, Dest, Length, DTraceUtag), + ?PRIM_FILE:close(Dest, DTraceUtag), DestReply; {error, _} = Error -> Error end, - ?PRIM_FILE:close(Source), + ?PRIM_FILE:close(Source, DTraceUtag), SourceReply; {error, _} = Error -> Error diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 3e2202922c..9575762b12 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -70,7 +70,7 @@ %% compile time. -define(PRIM_FILE_call(F, H, A), case H of - [] -> apply(?PRIM_FILE, F, A); + [] -> apply(?PRIM_FILE, F, A -- ["utag"]); _ -> apply(?PRIM_FILE, F, [H | A]) end). @@ -255,31 +255,31 @@ make_del_dir(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_mk-dir"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), - ?line {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), - ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), - ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), + ?line {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), + ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), % Make sure we are not in a directory directly under test_server % as that would result in eacess errors when trying to delere '..', % because there are processes having that directory as current. - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), ?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), try %% Check that we get an error when trying to create... %% a deep directory ?line NewDir2 = filename:join(RootDir, atom_to_list(?MODULE) ++"_mk-dir-noexist/foo"), - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]), + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2, "utag"]), %% a nameless directory - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]), + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, ["", "utag"]), %% a directory with illegal name - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']), + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir', "utag"]), %% a directory with illegal name, even if it's a (bad) list - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]), + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}], "utag"]), %% Maybe this isn't an error, exactly, but worth mentioning anyway: %% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])), @@ -292,17 +292,17 @@ make_del_dir(Config, Handle, Suffix) -> %% Try deleting some bad directories %% Deleting the parent directory to the current, sounds dangerous, huh? %% Don't worry ;-) the parent directory should never be empty, right? - ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of + ?line case ?PRIM_FILE_call(del_dir, Handle, ["..", "utag"]) of {error, eexist} -> ok; {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, - ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), - ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), + ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, ["", "utag"]), + ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}], "utag"]), ?line test_server:timetrap_cancel(Dog) after - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir]) + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir, "utag"]) end, ok. @@ -324,7 +324,7 @@ cur_dir_0(Config, Handle) -> %% Find out the current dir, and cd to it ;-) ?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []), ?line Dir1 = BaseDir ++ "", %% Check that it's a string - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), ?line DirName = atom_to_list(?MODULE) ++ case Handle of [] -> @@ -336,40 +336,40 @@ cur_dir_0(Config, Handle) -> %% Make a new dir, and cd to that ?line RootDir = ?config(priv_dir,Config), ?line NewDir = filename:join(RootDir, DirName), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), ?line io:format("cd to ~s",[NewDir]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), %% Create a file in the new current directory, and check that it %% really is created there ?line UncommonName = "uncommon.fil", ?line {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]), ?line ok = ?PRIM_FILE:close(Fd), - ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), + ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), ?line true = lists:member(UncommonName,NewDirFiles), %% Delete the directory and return to the old current directory %% and check that the created file isn't there (too!) ?line expect({error, einval}, {error, eacces}, {error, eexist}, - ?PRIM_FILE_call(del_dir, Handle, [NewDir])), - ?line ?PRIM_FILE_call(delete, Handle, [UncommonName]), - ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), + ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"])), + ?line ?PRIM_FILE_call(delete, Handle, [UncommonName, "utag"]), + ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), ?line io:format("cd back to ~s",[Dir1]), - ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), - ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), + ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), + ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), ?line io:format("cd back to ~s",[Dir1]), - ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), + ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), ?line false = lists:member(UncommonName,OldDirFiles), %% Try doing some bad things ?line {error, badarg} = - ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}]), + ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}, "utag"]), ?line {error, enoent} = - ?PRIM_FILE_call(set_cwd, Handle, [""]), + ?PRIM_FILE_call(set_cwd, Handle, ["", "utag"]), ?line {error, enoent} = - ?PRIM_FILE_call(set_cwd, Handle, [".......a......"]), + ?PRIM_FILE_call(set_cwd, Handle, [".......a......", "utag"]), ?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []), %% Still there? @@ -405,10 +405,10 @@ cur_dir_1(Config, Handle) -> ?line case os:type() of {unix, _} -> ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); + ?PRIM_FILE_call(get_cwd, Handle, ["d:", "utag"]); vxworks -> ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); + ?PRIM_FILE_call(get_cwd, Handle, ["d:", "utag"]); {win32, _} -> win_cur_dir_1(Config, Handle) end, @@ -422,7 +422,7 @@ win_cur_dir_1(_Config, Handle) -> %% and try to get current directory for that drive. ?line [Drive, $:|_] = BaseDir, - ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:]]), + ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:], "utag"]), io:format("BaseDir = ~s\n", [BaseDir]), %% Unfortunately, there is no way to move away from the @@ -1027,7 +1027,7 @@ file_write_file_info(Config, Handle, Suffix) -> ?line ok = ?PRIM_FILE:write_file(Name, "hello"), ?line Time = {{1997, 01, 02}, {12, 35, 42}}, ?line Info = #file_info{mode=8#400, atime=Time, mtime=Time, ctime=Time}, - ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info]), + ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info, "utag"]), %% Read back the times. @@ -1050,12 +1050,12 @@ file_write_file_info(Config, Handle, Suffix) -> %% Make the file writable again. ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#600}]), + [Name, #file_info{mode=8#600}, "utag"]), ?line ok = ?PRIM_FILE:write_file(Name, "hello again"), %% And unwritable. ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#400}]), + [Name, #file_info{mode=8#400}, "utag"]), ?line {error, eacces} = ?PRIM_FILE:write_file(Name, "hello again"), %% Write the times again. @@ -1063,7 +1063,7 @@ file_write_file_info(Config, Handle, Suffix) -> ?line NewTime = {{1997, 02, 15}, {13, 18, 20}}, ?line NewInfo = #file_info{atime=NewTime, mtime=NewTime, ctime=NewTime}, - ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo]), + ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo, "utag"]), ?line {ok, ActualInfo2} = ?PRIM_FILE_call(read_file_info, Handle, [Name]), ?line #file_info{atime=NewActAtime, mtime=NewTime, @@ -1081,7 +1081,7 @@ file_write_file_info(Config, Handle, Suffix) -> %% Make the file writeable again, so that we can remove the %% test suites ... :-) ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#600}]), + [Name, #file_info{mode=8#600}, "utag"]), ?line test_server:timetrap_cancel(Dog), ok. @@ -1390,11 +1390,11 @@ delete(Config, Handle, Suffix) -> %% Check that the file is readable ?line {ok, Fd2} = ?PRIM_FILE:open(Name, [read]), ?line ok = ?PRIM_FILE:close(Fd2), - ?line ok = ?PRIM_FILE_call(delete, Handle, [Name]), + ?line ok = ?PRIM_FILE_call(delete, Handle, [Name, "utag"]), %% Check that the file is not readable anymore ?line {error, _} = ?PRIM_FILE:open(Name, [read]), %% Try deleting a nonexistent file - ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name]), + ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name, "utag"]), ?line test_server:timetrap_cancel(Dog), ok. @@ -1895,14 +1895,14 @@ make_link(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_make_link"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), ?line Name = filename:join(NewDir, "a_file"), ?line ok = ?PRIM_FILE:write_file(Name, "some contents\n"), ?line Alias = filename:join(NewDir, "an_alias"), ?line Result = - case ?PRIM_FILE_call(make_link, Handle, [Name, Alias]) of + case ?PRIM_FILE_call(make_link, Handle, [Name, Alias, "utag"]) of {error, enotsup} -> {skipped, "Links not supported on this platform"}; ok -> @@ -1913,12 +1913,12 @@ make_link(Config, Handle, Suffix) -> %% since they are not used on symbolic links. ?line {ok, Info} = - ?PRIM_FILE_call(read_link_info, Handle, [Name]), + ?PRIM_FILE_call(read_link_info, Handle, [Name, "utag"]), ?line {ok, Info} = - ?PRIM_FILE_call(read_link_info, Handle, [Alias]), + ?PRIM_FILE_call(read_link_info, Handle, [Alias, "utag"]), ?line #file_info{links = 2, type = regular} = Info, ?line {error, eexist} = - ?PRIM_FILE_call(make_link, Handle, [Name, Alias]), + ?PRIM_FILE_call(make_link, Handle, [Name, Alias, "utag"]), ok end, @@ -1956,30 +1956,30 @@ symlinks(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_make_symlink"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), ?line Name = filename:join(NewDir, "a_plain_file"), ?line ok = ?PRIM_FILE:write_file(Name, "some stupid content\n"), ?line Alias = filename:join(NewDir, "a_symlink_alias"), ?line Result = - case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias]) of + case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias, "utag"]) of {error, enotsup} -> {skipped, "Links not supported on this platform"}; ok -> ?line {ok, Info1} = - ?PRIM_FILE_call(read_file_info, Handle, [Name]), + ?PRIM_FILE_call(read_file_info, Handle, [Name, "utag"]), ?line {ok, Info1} = - ?PRIM_FILE_call(read_file_info, Handle, [Alias]), + ?PRIM_FILE_call(read_file_info, Handle, [Alias, "utag"]), ?line {ok, Info1} = - ?PRIM_FILE_call(read_link_info, Handle, [Name]), + ?PRIM_FILE_call(read_link_info, Handle, [Name, "utag"]), ?line #file_info{links = 1, type = regular} = Info1, ?line {ok, Info2} = - ?PRIM_FILE_call(read_link_info, Handle, [Alias]), + ?PRIM_FILE_call(read_link_info, Handle, [Alias, "utag"]), ?line #file_info{links=1, type=symlink} = Info2, ?line {ok, Name} = - ?PRIM_FILE_call(read_link, Handle, [Alias]), + ?PRIM_FILE_call(read_link, Handle, [Alias, "utag"]), ok end, @@ -2003,7 +2003,7 @@ list_dir_limit(Config) when is_list(Config) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE)++"_list_dir_limit"), ?line {ok, Handle1} = ?PRIM_FILE:start(), - ?line ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir, "utag"]), Ref = erlang:start_timer(MaxTime*1000, self(), []), ?line Result = list_dir_limit_loop(NewDir, Handle1, Ref, MaxNumber, 0), ?line Time = case erlang:cancel_timer(Ref) of @@ -2054,7 +2054,7 @@ list_dir_limit_loop(Dir, Handle, Ref, N, Cnt) -> end. list_dir_check(Dir, Handle, Cnt) -> - case ?PRIM_FILE:list_dir(Handle, Dir) of + case ?PRIM_FILE:list_dir(Handle, Dir, "utag") of {ok, ListDir} -> case length(ListDir) of Cnt -> -- cgit v1.2.3 From 0fd4e39abeea3fc87b78eec8495109f9245b5ac8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Tue, 7 Feb 2012 19:19:27 +0100 Subject: Update dtrace for changes in R15 --- README.dtrace.md | 37 ++++++-------- erts/emulator/Makefile.in | 6 ++- erts/emulator/beam/beam_emu.c | 85 ++++++------------------------- erts/emulator/beam/dist.c | 16 ++++-- erts/emulator/beam/dtrace-wrapper.h | 9 ---- erts/emulator/beam/erl_async.c | 10 ++-- erts/emulator/beam/erl_gc.c | 1 - erts/emulator/beam/erl_message.c | 12 +++-- erts/emulator/beam/global.h | 69 ++++++++++++++++++++++--- erts/emulator/drivers/common/efile_drv.c | 26 ++++++---- erts/lib_src/common/erl_printf.c | 2 +- erts/preloaded/ebin/prim_file.beam | Bin 46840 -> 46736 bytes erts/preloaded/src/prim_file.erl | 22 ++++---- lib/dtrace/c_src/Makefile | 2 +- lib/dtrace/c_src/Makefile.in | 15 +++--- lib/dtrace/c_src/dtrace.c | 16 ++---- lib/dtrace/examples/dist.d | 14 ++--- lib/dtrace/examples/port1.d | 8 +-- lib/dtrace/examples/process-scheduling.d | 2 +- lib/dtrace/src/dtrace.erl | 38 ++++++++++++-- lib/kernel/src/file.erl | 8 +-- lib/kernel/src/file_server.erl | 6 +-- 22 files changed, 216 insertions(+), 188 deletions(-) diff --git a/README.dtrace.md b/README.dtrace.md index 71023dfe69..bbff233ed9 100644 --- a/README.dtrace.md +++ b/README.dtrace.md @@ -27,27 +27,17 @@ Goals Supported platforms ------------------- -The autoconf procedure is supported, I believe, for OS X/Snow Leopard -and OpenSolaris/64-bit. Just add the `--enable-dtrace` option your -command to run the `configure` script. - -The code has been only very lightly tested on OS X. It ought to -compile on a Solaris 10 or OpenSolaris machine, but no promises yet. - -The autoconf stuff is ugly right now. It could use some cleaning up. -For example: - -* After editing the `erlang_dtrace.d` file, you need to re-run the -* top-level "configure" script in order to update `erlang_dtrace.h`. -* `make clean` will remove `erlang_dtrace.h`. A build will fail - unless the top-level "configure" script is re-run to re-create that - file. -* The `erlang_dtrace.h` file's location should probably be moved to an - OTP platform-specific build dir, for example, - `path/to/somewhere/i386-apple-darwin10.8.0` -* There are probably some other build by-products that are also being - put into the "wrong" directory, for example, `erlang_dtrace.o` for - Solaris platforms. +* OS X 10.6.x / Snow Leopard. It should also work for 10.7 / Lion, + but I haven't personally tested it. +* Solaris 10. I have done limited testing on Solaris 11 and + OpenIndiana release 151a, and both appear to work. +* FreeBSD 9.0, though please see the "FreeBSD 9.0 Release Notes" + section below! +* Linux via SystemTap compatibility. Please see the file + `README.systemtap.md` for more details. + +Just add the `--enable-dtrace` option to your command when you run the +`configure` script. Contributions ------------- @@ -61,9 +51,12 @@ To build from scratch, use this recipe. If you're an experienced Git user and wish to add my repository as a remote repository, be my guest. Just resume the recipe at command #4. +NOTE: The `dtrace-experiment+michal2` branch is used for changes that +can be applied to both R14B and R15 releases. + % git clone git://github.com/slfritchie/otp.git % cd otp - % git checkout -b dtrace-experiment origin/dtrace-experiment + % git checkout -b dtrace-experiment+michal2 origin/dtrace-experiment+michal2 % env ERL_TOP=`pwd` ./otp_build autoconf % env ERL_TOP=`pwd` ./configure --enable-dtrace + whatever args you need % env ERL_TOP=`pwd` make diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 3fb0964810..d8fad98de2 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -486,7 +486,11 @@ endif endif ifdef DTRACE_ENABLED -GENERATE += $(TARGET)/erlang_dtrace.h +# global.h causes problems by including dtrace-wrapper.h which includes +# the autogenerated erlang_dtrace.h ... so make erlang_dtrace.h very early. +generate: $(TARGET)/erlang_dtrace.h $(GENERATE) +else +generate: $(GENERATE) endif ifdef HIPE_ENABLED diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index d0beccfda2..1dbe2cad00 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -41,8 +41,6 @@ #include "hipe_mode_switch.h" #include "hipe_bif1.h" #endif - -#include #include "dtrace-wrapper.h" /* #define HARDDEBUG 1 */ @@ -1053,72 +1051,6 @@ init_emulator(void) # define REG_tmp_arg2 #endif -ERTS_INLINE void -dtrace_proc_str(Process *process, char *process_buf) -{ - dtrace_pid_str(process->id, process_buf); -} - -ERTS_INLINE void -dtrace_pid_str(Eterm pid, char *process_buf) -{ - snprintf(process_buf, DTRACE_TERM_BUF_SIZE, "<%lu.%lu.%lu>", - pid_channel_no(pid), - pid_number(pid), - pid_serial(pid)); -} - -ERTS_INLINE void -dtrace_port_str(Port *port, char *port_buf) -{ - snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>", - port_channel_no(port->id), - port_number(port->id)); -} - -ERTS_INLINE void -dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) -{ - Port *port = erts_drvport2port(drvport); - - snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>", - port_channel_no(port->id), - port_number(port->id)); -} - -ERTS_INLINE void -dtrace_fun_decode(Process *process, - Eterm module, Eterm function, int arity, - char *process_buf, char *mfa_buf) -{ - char funbuf[DTRACE_TERM_BUF_SIZE]; - char *funptr = funbuf; - char *p = NULL; - - if (process_buf) { - dtrace_proc_str(process, process_buf); - } - - erts_snprintf(funbuf, sizeof(funbuf), "%T", function); - /* - * I'm not quite sure how these function names are synthesized, - * but they almost always seem to be in the form of - * '-name/arity-fun-0-' so I'm chopping them up when it's -fun-0- - * (which seems to be the toplevel) - */ - if (funbuf[0] == '\'' && funbuf[1] == '-' - && strlen(funbuf) > 3 && funbuf[strlen(funbuf) - 3] == '0') { - p = strchr(funbuf, '/'); - if (p) { - *p = 0; - } - funptr += 2; - } - - erts_snprintf(mfa_buf, DTRACE_TERM_BUF_SIZE, "%T:%s/%d", - module, funptr, arity); -} - #ifdef HAVE_DTRACE #define DTRACE_CALL(p, m, f, a) \ @@ -1190,6 +1122,16 @@ dtrace_fun_decode(Process *process, #endif /* HAVE_DTRACE */ +void +dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) +{ + Port *port = erts_drvport2port(drvport); + + erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>", + port_channel_no(port->id), + port_number(port->id)); +} + /* * process_main() is called twice: * The first call performs some initialisation, including exporting @@ -1376,7 +1318,8 @@ void process_main(void) (Eterm)fptr[1], (Uint)fptr[2], NULL, fun_buf); } else { - snprintf(fun_buf, sizeof(fun_buf), "", next); + erts_snprintf(fun_buf, sizeof(fun_buf), + "", next); } } @@ -1970,7 +1913,9 @@ void process_main(void) if (DTRACE_ENABLED(message_receive)) { Eterm token2 = NIL; DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); - Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + ERTS_DECLARE_DUMMY(Sint tok_label) = 0; + ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; + ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; dtrace_proc_str(c_p, receiver_name); token2 = SEQ_TRACE_TOKEN(c_p); diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 6f6b04d278..ba55a1918a 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -741,8 +741,10 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) Eterm token = NIL; Process *sender = dsdp->proc; int res; - Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; - Uint msize = 0; + ERTS_DECLARE_DUMMY(Sint tok_label) = 0; + ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; + ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; + ERTS_DECLARE_DUMMY(Uint msize) = 0; DTRACE_CHARBUF(node_name, 64); DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(receiver_name, 64); @@ -788,8 +790,10 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) Eterm token = NIL; Process *sender = dsdp->proc; int res; - Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; - Uint32 msize = 0; + ERTS_DECLARE_DUMMY(Sint tok_label) = 0; + ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; + ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; + ERTS_DECLARE_DUMMY(Uint32 msize) = 0; DTRACE_CHARBUF(node_name, 64); DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(receiver_name, 128); @@ -838,7 +842,9 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, DeclareTmpHeapNoproc(ctl_heap,6); int res; Process *sender = dsdp->proc; - Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + ERTS_DECLARE_DUMMY(Sint tok_label) = 0; + ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; + ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; DTRACE_CHARBUF(node_name, 64); DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(remote_name, 128); diff --git a/erts/emulator/beam/dtrace-wrapper.h b/erts/emulator/beam/dtrace-wrapper.h index f93871bd25..b633058e90 100644 --- a/erts/emulator/beam/dtrace-wrapper.h +++ b/erts/emulator/beam/dtrace-wrapper.h @@ -23,15 +23,6 @@ #define DTRACE_TERM_BUF_SIZE 256 -#ifndef DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS -inline void dtrace_proc_str(Process *process, char *process_buf); -inline void dtrace_pid_str(Eterm pid, char *process_buf); -inline void dtrace_port_str(Port *port, char *port_buf); -inline void dtrace_fun_decode(Process *process, - Eterm module, Eterm function, int arity, - char *process_buf, char *mfa_buf); -#endif - /* * Some varieties of SystemTap macros do not like statically-sized * char[N] buffers. (For example, CentOS 6's macros.) diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index 72dcc99f4f..b8cb3c6cc4 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -253,8 +253,7 @@ erts_get_async_ready_queue(Uint sched_id) static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) { - /* DTRACE TODO: Get the queue length from erts_thr_q_enqueue() */ - int len = -1; + int len; if (is_internal_port(a->port)) { #if ERTS_USE_ASYNC_READY_Q @@ -275,6 +274,8 @@ static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) DTRACE_CHARBUF(port_str, 16); erts_snprintf(port_str, sizeof(port_str), "%T", a->port); + /* DTRACE TODO: Get the queue length from erts_thr_q_enqueue() ? */ + len = -1; DTRACE2(aio_pool_add, port_str, len); } gcc_optimizer_hack++; @@ -288,8 +289,7 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, int saved_fin_deq = 0; ErtsThrQFinDeQ_t fin_deq; #endif - /* DTRACE TODO: Get the queue length from erts_thr_q_dequeue() somehow? */ - int len = -1; + int len; while (1) { ErtsAsync *a = (ErtsAsync *) erts_thr_q_dequeue(q); @@ -305,6 +305,8 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, DTRACE_CHARBUF(port_str, 16); erts_snprintf(port_str, sizeof(port_str), "%T", a->port); + /* DTRACE TODO: Get the length from erts_thr_q_dequeue() ? */ + len = -1; DTRACE2(aio_pool_get, port_str, len); } return a; diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 858ae32ad5..679a3645ba 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -2055,7 +2055,6 @@ shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj) Uint heap_size = HEAP_TOP(p) - HEAP_START(p); Sint offs; Uint stack_size = p->hend - p->stop; - char pidbuf[DTRACE_TERM_BUF_SIZE]; ASSERT(new_sz < p->heap_sz); sys_memmove(p->heap + new_sz - stack_size, p->stop, stack_size * diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 8489353c9e..786d6ac52c 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -336,7 +336,9 @@ erts_queue_dist_message(Process *rcvr, Eterm token) { ErlMessage* mp; - Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + ERTS_DECLARE_DUMMY(Sint tok_label) = 0; + ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; + ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; #ifdef ERTS_SMP ErtsProcLocks need_locks; #endif @@ -495,7 +497,9 @@ erts_queue_message(Process* receiver, if (DTRACE_ENABLED(message_queued)) { DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); - Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + ERTS_DECLARE_DUMMY(Sint tok_label) = 0; + ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; + ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; dtrace_proc_str(receiver, receiver_name); if (seq_trace_token != NIL && is_tuple(seq_trace_token)) { @@ -822,7 +826,9 @@ erts_send_message(Process* sender, Eterm token = NIL; DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(receiver_name, 64); - Sint tok_label = 0, tok_lastcnt = 0, tok_serial = 0; + ERTS_DECLARE_DUMMY(Sint tok_label) = 0; + ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; + ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; BM_STOP_TIMER(system); BM_MESSAGE(message,sender,receiver); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 6f6263d160..7f12004b43 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1072,13 +1072,6 @@ void process_main(void); Eterm build_stacktrace(Process* c_p, Eterm exc); Eterm expand_error_value(Process* c_p, Uint freason, Eterm Value); void erts_save_stacktrace(Process* p, struct StackTrace* s, int depth); -ERTS_INLINE void dtrace_proc_str(Process *process, char *process_buf); -ERTS_INLINE void dtrace_pid_str(Eterm pid, char *process_buf); -ERTS_INLINE void dtrace_port_str(Port *port, char *port_buf); -ERTS_INLINE void dtrace_drvport_str(ErlDrvPort port, char *port_buf); -ERTS_INLINE void dtrace_fun_decode(Process *process, - Eterm module, Eterm function, int arity, - char *process_buf, char *mfa_buf); /* erl_init.c */ @@ -1981,4 +1974,66 @@ erts_alloc_message_heap(Uint size, # define UseTmpHeapNoproc(Size) /* Nothing */ # define UnUseTmpHeapNoproc(Size) /* Nothing */ #endif /* HEAP_ON_C_STACK */ + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +#include "dtrace-wrapper.h" + +ERTS_GLB_INLINE void +dtrace_pid_str(Eterm pid, char *process_buf) +{ + erts_snprintf(process_buf, DTRACE_TERM_BUF_SIZE, "<%lu.%lu.%lu>", + pid_channel_no(pid), + pid_number(pid), + pid_serial(pid)); +} + +ERTS_GLB_INLINE void +dtrace_proc_str(Process *process, char *process_buf) +{ + dtrace_pid_str(process->id, process_buf); +} + +ERTS_GLB_INLINE void +dtrace_port_str(Port *port, char *port_buf) +{ + erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>", + port_channel_no(port->id), + port_number(port->id)); +} + +ERTS_GLB_INLINE void +dtrace_fun_decode(Process *process, + Eterm module, Eterm function, int arity, + char *process_buf, char *mfa_buf) +{ + char funbuf[DTRACE_TERM_BUF_SIZE]; + char *funptr = funbuf; + char *p = NULL; + + if (process_buf) { + dtrace_proc_str(process, process_buf); + } + + erts_snprintf(funbuf, sizeof(funbuf), "%T", function); + /* + * I'm not quite sure how these function names are synthesized, + * but they almost always seem to be in the form of + * '-name/arity-fun-0-' so I'm chopping them up when it's -fun-0- + * (which seems to be the toplevel) + */ + if (funbuf[0] == '\'' && funbuf[1] == '-' + && strlen(funbuf) > 3 && funbuf[strlen(funbuf) - 3] == '0') { + p = strchr(funbuf, '/'); + if (p) { + *p = 0; + } + funptr += 2; + } + + erts_snprintf(mfa_buf, DTRACE_TERM_BUF_SIZE, "%T:%s/%d", + module, funptr, arity); +} +#endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ + #endif /* !__GLOBAL_H__ */ diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index b72f95792c..293f024e45 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -112,7 +112,6 @@ #include "erl_threads.h" #include "zlib.h" #include "gzio.h" -#define DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS #include "dtrace-wrapper.h" #include #include @@ -126,6 +125,8 @@ static unsigned gcc_optimizer_hack = 0; #ifdef HAVE_DTRACE +#define DTRACE_EFILE_BUFSIZ 128 + #define DTRACE_INVOKE_SETUP(op) \ do { DTRACE3(efile_drv_int_entry, d->sched_i1, d->sched_i2, op); } while (0) #define DTRACE_INVOKE_SETUP_BY_NAME(op) \ @@ -149,6 +150,7 @@ typedef struct { dt_private *get_dt_private(int); #else /* HAVE_DTRACE */ typedef struct { + char dummy; /* Unused except to quiet some compilers */ } dt_private; #define DTRACE_INVOKE_SETUP(op) do {} while (0) @@ -429,7 +431,7 @@ struct t_data #ifdef HAVE_DTRACE int sched_i1; Uint64 sched_i2; - char sched_utag[128+1]; + char sched_utag[DTRACE_EFILE_BUFSIZ+1]; #else char sched_utag[1]; #endif @@ -2196,12 +2198,12 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) int sched_i1 = d->sched_i1, sched_i2 = d->sched_i2, command = d->command, result_ok = d->result_ok, posix_errno = d->result_ok ? 0 : d->errInfo.posix_errno; - DTRACE_CHARBUF(sched_utag, 128+1); + DTRACE_CHARBUF(sched_utag, DTRACE_EFILE_BUFSIZ+1); sched_utag[0] = '\0'; if (DTRACE_ENABLED(efile_drv_return)) { - strncpy(sched_utag, d->sched_utag, sizeof(sched_utag) - 1); - sched_utag[sizeof(sched_utag) - 1] = '\0'; + strncpy(sched_utag, d->sched_utag, DTRACE_EFILE_BUFSIZ); + sched_utag[DTRACE_EFILE_BUFSIZ] = '\0'; } #endif /* HAVE_DTRACE */ @@ -2488,8 +2490,12 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) char* name; /* Points to the filename in buf. */ int command; struct t_data *d = NULL; - char *dt_utag = NULL, *dt_s1 = NULL, *dt_s2 = NULL; - Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0, dt_i4 = 0; + ERTS_DECLARE_DUMMY(char *dt_utag) = NULL; + char *dt_s1 = NULL, *dt_s2 = NULL; + ERTS_DECLARE_DUMMY(Sint64 dt_i1) = 0; + ERTS_DECLARE_DUMMY(Sint64 dt_i2) = 0; + ERTS_DECLARE_DUMMY(Sint64 dt_i3) = 0; + ERTS_DECLARE_DUMMY(Sint64 dt_i4) = 0; #ifdef HAVE_DTRACE dt_private *dt_priv = get_dt_private(0); #endif /* HAVE_DTRACE */ @@ -3015,8 +3021,10 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { int p, q; int err; struct t_data *d = NULL; - Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0, dt_i4 = 0; - char *dt_utag = NULL, *dt_s1 = NULL; + Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; + ERTS_DECLARE_DUMMY(Sint64 dt_i4) = 0; + char *dt_utag = NULL; + ERTS_DECLARE_DUMMY(char *dt_s1) = NULL; #ifdef HAVE_DTRACE dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); #else diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c index afb9c0abb7..399c83384e 100644 --- a/erts/lib_src/common/erl_printf.c +++ b/erts/lib_src/common/erl_printf.c @@ -173,10 +173,10 @@ typedef struct { static int write_sn(void *vwsnap, char* buf, size_t len) { + int rv = 0; write_sn_arg_t *wsnap = (write_sn_arg_t *) vwsnap; ASSERT(wsnap); ASSERT(len > 0); - int rv = 0; if (wsnap->len > 0) { size_t sz = len; if (sz >= wsnap->len) diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index 9d6c47ffc1..6778fe353c 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 5c9cad3a2c..46ce3ab1a4 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -1493,19 +1493,15 @@ to_seconds({_,_} = Datetime, universal) -> to_seconds({_,_} = Datetime, local) -> erlang:universaltime_to_posixtime(erlang:localtime_to_universaltime(Datetime)). -%% TODO: Duplicate code! get_dtrace_utag() -> - case get(dtrace_utag) of - X when is_list(X) -> - X; - _ -> - "" + %% We cannot call dtrace:get_utag() because this is prim_file.erl. + %% We must reimplement it here. + case get('_dtrace_utag_@_@') of + undefined -> + <<>>; + X -> + X end. -%% TODO: Measure if it's worth checking (re:run()?) for NUL byte first? -enc_utag([0|Cs]) -> - enc_utag(Cs); -enc_utag([C|Cs]) -> - [C|enc_utag(Cs)]; -enc_utag([]) -> - [0]. +enc_utag(UTag) -> + [UTag, 0]. diff --git a/lib/dtrace/c_src/Makefile b/lib/dtrace/c_src/Makefile index f3320bb766..a65491d45d 100644 --- a/lib/dtrace/c_src/Makefile +++ b/lib/dtrace/c_src/Makefile @@ -1,4 +1,4 @@ # -# Invoke with GNU make or clearmake -C gnu. +# Invoke with GNU make # include $(ERL_TOP)/make/run_make.mk diff --git a/lib/dtrace/c_src/Makefile.in b/lib/dtrace/c_src/Makefile.in index ed13684a95..831ce5ce75 100644 --- a/lib/dtrace/c_src/Makefile.in +++ b/lib/dtrace/c_src/Makefile.in @@ -72,7 +72,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/dtrace-$(VSN) # ---------------------------------------------------- # Misc Macros # ---------------------------------------------------- -OBJS = $(OBJDIR)/dtrace$(TYPEMARKER).o +before_DTrace_OBJS = $(OBJDIR)/dtrace$(TYPEMARKER).o ## NIF_MAKEFILE = $(PRIVDIR)/Makefile # Higher-level makefiles says that we can only compile on UNIX flavors @@ -100,18 +100,17 @@ else DTRACE_USER_HEADER= endif +DTRACE_OBJS = ifdef DTRACE_ENABLED_2STEP -OBJS += $(OBJDIR)/dtrace_user.o -$(OBJDIR)/dtrace_user.o: $(OBJS) $(OBJDIR)/dtrace_user.h - touch $(OBJDIR)/erlang_dtrace.c - $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/erlang_dtrace.c - # The object file created above is immediately clobbered below. - # But creating it above avoids chicken-and-egg problem with OBJS +DTRACE_OBJS += $(OBJDIR)/dtrace_user.o +$(OBJDIR)/dtrace_user.o: $(before_DTrace_OBJS) $(OBJDIR)/dtrace_user.h dtrace -G -C \ -s ./dtrace_user.d \ - -o $@ $(OBJS) + -o $@ $(before_DTrace_OBJS) endif +OBJS = $(before_DTrace_OBJS) $(DTRACE_OBJS) + $(OBJDIR): -@mkdir -p $(OBJDIR) diff --git a/lib/dtrace/c_src/dtrace.c b/lib/dtrace/c_src/dtrace.c index c9d25ece9c..90bb39a4b8 100644 --- a/lib/dtrace/c_src/dtrace.c +++ b/lib/dtrace/c_src/dtrace.c @@ -25,7 +25,6 @@ #include "erl_nif.h" #include "config.h" #include "sys.h" -#define DTRACE_DRIVER_SKIP_FUNC_DECLARATIONS #include "dtrace-wrapper.h" #ifdef HAVE_DTRACE #include "dtrace_user.h" @@ -144,8 +143,7 @@ static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM if (DTRACE_ENABLED(user_trace_i4s4)) { dtrace_nifenv_str(env, procbuf); - get_string_maybe(env, argv[0], &utbuf, - user_tagbuf, sizeof(user_tagbuf)-1); + get_string_maybe(env, argv[0], &utbuf, user_tagbuf, MESSAGE_BUFSIZ); if (! enif_get_int64(env, argv[1], &i1)) i1 = 0; if (! enif_get_int64(env, argv[2], &i2)) @@ -154,14 +152,10 @@ static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM i3 = 0; if (! enif_get_int64(env, argv[4], &i4)) i4 = 0; - get_string_maybe(env, argv[5], &mbuf1, - messagebuf1, sizeof(messagebuf1)-1); - get_string_maybe(env, argv[6], &mbuf2, - messagebuf2, sizeof(messagebuf2)-1); - get_string_maybe(env, argv[7], &mbuf3, - messagebuf3, sizeof(messagebuf3)-1); - get_string_maybe(env, argv[8], &mbuf4, - messagebuf4, sizeof(messagebuf4)-1); + get_string_maybe(env, argv[5], &mbuf1, messagebuf1, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[6], &mbuf2, messagebuf2, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[7], &mbuf3, messagebuf3, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[8], &mbuf4, messagebuf4, MESSAGE_BUFSIZ); DTRACE10(user_trace_i4s4, procbuf, utbuf, i1, i2, i3, i4, mbuf1, mbuf2, mbuf3, mbuf4); return atom_true; diff --git a/lib/dtrace/examples/dist.d b/lib/dtrace/examples/dist.d index f37c827f14..550e10d363 100644 --- a/lib/dtrace/examples/dist.d +++ b/lib/dtrace/examples/dist.d @@ -30,13 +30,13 @@ erlang*:::dist-port_busy { printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); - blocked_procs[copyinstr(arg3)] = timestamp; -} - -erlang*:::dist-port_busy -{ - printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); + /* + * For variable use advice, see: + * http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types/ + * + * Howevever, it's quite possible for the blocked events to span + * threads, so we'll use globals. + */ blocked_procs[copyinstr(arg3)] = timestamp; } diff --git a/lib/dtrace/examples/port1.d b/lib/dtrace/examples/port1.d index b82e783a14..204abbd3b8 100644 --- a/lib/dtrace/examples/port1.d +++ b/lib/dtrace/examples/port1.d @@ -99,10 +99,12 @@ erlang*:::port-command erlang*:::port-control { - cmd = driver_map[copyinstr(arg2), arg3]; - cmd_str = (cmd == 0) ? "unknown" : cmd; + /* http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types/ */ + this->cmd = driver_map[copyinstr(arg2), arg3]; + this->cmd_str = (this->cmd == 0) ? "unknown" : this->cmd; printf("port control pid %s port %s port name %s command %d %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, cmd_str); + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, + this->cmd_str); } /* port-exit is fired as a result of port_close() or exit signal */ diff --git a/lib/dtrace/examples/process-scheduling.d b/lib/dtrace/examples/process-scheduling.d index 9e31da2774..79e9cc598c 100644 --- a/lib/dtrace/examples/process-scheduling.d +++ b/lib/dtrace/examples/process-scheduling.d @@ -31,5 +31,5 @@ erlang*:::process-unscheduled erlang*:::process-hibernate { printf(" Hibernate pid %s resume mfa %s\n", - copyinstr(arg0), copyinstr(arg1)); + copyinstr(arg0), copyinstr(arg1)); } diff --git a/lib/dtrace/src/dtrace.erl b/lib/dtrace/src/dtrace.erl index 45addafc53..6951c03215 100644 --- a/lib/dtrace/src/dtrace.erl +++ b/lib/dtrace/src/dtrace.erl @@ -14,8 +14,8 @@ %%% four integer arguments and four string arguments; the integer %%% argument(s) must come before any string argument. For example: %%% ``` -%%% 1> put(dtrace_utag, "GGOOOAAALL!!!!!"). -%%% undefined +%%% 1> dtrace:put_tag("GGOOOAAALL!!!!!"). +%%% true %%% 2> dtrace:init(). %%% ok %%% @@ -35,9 +35,13 @@ %%% then the driver will ignore the user's input and use a default %%% value of 0 or NULL, respectively. +-define(DTRACE_UT_KEY, '_dtrace_utag_@_@'). % Match prim_file:get_dtrace_utag()! + -export([init/0, available/0, user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). +-export([put_utag/1, get_utag/0]). + -export([scaff/0]). % Development only -export([user_trace_i4s4/9]). % Know what you're doing! @@ -68,7 +72,7 @@ available() -> -spec user_trace_s1(iolist()) -> true | false | error | badarg. -user_trace_s1(Message) -> +user_trace_s1(_Message) -> erlang:nif_error(nif_not_loaded). -spec user_trace_i4s4(iolist(), @@ -176,8 +180,32 @@ p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_intege true | false | error | badarg. user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> - UTag = prim_file:get_dtrace_utag(), - user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4). + UTag = get_utag(), + try + user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4) + catch + error:nif_not_loaded -> + false + end. + +-spec put_utag(undefined | iolist()) -> ok. + +put_utag(undefined) -> + put_utag(<<>>); +put_utag(T) when is_binary(T) -> + put(?DTRACE_UT_KEY, T), + ok; +put_utag(T) when is_list(T) -> + put(?DTRACE_UT_KEY, list_to_binary(T)), + ok. + +get_utag() -> + case get(?DTRACE_UT_KEY) of + undefined -> + <<>>; + X -> + X + end. %% Scaffolding to write tedious code: quick brute force and not 100% correct. diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index a2e0d261ee..aecb9f7923 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -227,7 +227,7 @@ read_file_info(Name) -> Reason :: posix() | badarg. read_file_info(Name, Opts) when is_list(Opts) -> - check_and_call(read_file_info, [file_name(Name), Opts]). + check_and_call(read_file_info, [file_name(Name), Opts, get_dtrace_utag()]). -spec altname(Name :: name()) -> any(). @@ -249,7 +249,7 @@ read_link_info(Name) -> Reason :: posix() | badarg. read_link_info(Name, Opts) when is_list(Opts) -> - check_and_call(read_link_info, [file_name(Name),Opts]). + check_and_call(read_link_info, [file_name(Name),Opts, get_dtrace_utag()]). -spec read_link(Name) -> {ok, Filename} | {error, Reason} when @@ -275,7 +275,7 @@ write_file_info(Name, Info = #file_info{}) -> Reason :: posix() | badarg. write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> - check_and_call(write_file_info, [file_name(Name), Info, Opts]). + check_and_call(write_file_info, [file_name(Name), Info, Opts, get_dtrace_utag()]). -spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when Dir :: name(), @@ -1504,4 +1504,4 @@ wait_file_reply(From, Ref) -> end. get_dtrace_utag() -> - prim_file:get_dtrace_utag(). + dtrace:get_utag(). diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl index c917819508..82adc45795 100644 --- a/lib/kernel/src/file_server.erl +++ b/lib/kernel/src/file_server.erl @@ -146,7 +146,7 @@ handle_call({get_cwd, Name, DTraceUtag}, _From, Handle) -> {reply, ?PRIM_FILE:get_cwd(Handle, Name, DTraceUtag), Handle}; handle_call({read_file_info, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file_info(Handle, Name, DTraceUtag), Handle}; + {reply, ?PRIM_FILE:read_file_info(Handle, Name, [], DTraceUtag), Handle}; handle_call({read_file_info, Name, Opts, DTraceUtag}, _From, Handle) -> {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts, DTraceUtag), Handle}; @@ -154,12 +154,12 @@ handle_call({altname, Name, DTraceUtag}, _From, Handle) -> {reply, ?PRIM_FILE:altname(Handle, Name, DTraceUtag), Handle}; handle_call({write_file_info, Name, Info, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, DTraceUtag), Handle}; + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, [], DTraceUtag), Handle}; handle_call({write_file_info, Name, Info, Opts, DTraceUtag}, _From, Handle) -> {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts, DTraceUtag), Handle}; handle_call({read_link_info, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link_info(Handle, Name, DTraceUtag), Handle}; + {reply, ?PRIM_FILE:read_link_info(Handle, Name, [], DTraceUtag), Handle}; handle_call({read_link_info, Name, Opts, DTraceUtag}, _From, Handle) -> {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts, DTraceUtag), Handle}; -- cgit v1.2.3 From c15f94e7922040b63f3abf8680cd77d5548fecf3 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Mon, 13 Feb 2012 20:13:37 +0100 Subject: Add user tag spreading functionality to VM and use in file User tags in a dynamic trace enabled VM are spread throughout the system in the same way as seq_trace tokens. This is used by the file module and various other modules to get hold of the tag from the user process without changing the protocol. --- erts/emulator/beam/atom.names | 1 + erts/emulator/beam/beam_emu.c | 55 ++- erts/emulator/beam/bif.c | 188 ++++++++- erts/emulator/beam/bif.tab | 17 + erts/emulator/beam/dist.c | 32 +- erts/emulator/beam/erl_alloc.c | 6 +- erts/emulator/beam/erl_bif_ddll.c | 6 +- erts/emulator/beam/erl_bif_timer.c | 6 +- erts/emulator/beam/erl_bif_trace.c | 34 +- erts/emulator/beam/erl_db_util.c | 12 +- erts/emulator/beam/erl_gc.c | 18 +- erts/emulator/beam/erl_message.c | 182 +++++++-- erts/emulator/beam/erl_message.h | 13 +- erts/emulator/beam/erl_nif.c | 6 +- erts/emulator/beam/erl_process.c | 34 +- erts/emulator/beam/erl_process.h | 12 + erts/emulator/beam/erl_trace.c | 51 ++- erts/emulator/beam/io.c | 30 +- erts/emulator/beam/utils.c | 6 +- erts/emulator/drivers/common/efile_drv.c | 488 +++++++++++++++++------ erts/preloaded/ebin/prim_file.beam | Bin 46736 -> 38764 bytes erts/preloaded/src/prim_file.erl | 649 +++++++++++++------------------ lib/dtrace/c_src/Makefile.in | 10 +- lib/dtrace/examples/efile_drv.d | 3 +- lib/dtrace/src/dtrace.erl | 41 +- lib/hipe/cerl/erl_bif_types.erl | 35 ++ lib/kernel/src/file.erl | 160 +++----- lib/kernel/src/file_io_server.erl | 15 +- lib/kernel/src/file_server.erl | 106 ++--- lib/kernel/test/prim_file_SUITE.erl | 108 ++--- 30 files changed, 1489 insertions(+), 835 deletions(-) diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 7be40976f6..9ce1068b23 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -248,6 +248,7 @@ atom global_heaps_size atom Gt='>' atom grun atom group_leader +atom have_dt_utag atom heap_block_size atom heap_size atom heap_sizes diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 1dbe2cad00..deeb7357d6 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1892,23 +1892,52 @@ void process_main(void) save_calls(c_p, &exp_receive); } if (ERL_MESSAGE_TOKEN(msgp) == NIL) { - SEQ_TRACE_TOKEN(c_p) = NIL; +#ifdef HAVE_DTRACE + if (DT_UTAG(c_p) != NIL) { + if (DT_UTAG_FLAGS(c_p) & DT_UTAG_PERMANENT) { + SEQ_TRACE_TOKEN(c_p) = am_have_dt_utag; + if (DT_UTAG_FLAGS(c_p) & DT_UTAG_SPREADING) + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) stop spreading tag %T with message %T\r\n",c_p->id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp)); + } else { + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) kill tag %T with message %T\r\n",c_p->id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp)); + DT_UTAG(c_p) = NIL; + SEQ_TRACE_TOKEN(c_p) = NIL; + } + } else { +#endif + SEQ_TRACE_TOKEN(c_p) = NIL; +#ifdef HAVE_DTRACE + } + DT_UTAG_FLAGS(c_p) &= ~DT_UTAG_SPREADING; +#endif } else if (ERL_MESSAGE_TOKEN(msgp) != am_undefined) { Eterm msg; SEQ_TRACE_TOKEN(c_p) = ERL_MESSAGE_TOKEN(msgp); - ASSERT(is_tuple(SEQ_TRACE_TOKEN(c_p))); - ASSERT(SEQ_TRACE_TOKEN_ARITY(c_p) == 5); - ASSERT(is_small(SEQ_TRACE_TOKEN_SERIAL(c_p))); - ASSERT(is_small(SEQ_TRACE_TOKEN_LASTCNT(c_p))); - ASSERT(is_small(SEQ_TRACE_TOKEN_FLAGS(c_p))); - ASSERT(is_pid(SEQ_TRACE_TOKEN_SENDER(c_p))); - c_p->seq_trace_lastcnt = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); - if (c_p->seq_trace_clock < unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p))) { - c_p->seq_trace_clock = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); +#ifdef HAVE_DTRACE + if (ERL_MESSAGE_TOKEN(msgp) == am_have_dt_utag) { + if (DT_UTAG(c_p) == NIL) { + DT_UTAG(c_p) = ERL_MESSAGE_DT_UTAG(msgp); + } + DT_UTAG_FLAGS(c_p) |= DT_UTAG_SPREADING; + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) receive tag (%T) with message %T\r\n",c_p->id, DT_UTAG(c_p), ERL_MESSAGE_TERM(msgp)); + } else { +#endif + ASSERT(is_tuple(SEQ_TRACE_TOKEN(c_p))); + ASSERT(SEQ_TRACE_TOKEN_ARITY(c_p) == 5); + ASSERT(is_small(SEQ_TRACE_TOKEN_SERIAL(c_p))); + ASSERT(is_small(SEQ_TRACE_TOKEN_LASTCNT(c_p))); + ASSERT(is_small(SEQ_TRACE_TOKEN_FLAGS(c_p))); + ASSERT(is_pid(SEQ_TRACE_TOKEN_SENDER(c_p))); + c_p->seq_trace_lastcnt = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); + if (c_p->seq_trace_clock < unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p))) { + c_p->seq_trace_clock = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); + } + msg = ERL_MESSAGE_TERM(msgp); + seq_trace_output(SEQ_TRACE_TOKEN(c_p), msg, SEQ_TRACE_RECEIVE, + c_p->id, c_p); +#ifdef HAVE_DTRACE } - msg = ERL_MESSAGE_TERM(msgp); - seq_trace_output(SEQ_TRACE_TOKEN(c_p), msg, SEQ_TRACE_RECEIVE, - c_p->id, c_p); +#endif } if (DTRACE_ENABLED(message_receive)) { Eterm token2 = NIL; diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index ebdca87f4a..6478e54996 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -563,7 +563,11 @@ erts_queue_monitor_message(Process *p, ref_copy = copy_struct(ref, ref_size, &hp, ohp); tup = TUPLE5(hp, am_DOWN, ref_copy, type, item_copy, reason_copy); - erts_queue_message(p, p_locksp, bp, tup, NIL); + erts_queue_message(p, p_locksp, bp, tup, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); } static BIF_RETTYPE @@ -1944,7 +1948,11 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) { if (ERTS_PROC_GET_SAVED_CALLS_BUF(p)) save_calls(p, &exp_send); - if (SEQ_TRACE_TOKEN(p) != NIL) { + if (SEQ_TRACE_TOKEN(p) != NIL +#ifdef HAVE_DTRACE + && SEQ_TRACE_TOKEN(p) != am_have_dt_utag +#endif + ) { seq_trace_update_send(p); seq_trace_output(SEQ_TRACE_TOKEN(p), msg, SEQ_TRACE_SEND, portid, p); @@ -4226,13 +4234,21 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) for (i = 0; i < erts_max_processes; i++) { if (process_tab[i] != (Process*) 0) { Process* p = process_tab[i]; +#ifdef HAVE_DTRACE + p->seq_trace_token = (p->dt_utag != NIL) ? am_have_dt_utag : NIL; +#else p->seq_trace_token = NIL; +#endif p->seq_trace_clock = 0; p->seq_trace_lastcnt = 0; ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p); mp = p->msg.first; while(mp != NULL) { +#ifdef HAVE_DTRACE + ERL_MESSAGE_TOKEN(mp) = (ERL_MESSAGE_DT_UTAG(mp) != NIL) ? am_have_dt_utag : NIL; +#else ERL_MESSAGE_TOKEN(mp) = NIL; +#endif mp = mp->next; } } @@ -4630,3 +4646,171 @@ BIF_RETTYPE get_module_info_2(BIF_ALIST_2) } BIF_RET(ret); } + +BIF_RETTYPE put_utag_1(BIF_ALIST_1) +{ +#ifdef HAVE_DTRACE + Eterm otag; + if (BIF_ARG_1 == am_undefined) { + otag = (DT_UTAG(BIF_P) == NIL) ? am_undefined : DT_UTAG(BIF_P); + DT_UTAG(BIF_P) = NIL; + DT_UTAG_FLAGS(BIF_P) = 0; + if (SEQ_TRACE_TOKEN(BIF_P) == am_have_dt_utag) { + SEQ_TRACE_TOKEN(BIF_P) = NIL; + } + BIF_RET(otag); + } + if (!is_binary(BIF_ARG_1)) { + BIF_ERROR(BIF_P,BADARG); + } + otag = (DT_UTAG(BIF_P) == NIL) ? am_undefined : DT_UTAG(BIF_P); + DT_UTAG(BIF_P) = BIF_ARG_1; + DT_UTAG_FLAGS(BIF_P) |= DT_UTAG_PERMANENT; + if (SEQ_TRACE_TOKEN(BIF_P) == NIL) { + SEQ_TRACE_TOKEN(BIF_P) = am_have_dt_utag; + } + BIF_RET(otag); +#else + BIF_RET(am_undefined); +#endif +} + +BIF_RETTYPE get_utag_0(BIF_ALIST_0) +{ +#ifdef HAVE_DTRACE + BIF_RET((DT_UTAG(BIF_P) == NIL || !(DT_UTAG_FLAGS(BIF_P) & DT_UTAG_PERMANENT)) ? am_undefined : DT_UTAG(BIF_P)); +#else + BIF_RET(am_undefined); +#endif +} +BIF_RETTYPE get_utag_data_0(BIF_ALIST_0) +{ +#ifdef HAVE_DTRACE + BIF_RET((DT_UTAG(BIF_P) == NIL) ? am_undefined : DT_UTAG(BIF_P)); +#else + BIF_RET(am_undefined); +#endif +} +BIF_RETTYPE prepend_vm_utag_data_1(BIF_ALIST_1) +{ +#ifdef HAVE_DTRACE + Eterm b; + Eterm *hp; + hp = HAlloc(BIF_P,2); + if (is_binary((DT_UTAG(BIF_P)))) { + Uint sz = binary_size(DT_UTAG(BIF_P)); + int i; + unsigned char *p,*q; + byte *temp_alloc = NULL; + b = new_binary(BIF_P,NULL,sz+1); + q = binary_bytes(b); + p = erts_get_aligned_binary_bytes(DT_UTAG(BIF_P),&temp_alloc); + for(i=0;i (%T) start spreading tag %T\r\n",BIF_P->id,DT_UTAG(BIF_P)); + } else { + DT_UTAG_FLAGS(BIF_P) &= ~DT_UTAG_SPREADING; + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) stop spreading tag %T\r\n",BIF_P->id,DT_UTAG(BIF_P)); + } + } + BIF_RET(ret); +#else + BIF_RET(am_true); +#endif +} +BIF_RETTYPE restore_utag_1(BIF_ALIST_1) +{ +#ifdef HAVE_DTRACE + Eterm *tpl; + Uint x; + if (is_not_tuple(BIF_ARG_1)) { + BIF_ERROR(BIF_P,BADARG); + } + tpl = tuple_val(BIF_ARG_1); + if(arityval(*tpl) != 2 || is_not_small(tpl[1]) || (is_not_binary(tpl[2]) && tpl[2] != NIL)) { + BIF_ERROR(BIF_P,BADARG); + } + if (tpl[2] == NIL) { + if (DT_UTAG(BIF_P) != NIL) { + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) restore Killing tag!\r\n",BIF_P->id); + } + DT_UTAG(BIF_P) = NIL; + if (SEQ_TRACE_TOKEN(BIF_P) == am_have_dt_utag) { + SEQ_TRACE_TOKEN(BIF_P) = NIL; + } + DT_UTAG_FLAGS(BIF_P) = 0; + } else { + x = unsigned_val(tpl[1]) & (DT_UTAG_SPREADING | DT_UTAG_PERMANENT); + if (!(x & DT_UTAG_SPREADING) && (DT_UTAG_FLAGS(BIF_P) & DT_UTAG_SPREADING)) { + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) restore stop spreading tag %T\r\n",BIF_P->id,tpl[2]); + } else if ((x & DT_UTAG_SPREADING) && !(DT_UTAG_FLAGS(BIF_P) & DT_UTAG_SPREADING)) { + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) restore start spreading tag %T\r\n",BIF_P->id,tpl[2]); + } + DT_UTAG_FLAGS(BIF_P) = x; + DT_UTAG(BIF_P) = tpl[2]; + if (SEQ_TRACE_TOKEN(BIF_P) == NIL) { + SEQ_TRACE_TOKEN(BIF_P) = am_have_dt_utag; + } + } +#else + if (BIF_ARG_1 != am_true) { + BIF_ERROR(BIF_P,BADARG); + } +#endif + BIF_RET(am_true); +} + + diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 007c884a6a..7940544156 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -814,6 +814,23 @@ bif erlang:check_old_code/1 # bif erlang:universaltime_to_posixtime/1 bif erlang:posixtime_to_universaltime/1 + +# +# New in R15B01 +# + +# The dtrace BIF's are always present, but give dummy results if dynamic trace is not enabled in the build +bif erlang:put_utag/1 +bif erlang:get_utag/0 +bif erlang:get_utag_data/0 +bif erlang:spread_utag/1 +bif erlang:restore_utag/1 + +# These are dummies even with enabled dynamic trace unless vm probes are enabled. +# They are also internal, for dtrace tags sent to the VM's own drivers (efile) +bif erlang:prepend_vm_utag_data/1 +bif erlang:append_vm_utag_data/1 + # # Obsolete # diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index ba55a1918a..43fc910054 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -382,7 +382,11 @@ static void doit_node_link_net_exits(ErtsLink *lnk, void *vnecp) Eterm tup; Eterm *hp = erts_alloc_message_heap(3,&bp,&ohp,rp,&rp_locks); tup = TUPLE2(hp, am_nodedown, name); - erts_queue_message(rp, &rp_locks, bp, tup, NIL); + erts_queue_message(rp, &rp_locks, bp, tup, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); } erts_smp_proc_unlock(rp, rp_locks); } @@ -750,7 +754,11 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) DTRACE_CHARBUF(receiver_name, 64); UseTmpHeapNoproc(5); - if (SEQ_TRACE_TOKEN(sender) != NIL) { + if (SEQ_TRACE_TOKEN(sender) != NIL +#ifdef HAVE_DTRACE + && SEQ_TRACE_TOKEN(sender) != am_have_dt_utag +#endif + ) { seq_trace_update_send(sender); token = SEQ_TRACE_TOKEN(sender); seq_trace_output(token, message, SEQ_TRACE_SEND, remote, sender); @@ -799,7 +807,11 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) DTRACE_CHARBUF(receiver_name, 128); UseTmpHeapNoproc(6); - if (SEQ_TRACE_TOKEN(sender) != NIL) { + if (SEQ_TRACE_TOKEN(sender) != NIL +#ifdef HAVE_DTRACE + && SEQ_TRACE_TOKEN(sender) != am_have_dt_utag +#endif + ) { seq_trace_update_send(sender); token = SEQ_TRACE_TOKEN(sender); seq_trace_output(token, message, SEQ_TRACE_SEND, remote_name, sender); @@ -851,7 +863,11 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, DTRACE_CHARBUF(reason_str, 128); UseTmpHeapNoproc(6); - if (token != NIL) { + if (token != NIL +#ifdef HAVE_DTRACE + && token != am_have_dt_utag +#endif + ) { seq_trace_update_send(dsdp->proc); seq_trace_output_exit(token, reason, SEQ_TRACE_SEND, remote, local); ctl = TUPLE5(&ctl_heap[0], @@ -866,7 +882,7 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, erts_snprintf(remote_name, sizeof(remote_name), "{%T,%s}", remote, node_name); erts_snprintf(reason_str, sizeof(reason), "%T", reason); - if (token != NIL) { + if (token != NIL && token != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); @@ -3094,7 +3110,11 @@ send_nodes_mon_msg(Process *rp, } ASSERT(hend == hp); - erts_queue_message(rp, rp_locksp, bp, msg, NIL); + erts_queue_message(rp, rp_locksp, bp, msg, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); } static void diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index df27186680..d575e30092 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -3001,7 +3001,11 @@ reply_alloc_info(void *vair) HRelease(rp, hp_end, hp); } - erts_queue_message(rp, &rp_locks, bp, msg, NIL); + erts_queue_message(rp, &rp_locks, bp, msg, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); if (air->req_sched == sched_id) rp_locks &= ~ERTS_PROC_LOCK_MAIN; diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index 3326fd84df..b58c5ab761 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1762,7 +1762,11 @@ static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, Eterm type, hp += REF_THING_SIZE; mess = TUPLE5(hp,type,r,am_driver,driver_name,tag); } - erts_queue_message(proc, &rp_locks, bp, mess, am_undefined); + erts_queue_message(proc, &rp_locks, bp, mess, am_undefined +#ifdef HAVE_DTRACE + , NIL +#endif + ); erts_smp_proc_unlock(proc, rp_locks); ERTS_SMP_CHK_NO_PROC_LOCKS; } diff --git a/erts/emulator/beam/erl_bif_timer.c b/erts/emulator/beam/erl_bif_timer.c index a922a33da3..fbc2f08c09 100644 --- a/erts/emulator/beam/erl_bif_timer.c +++ b/erts/emulator/beam/erl_bif_timer.c @@ -373,7 +373,11 @@ bif_timer_timeout(ErtsBifTimer* btm) message = TUPLE3(hp, am_timeout, ref, message); } - erts_queue_message(rp, &rp_locks, bp, message, NIL); + erts_queue_message(rp, &rp_locks, bp, message, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); erts_smp_proc_unlock(rp, rp_locks); erts_smp_proc_dec_refc(rp); } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index b0a58c80ea..c518aa6866 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -1744,9 +1744,17 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2, return THE_NON_VALUE; } if (build_result) { +#ifdef HAVE_DTRACE + old_value = (SEQ_TRACE_TOKEN(p) == am_have_dt_utag) ? NIL : SEQ_TRACE_TOKEN(p); +#else old_value = SEQ_TRACE_TOKEN(p); +#endif } +#ifdef HAVE_DTRACE + SEQ_TRACE_TOKEN(p) = (DT_UTAG(p) != NIL) ? am_have_dt_utag : NIL; +#else SEQ_TRACE_TOKEN(p) = NIL; +#endif return old_value; } else { @@ -1759,7 +1767,11 @@ new_seq_trace_token(Process* p) { Eterm* hp; - if (SEQ_TRACE_TOKEN(p) == NIL) { + if (SEQ_TRACE_TOKEN(p) == NIL +#ifdef HAVE_DTRACE + || SEQ_TRACE_TOKEN(p) == am_have_dt_utag +#endif + ) { hp = HAlloc(p, 6); SEQ_TRACE_TOKEN(p) = TUPLE5(hp, make_small(0), /* Flags */ make_small(0), /* Label */ @@ -1779,7 +1791,11 @@ BIF_RETTYPE erl_seq_trace_info(Process *p, Eterm item) BIF_ERROR(p, BADARG); } - if (SEQ_TRACE_TOKEN(p) == NIL) { + if (SEQ_TRACE_TOKEN(p) == NIL +#ifdef HAVE_DTRACE + || SEQ_TRACE_TOKEN(p) == am_have_dt_utag +#endif + ) { if ((item == am_send) || (item == am_receive) || (item == am_print) || (item == am_timestamp)) { hp = HAlloc(p,3); @@ -1836,8 +1852,13 @@ BIF_RETTYPE seq_trace_info_1(BIF_ALIST_1) */ BIF_RETTYPE seq_trace_print_1(BIF_ALIST_1) { - if (SEQ_TRACE_TOKEN(BIF_P) == NIL) + if (SEQ_TRACE_TOKEN(BIF_P) == NIL +#ifdef HAVE_DTRACE + || SEQ_TRACE_TOKEN(BIF_P) == am_have_dt_utag +#endif + ) { BIF_RET(am_false); + } seq_trace_update_send(BIF_P); seq_trace_output(SEQ_TRACE_TOKEN(BIF_P), BIF_ARG_1, SEQ_TRACE_PRINT, NIL, BIF_P); @@ -1854,8 +1875,13 @@ BIF_RETTYPE seq_trace_print_1(BIF_ALIST_1) */ BIF_RETTYPE seq_trace_print_2(BIF_ALIST_2) { - if (SEQ_TRACE_TOKEN(BIF_P) == NIL) + if (SEQ_TRACE_TOKEN(BIF_P) == NIL +#ifdef HAVE_DTRACE + || SEQ_TRACE_TOKEN(BIF_P) == am_have_dt_utag +#endif + ) { BIF_RET(am_false); + } if (!(is_atom(BIF_ARG_1) || is_small(BIF_ARG_1))) { BIF_ERROR(BIF_P, BADARG); } diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 4821a7d9fb..eb05ceaaf1 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -2203,7 +2203,11 @@ restart: *esp++ = am_true; break; case matchIsSeqTrace: - if (SEQ_TRACE_TOKEN(c_p) != NIL) + if (SEQ_TRACE_TOKEN(c_p) != NIL +#ifdef HAVE_DTRACE + && SEQ_TRACE_TOKEN(c_p) != am_have_dt_utag +#endif + ) *esp++ = am_true; else *esp++ = am_false; @@ -2227,7 +2231,11 @@ restart: --esp; break; case matchGetSeqToken: - if (SEQ_TRACE_TOKEN(c_p) == NIL) + if (SEQ_TRACE_TOKEN(c_p) == NIL +#ifdef HAVE_DTRACE + || SEQ_TRACE_TOKEN(c_p) == am_have_dt_utag +#endif + ) *esp++ = NIL; else { Eterm sender = SEQ_TRACE_TOKEN_SENDER(c_p); diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 679a3645ba..6dfccfe52f 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -1935,7 +1935,13 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset) roots[n].sz = 1; n++; } - +#ifdef HAVE_DTRACE + if (is_not_immed(p->dt_utag)) { + roots[n].v = &p->dt_utag; + roots[n].sz = 1; + n++; + } +#endif ASSERT(is_nil(p->tracer_proc) || is_internal_pid(p->tracer_proc) || is_internal_port(p->tracer_proc)); @@ -2472,6 +2478,13 @@ offset_mqueue(Process *p, Sint offs, char* area, Uint area_size) if (is_boxed(mesg) && in_area(ptr_val(mesg), area, area_size)) { ERL_MESSAGE_TOKEN(mp) = offset_ptr(mesg, offs); } +#ifdef HAVE_DTRACE + mesg = ERL_MESSAGE_DT_UTAG(mp); + if (is_boxed(mesg) && in_area(ptr_val(mesg), area, area_size)) { + ERL_MESSAGE_DT_UTAG(mp) = offset_ptr(mesg, offs); + } +#endif + ASSERT((is_nil(ERL_MESSAGE_TOKEN(mp)) || is_tuple(ERL_MESSAGE_TOKEN(mp)) || is_atom(ERL_MESSAGE_TOKEN(mp)))); @@ -2491,6 +2504,9 @@ offset_one_rootset(Process *p, Sint offs, char* area, Uint area_size, offset_heap_ptr(&p->fvalue, 1, offs, area, area_size); offset_heap_ptr(&p->ftrace, 1, offs, area, area_size); offset_heap_ptr(&p->seq_trace_token, 1, offs, area, area_size); +#ifdef HAVE_DTRACE + offset_heap_ptr(&p->dt_utag, 1, offs, area, area_size); +#endif offset_heap_ptr(&p->group_leader, 1, offs, area, area_size); offset_mqueue(p, offs, area, area_size); offset_heap_ptr(p->stop, (STACK_START(p) - p->stop), offs, area, area_size); diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 786d6ac52c..dc59b9c2c4 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -393,13 +393,26 @@ erts_queue_dist_message(Process *rcvr, receiver_name, size_object(msg), rcvr->msg.len, tok_label, tok_lastcnt, tok_serial); } - erts_queue_message(rcvr, rcvr_locks, mbuf, msg, token); + erts_queue_message(rcvr, rcvr_locks, mbuf, msg, token +#ifdef HAVE_DTRACE + , NIL +#endif + ); } else { /* Enqueue message on external format */ ERL_MESSAGE_TERM(mp) = THE_NON_VALUE; - ERL_MESSAGE_TOKEN(mp) = token; +#ifdef HAVE_DTRACE + ERL_MESSAGE_DT_UTAG(mp) = NIL; + if (token == am_have_dt_utag) { + ERL_MESSAGE_TOKEN(mp) = NIL; + } else { +#endif + ERL_MESSAGE_TOKEN(mp) = token; +#ifdef HAVE_DTRACE + } +#endif mp->next = NULL; if (DTRACE_ENABLED(message_queued)) { @@ -431,7 +444,11 @@ erts_queue_message(Process* receiver, ErtsProcLocks *receiver_locks, ErlHeapFragment* bp, Eterm message, - Eterm seq_trace_token) + Eterm seq_trace_token +#ifdef HAVE_DTRACE + , Eterm dt_utag +#endif +) { ErlMessage* mp; #ifdef ERTS_SMP @@ -472,6 +489,9 @@ erts_queue_message(Process* receiver, ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = seq_trace_token; +#ifdef HAVE_DTRACE + ERL_MESSAGE_DT_UTAG(mp) = dt_utag; +#endif mp->next = NULL; mp->data.heap_frag = bp; @@ -547,6 +567,9 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) Sint offs; Uint sz; ErlHeapFragment *bp; +#ifdef HAVE_DTRACE + Eterm utag; +#endif #ifdef HARD_DEBUG ProcBin *dbg_mso_start = off_heap->mso; @@ -556,32 +579,56 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) ErlHeapFragment *dbg_bp; Uint *dbg_hp, *dbg_thp_start; Uint dbg_term_sz, dbg_token_sz; +#ifdef HAVE_DTRACE + Eterm dbg_utag; + Uint dbg_utag_sz; +#endif #endif bp = msg->data.heap_frag; term = ERL_MESSAGE_TERM(msg); token = ERL_MESSAGE_TOKEN(msg); +#ifdef HAVE_DTRACE + utag = ERL_MESSAGE_DT_UTAG(msg); +#endif if (!bp) { +#ifdef HAVE_DTRACE + ASSERT(is_immed(term) && is_immed(token) && is_immed(utag)); +#else ASSERT(is_immed(term) && is_immed(token)); +#endif return; } #ifdef HARD_DEBUG dbg_term_sz = size_object(term); dbg_token_sz = size_object(token); + dbg_bp = new_message_buffer(dbg_term_sz + dbg_token_sz); +#ifdef HAVE_DTRACE + dbg_utag_sz = size_object(utag); + dbg_bp = new_message_buffer(dbg_term_sz + dbg_token_sz + dbg_utag_sz ); +#endif /*ASSERT(dbg_term_sz + dbg_token_sz == erts_msg_used_frag_sz(msg)); Copied size may be smaller due to removed SubBins's or garbage. Copied size may be larger due to duplicated shared terms. */ - dbg_bp = new_message_buffer(dbg_term_sz + dbg_token_sz); dbg_hp = dbg_bp->mem; dbg_term = copy_struct(term, dbg_term_sz, &dbg_hp, &dbg_bp->off_heap); dbg_token = copy_struct(token, dbg_token_sz, &dbg_hp, &dbg_bp->off_heap); - dbg_thp_start = *hpp; +#ifdef HAVE_DTRACE + dbg_utag = copy_struct(utag, dbg_utag_sz, &dbg_hp, &dbg_bp->off_heap); +#endif + dbg_thp_start = *hpp; #endif if (bp->next != NULL) { - move_multi_frags(hpp, off_heap, bp, msg->m, 2); + move_multi_frags(hpp, off_heap, bp, msg->m, +#ifdef HAVE_DTRACE + 3 +#else + 2 +#endif + ); goto copy_done; } @@ -683,6 +730,16 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) ASSERT(hp > ptr_val(ERL_MESSAGE_TERM(msg))); #endif } +#ifdef HAVE_DTRACE + if (is_not_immed(utag)) { + ASSERT(in_heapfrag(ptr_val(utag), bp)); + ERL_MESSAGE_DT_UTAG(msg) = offset_ptr(utag, offs); +#ifdef HARD_DEBUG + ASSERT(dbg_thp_start <= ptr_val(ERL_MESSAGE_DT_UTAG(msg))); + ASSERT(hp > ptr_val(ERL_MESSAGE_DT_UTAG(msg))); +#endif + } +#endif copy_done: @@ -749,6 +806,9 @@ copy_done: #ifdef HARD_DEBUG ASSERT(eq(ERL_MESSAGE_TERM(msg), dbg_term)); ASSERT(eq(ERL_MESSAGE_TOKEN(msg), dbg_token)); +#ifdef HAVE_DTRACE + ASSERT(eq(ERL_MESSAGE_DT_UTAG(msg), dbg_utag)); +#endif free_message_buffer(dbg_bp); #endif @@ -841,42 +901,85 @@ erts_send_message(Process* sender, } if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) { Eterm* hp; + Eterm stoken = SEQ_TRACE_TOKEN(sender); + Uint seq_trace_size = 0; +#ifdef HAVE_DTRACE + Uint dt_utag_size = 0; + Eterm utag = NIL; +#endif - BM_SWAP_TIMER(send,size); + BM_SWAP_TIMER(send,size); msize = size_object(message); - BM_SWAP_TIMER(size,send); + BM_SWAP_TIMER(size,send); + +#ifdef HAVE_DTRACE + if (stoken != am_have_dt_utag) { +#endif - seq_trace_update_send(sender); - seq_trace_output(SEQ_TRACE_TOKEN(sender), message, SEQ_TRACE_SEND, - receiver->id, sender); - bp = new_message_buffer(msize + 6 /* TUPLE5 */); + seq_trace_update_send(sender); + seq_trace_output(stoken, message, SEQ_TRACE_SEND, + receiver->id, sender); + seq_trace_size = 6; /* TUPLE5 */ +#ifdef HAVE_DTRACE + } + if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) { + dt_utag_size = size_object(DT_UTAG(sender)); + } else if (stoken == am_have_dt_utag ) { + stoken = NIL; + } +#endif + + bp = new_message_buffer(msize + seq_trace_size +#ifdef HAVE_DTRACE + + dt_utag_size +#endif + ); hp = bp->mem; BM_SWAP_TIMER(send,copy); - token = copy_struct(SEQ_TRACE_TOKEN(sender), - 6 /* TUPLE5 */, + token = copy_struct(stoken, + seq_trace_size, &hp, &bp->off_heap); message = copy_struct(message, msize, &hp, &bp->off_heap); +#ifdef HAVE_DTRACE + if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) { + utag = copy_struct(DT_UTAG(sender), dt_utag_size, &hp, &bp->off_heap); + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) Spreading tag (%T) with message %T!\r\n",sender->id, utag, message); + } +#if 0 + DT_UTAG_FLAGS(sender) &= ~DT_UTAG_SPREADING; + if (!(DT_UTAG_FLAGS(sender) & DT_UTAG_PERMANENT)) { + erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) Killing tag!\r\n",sender->id); + DT_UTAG(sender) = NIL; + if (SEQ_TRACE_TOKEN(sender) == am_have_dt_utag) { + SEQ_TRACE_TOKEN(sender) = NIL; + } + } +#endif +#endif BM_MESSAGE_COPIED(msize); BM_SWAP_TIMER(copy,send); if (DTRACE_ENABLED(message_send)) { - Eterm token2 = NIL; - - token2 = SEQ_TRACE_TOKEN(sender); - tok_label = signed_val(SEQ_TRACE_T_LABEL(token2)); - tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token2)); - tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token2)); - DTRACE6(message_send, sender_name, receiver_name, - msize, tok_label, tok_lastcnt, tok_serial); + if (stoken != NIL) { + tok_label = signed_val(SEQ_TRACE_T_LABEL(stoken)); + tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(stoken)); + tok_serial = signed_val(SEQ_TRACE_T_SERIAL(stoken)); + } + DTRACE6(message_send, sender_name, receiver_name, + msize, tok_label, tok_lastcnt, tok_serial); } erts_queue_message(receiver, receiver_locks, bp, message, - token); + token +#ifdef HAVE_DTRACE + , utag +#endif + ); BM_SWAP_TIMER(send,system); #ifdef HYBRID } else { @@ -909,6 +1012,9 @@ erts_send_message(Process* sender, size_object(message)msize, tok_label, tok_lastcnt, tok_serial); ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; +#ifdef HAVE_DTRACE + ERL_MESSAGE_DT_UTAG(mp) = NIL; +#endif mp->next = NULL; LINK_MESSAGE(receiver, mp); ACTIVATE(receiver); @@ -951,6 +1057,9 @@ erts_send_message(Process* sender, mp->data.attached = NULL; ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; +#ifdef HAVE_DTRACE + ERL_MESSAGE_DT_UTAG(mp) = NIL; +#endif mp->next = NULL; /* * We move 'in queue' to 'private queue' and place @@ -984,7 +1093,11 @@ erts_send_message(Process* sender, BM_SWAP_TIMER(copy,send); DTRACE6(message_send, sender_name, receiver_name, msize, tok_label, tok_lastcnt, tok_serial); - erts_queue_message(receiver, receiver_locks, bp, message, token); + erts_queue_message(receiver, receiver_locks, bp, message, token +#ifdef HAVE_DTRACE + , NIL +#endif + ); BM_SWAP_TIMER(send,system); #else ErlMessage* mp = message_alloc(); @@ -1008,6 +1121,9 @@ erts_send_message(Process* sender, (uint32_t)msize, tok_label, tok_lastcnt, tok_serial); ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; +#ifdef HAVE_DTRACE + ERL_MESSAGE_DT_UTAG(mp) = NIL; +#endif mp->next = NULL; mp->data.attached = NULL; LINK_MESSAGE(receiver, mp); @@ -1046,7 +1162,11 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp, Eterm temptoken; ErlHeapFragment* bp = NULL; - if (token != NIL) { + if (token != NIL +#ifdef HAVE_DTRACE + && token != am_have_dt_utag +#endif + ) { ASSERT(is_tuple(token)); sz_reason = size_object(reason); @@ -1061,7 +1181,11 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp, /* the trace token must in this case be updated by the caller */ seq_trace_output(token, save, SEQ_TRACE_SEND, to->id, NULL); temptoken = copy_struct(token, sz_token, &hp, &bp->off_heap); - erts_queue_message(to, to_locksp, bp, save, temptoken); + erts_queue_message(to, to_locksp, bp, save, temptoken +#ifdef HAVE_DTRACE + , NIL +#endif + ); } else { ErlOffHeap *ohp; sz_reason = size_object(reason); @@ -1078,7 +1202,11 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp, ? from : copy_struct(from, sz_from, &hp, ohp)); save = TUPLE3(hp, am_EXIT, from_copy, mess); - erts_queue_message(to, to_locksp, bp, save, NIL); + erts_queue_message(to, to_locksp, bp, save, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); } } diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index 5aca0db6fe..98321dd2c6 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -70,11 +70,18 @@ typedef struct erl_mesg { ErlHeapFragment *heap_frag; void *attached; } data; +#ifdef HAVE_DTRACE + Eterm m[3]; /* m[0] = message, m[1] = seq trace token, m[3] = dynamic trace user tag */ +#else Eterm m[2]; /* m[0] = message, m[1] = seq trace token */ +#endif } ErlMessage; #define ERL_MESSAGE_TERM(mp) ((mp)->m[0]) #define ERL_MESSAGE_TOKEN(mp) ((mp)->m[1]) +#ifdef HAVE_DTRACE +#define ERL_MESSAGE_DT_UTAG(mp) ((mp)->m[2]) +#endif /* Size of default message buffer (erl_message.c) */ #define ERL_MESSAGE_BUF_SZ 500 @@ -221,7 +228,11 @@ ErlHeapFragment* erts_resize_message_buffer(ErlHeapFragment *, Uint, Eterm *, Uint); void free_message_buffer(ErlHeapFragment *); void erts_queue_dist_message(Process*, ErtsProcLocks*, ErtsDistExternal *, Eterm); -void erts_queue_message(Process*, ErtsProcLocks*, ErlHeapFragment*, Eterm, Eterm); +void erts_queue_message(Process*, ErtsProcLocks*, ErlHeapFragment*, Eterm, Eterm +#ifdef HAVE_DTRACE + , Eterm dt_utag +#endif +); void erts_deliver_exit_message(Eterm, Process*, ErtsProcLocks *, Eterm, Eterm); void erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm, unsigned); void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp); diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index dc4049327d..ebc771b016 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -351,7 +351,11 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, if (flush_me) { flush_env(env); /* Needed for ERTS_HOLE_CHECK */ } - erts_queue_message(rp, &rp_locks, frags, msg, am_undefined); + erts_queue_message(rp, &rp_locks, frags, msg, am_undefined +#ifdef HAVE_DTRACE + , NIL +#endif + ); if (rp_locks) { ERTS_SMP_LC_ASSERT(rp_locks == (rp_had_locks | (ERTS_PROC_LOCK_MSGQ | ERTS_PROC_LOCK_STATUS))); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 1173624f51..6771e00c7e 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -679,7 +679,11 @@ reply_sched_wall_time(void *vswtrp) hpp = &hp; } - erts_queue_message(rp, &rp_locks, bp, msg, NIL); + erts_queue_message(rp, &rp_locks, bp, msg, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); if (swtrp->req_sched == esdp->no) rp_locks &= ~ERTS_PROC_LOCK_MAIN; @@ -7260,6 +7264,10 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->seq_trace_lastcnt = 0; p->seq_trace_clock = 0; SEQ_TRACE_TOKEN(p) = NIL; +#ifdef HAVE_DTRACE + DT_UTAG(p) = NIL; + DT_UTAG_FLAGS(p) = 0; +#endif p->parent = parent->id == ERTS_INVALID_PID ? NIL : parent->id; #ifdef HYBRID @@ -7851,7 +7859,11 @@ static ERTS_INLINE void send_exit_message(Process *to, ErtsProcLocks *to_locksp, Eterm exit_term, Uint term_size, Eterm token) { - if (token == NIL) { + if (token == NIL +#ifdef HAVE_DTRACE + || token == am_have_dt_utag +#endif + ) { Eterm* hp; Eterm mess; ErlHeapFragment* bp; @@ -7859,7 +7871,11 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp, hp = erts_alloc_message_heap(term_size, &bp, &ohp, to, to_locksp); mess = copy_struct(exit_term, term_size, &hp, ohp); - erts_queue_message(to, to_locksp, bp, mess, NIL); + erts_queue_message(to, to_locksp, bp, mess, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); } else { ErlHeapFragment* bp; Eterm* hp; @@ -7875,7 +7891,11 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp, /* the trace token must in this case be updated by the caller */ seq_trace_output(token, mess, SEQ_TRACE_SEND, to->id, NULL); temp_token = copy_struct(token, sz_token, &hp, &bp->off_heap); - erts_queue_message(to, to_locksp, bp, mess, temp_token); + erts_queue_message(to, to_locksp, bp, mess, temp_token +#ifdef HAVE_DTRACE + , NIL +#endif + ); } } @@ -7981,7 +8001,11 @@ send_exit_signal(Process *c_p, /* current process if and only if (ERTS_PROC_IS_TRAPPING_EXITS(rp) && (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) { - if (is_not_nil(token) && token_update) + if (is_not_nil(token) +#ifdef HAVE_DTRACE + && token != am_have_dt_utag +#endif + && token_update) seq_trace_update_send(token_update); if (is_value(exit_tuple)) send_exit_message(rp, rp_locks, exit_tuple, exit_tuple_sz, token); diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index d671638ce8..35b31b1009 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -683,6 +683,10 @@ struct process { Uint seq_trace_lastcnt; Eterm seq_trace_token; /* Sequential trace token (tuple size 5 see below) */ +#ifdef HAVE_DTRACE + Eterm dt_utag; /* Place to store the dynamc trace user tag */ + Uint dt_utag_flags; /* flag field for the dt_utag */ +#endif BeamInstr initial[3]; /* Initial module(0), function(1), arity(2), often used instead of pointer to funcinfo instruction, hence the BeamInstr datatype */ BeamInstr* current; /* Current Erlang function, part of the funcinfo: @@ -998,6 +1002,14 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; #define SEQ_TRACE_PRINT (1 << 2) #define SEQ_TRACE_TIMESTAMP (1 << 3) +#ifdef HAVE_DTRACE +#define DT_UTAG_PERMANENT (1 << 0) +#define DT_UTAG_SPREADING (1 << 1) +#define DT_UTAG(P) ((P)->dt_utag) +#define DT_UTAG_FLAGS(P) ((P)->dt_utag_flags) +#endif + + #ifdef ERTS_SMP /* Status flags ... */ #define ERTS_PROC_SFLG_PENDADD2SCHEDQ (((Uint32) 1) << 0) /* Pending diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index b1d1e1d9b0..a4aed0122b 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -125,8 +125,13 @@ do { \ enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, (FPID), (TPID), (MSG), (BP)); \ } while(0) #else +#ifdef HAVE_DTRACE #define ERTS_ENQ_TRACE_MSG(FPID, TPROC, MSG, BP) \ - erts_queue_message((TPROC), NULL, (BP), (MSG), NIL) + erts_queue_message((TPROC), NULL, (BP), (MSG), NIL, NIL) +#else +#define ERTS_ENQ_TRACE_MSG(FPID, TPROC, MSG, BP) \ + erts_queue_message((TPROC), NULL, (BP), (MSG), NIL) +#endif #endif /* @@ -583,7 +588,11 @@ profile_send(Eterm from, Eterm message) { hp = erts_alloc_message_heap(sz, &bp, &off_heap, profile_p, 0); msg = copy_struct(message, sz, &hp, &bp->off_heap); - erts_queue_message(profile_p, NULL, bp, msg, NIL); + erts_queue_message(profile_p, NULL, bp, msg, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); } } @@ -994,9 +1003,13 @@ seq_trace_update_send(Process *p) { Eterm seq_tracer = erts_get_system_seq_tracer(); ASSERT((is_tuple(SEQ_TRACE_TOKEN(p)) || is_nil(SEQ_TRACE_TOKEN(p)))); - if ( (p->id == seq_tracer) || (SEQ_TRACE_TOKEN(p) == NIL)) + if ( (p->id == seq_tracer) || (SEQ_TRACE_TOKEN(p) == NIL) +#ifdef HAVE_DTRACE + || (SEQ_TRACE_TOKEN(p) == am_have_dt_utag) +#endif + ) { return 0; - + } SEQ_TRACE_TOKEN_SENDER(p) = p->id; /* Internal pid */ SEQ_TRACE_TOKEN_SERIAL(p) = make_small(++(p -> seq_trace_clock)); @@ -1178,7 +1191,11 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SEQTRACE, NIL, NIL, mess, bp); erts_smp_mtx_unlock(&smq_mtx); #else - erts_queue_message(tracer, NULL, bp, mess, NIL); /* trace_token must be NIL here */ + erts_queue_message(tracer, NULL, bp, mess, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); /* trace_token must be NIL here */ #endif } } @@ -2469,7 +2486,11 @@ monitor_long_gc(Process *p, Uint time) { #ifdef ERTS_SMP enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp); #else - erts_queue_message(monitor_p, NULL, bp, msg, NIL); + erts_queue_message(monitor_p, NULL, bp, msg, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); #endif } @@ -2541,7 +2562,11 @@ monitor_large_heap(Process *p) { #ifdef ERTS_SMP enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp); #else - erts_queue_message(monitor_p, NULL, bp, msg, NIL); + erts_queue_message(monitor_p, NULL, bp, msg, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); #endif } @@ -2571,7 +2596,11 @@ monitor_generic(Process *p, Eterm type, Eterm spec) { #ifdef ERTS_SMP enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp); #else - erts_queue_message(monitor_p, NULL, bp, msg, NIL); + erts_queue_message(monitor_p, NULL, bp, msg, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); #endif } @@ -3357,7 +3386,11 @@ sys_msg_dispatcher_func(void *unused) } else { queue_proc_msg: - erts_queue_message(proc,&proc_locks,smqp->bp,smqp->msg,NIL); + erts_queue_message(proc,&proc_locks,smqp->bp,smqp->msg,NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); #ifdef DEBUG_PRINTOUTS erts_fprintf(stderr, "delivered\n"); #endif diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 81f79b8f85..75ea53c2b7 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -1564,7 +1564,11 @@ deliver_result(Eterm sender, Eterm pid, Eterm res) hp = erts_alloc_message_heap(sz_res + 3, &bp, &ohp, rp, &rp_locks); res = copy_struct(res, sz_res, &hp, ohp); tuple = TUPLE2(hp, sender, res); - erts_queue_message(rp, &rp_locks, bp, tuple, NIL); + erts_queue_message(rp, &rp_locks, bp, tuple, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); erts_smp_proc_unlock(rp, rp_locks); erts_smp_proc_dec_refc(rp); } @@ -1653,7 +1657,11 @@ static void deliver_read_message(Port* prt, Eterm to, tuple = TUPLE2(hp, prt->id, tuple); hp += 3; - erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined); + erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined +#ifdef HAVE_DTRACE + , NIL +#endif + ); erts_smp_proc_unlock(rp, rp_locks); erts_smp_proc_dec_refc(rp); } @@ -1806,7 +1814,11 @@ deliver_vec_message(Port* prt, /* Port */ tuple = TUPLE2(hp, prt->id, tuple); hp += 3; - erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined); + erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined +#ifdef HAVE_DTRACE + , NIL +#endif + ); erts_smp_proc_unlock(rp, rp_locks); erts_smp_proc_dec_refc(rp); } @@ -2772,7 +2784,11 @@ void driver_report_exit(int ix, int status) hp += 3; tuple = TUPLE2(hp, prt->id, tuple); - erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined); + erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined +#ifdef HAVE_DTRACE + , NIL +#endif + ); erts_smp_proc_unlock(rp, rp_locks); erts_smp_proc_dec_refc(rp); @@ -3322,7 +3338,11 @@ driver_deliver_term(ErlDrvPort port, HRelease(rp, hp_end, hp); } /* send message */ - erts_queue_message(rp, &rp_locks, bp, mess, am_undefined); + erts_queue_message(rp, &rp_locks, bp, mess, am_undefined +#ifdef HAVE_DTRACE + , NIL +#endif + ); } else { if (b2t.ix > b2t.used) diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 49b6618f73..2efcd19162 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -1697,7 +1697,11 @@ static int do_send_to_logger(Eterm tag, Eterm gleader, char *buf, int len) erts_queue_error_logger_message(from, tuple3, bp); } #else - erts_queue_message(p, NULL /* only used for smp build */, bp, tuple3, NIL); + erts_queue_message(p, NULL /* only used for smp build */, bp, tuple3, NIL +#ifdef HAVE_DTRACE + , NIL +#endif + ); #endif return 0; } diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 293f024e45..62b582f76a 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -100,7 +100,7 @@ #endif #include -// Need (NON)BLOCKING macros for sendfile +/* Need (NON)BLOCKING macros for sendfile */ #ifndef WANT_NONBLOCKING #define WANT_NONBLOCKING #endif @@ -112,7 +112,7 @@ #include "erl_threads.h" #include "zlib.h" #include "gzio.h" -#include "dtrace-wrapper.h" +#include "dtrace-wrapper.h" #include #include @@ -149,10 +149,6 @@ typedef struct { dt_private *get_dt_private(int); #else /* HAVE_DTRACE */ -typedef struct { - char dummy; /* Unused except to quiet some compilers */ -} dt_private; - #define DTRACE_INVOKE_SETUP(op) do {} while (0) #define DTRACE_INVOKE_SETUP_BY_NAME(op) do {} while (0) #define DTRACE_INVOKE_RETURN(op) do {} while (0) @@ -212,6 +208,9 @@ typedef struct { #ifdef FILENAMES_16BIT +#ifdef HAVE_DTRACE +#error 16bit characters in filenames and dtrace in combination is not supported. +#endif # define FILENAME_BYTELEN(Str) filename_len_16bit(Str) # define FILENAME_COPY(To,From) filename_cpy_16bit((To),(From)) # define FILENAME_CHARSIZE 2 @@ -432,8 +431,6 @@ struct t_data int sched_i1; Uint64 sched_i2; char sched_utag[DTRACE_EFILE_BUFSIZ+1]; -#else - char sched_utag[1]; #endif int result_ok; Efile_error errInfo; @@ -2027,8 +2024,11 @@ static void cq_execute(file_descriptor *desc) { } static struct t_data *async_write(file_descriptor *desc, int *errp, - int reply, Uint32 reply_size, - Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3) { + int reply, Uint32 reply_size +#ifdef HAVE_DTRACE + ,Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3 +#endif +) { struct t_data *d; if (! (d = EF_ALLOC(sizeof(struct t_data) - 1))) { if (errp) *errp = ENOMEM; @@ -2041,11 +2041,13 @@ static struct t_data *async_write(file_descriptor *desc, int *errp, d->c.writev.port = desc->port; d->c.writev.q_mtx = desc->q_mtx; d->c.writev.size = desc->write_buffered; +#ifdef HAVE_DTRACE if (dt_i1 != NULL) { *dt_i1 = d->fd; *dt_i2 = d->flags; *dt_i3 = d->c.writev.size; } +#endif d->reply = reply; d->c.writev.free_size = 0; d->c.writev.reply_size = reply_size; @@ -2057,16 +2059,24 @@ static struct t_data *async_write(file_descriptor *desc, int *errp, return d; } -static int flush_write(file_descriptor *desc, int *errp, - dt_private *dt_priv, char *dt_utag) { +static int flush_write(file_descriptor *desc, int *errp +#ifdef HAVE_DTRACE + , dt_private *dt_priv, char *dt_utag +#endif +) { int result = 0; +#ifdef HAVE_DTRACE Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; +#endif struct t_data *d = NULL; MUTEX_LOCK(desc->q_mtx); if (desc->write_buffered > 0) { - if ((d = async_write(desc, errp, 0, 0, - &dt_i1, &dt_i2, &dt_i3)) == NULL) { + if ((d = async_write(desc, errp, 0, 0 +#ifdef HAVE_DTRACE + ,&dt_i1, &dt_i2, &dt_i3 +#endif + )) == NULL) { result = -1; } } @@ -2101,10 +2111,17 @@ static int check_write_error(file_descriptor *desc, int *errp) { return 0; } -static int flush_write_check_error(file_descriptor *desc, int *errp, - dt_private *dt_priv, char *dt_utag) { +static int flush_write_check_error(file_descriptor *desc, int *errp +#ifdef HAVE_DTRACE + , dt_private *dt_priv, char *dt_utag +#endif + ) { int r; - if ( (r = flush_write(desc, errp, dt_priv, dt_utag)) != 0) { + if ( (r = flush_write(desc, errp +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + )) != 0) { check_write_error(desc, NULL); return r; } else { @@ -2113,8 +2130,11 @@ static int flush_write_check_error(file_descriptor *desc, int *errp, } static struct t_data *async_lseek(file_descriptor *desc, int *errp, int reply, - Sint64 offset, int origin, - Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3) { + Sint64 offset, int origin +#ifdef HAVE_DTRACE + , Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3 +#endif + ) { struct t_data *d; if (! (d = EF_ALLOC(sizeof(struct t_data)))) { *errp = ENOMEM; @@ -2126,11 +2146,13 @@ static struct t_data *async_lseek(file_descriptor *desc, int *errp, int reply, d->reply = reply; d->c.lseek.offset = offset; d->c.lseek.origin = origin; +#ifdef HAVE_DTRACE if (dt_i1 != NULL) { *dt_i1 = d->fd; *dt_i2 = d->c.lseek.offset; *dt_i3 = d->c.lseek.origin; } +#endif d->invoke = invoke_lseek; d->free = free_data; d->level = 1; @@ -2147,18 +2169,26 @@ static void flush_read(file_descriptor *desc) { } } -static int lseek_flush_read(file_descriptor *desc, int *errp, - dt_private *dt_priv, char *dt_utag) { +static int lseek_flush_read(file_descriptor *desc, int *errp +#ifdef HAVE_DTRACE + ,dt_private *dt_priv, char *dt_utag +#endif + ) { int r = 0; size_t read_size = desc->read_size; +#ifdef HAVE_DTRACE Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; +#endif struct t_data *d; flush_read(desc); if (read_size != 0) { if ((d = async_lseek(desc, errp, 0, - -((ssize_t)read_size), EFILE_SEEK_CUR, - &dt_i1, &dt_i2, &dt_i3)) == NULL) { + -((ssize_t)read_size), EFILE_SEEK_CUR +#ifdef HAVE_DTRACE + , &dt_i1, &dt_i2, &dt_i3 +#endif + )) == NULL) { r = -1; } else { #ifdef HAVE_DTRACE @@ -2490,13 +2520,13 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) char* name; /* Points to the filename in buf. */ int command; struct t_data *d = NULL; - ERTS_DECLARE_DUMMY(char *dt_utag) = NULL; - char *dt_s1 = NULL, *dt_s2 = NULL; - ERTS_DECLARE_DUMMY(Sint64 dt_i1) = 0; - ERTS_DECLARE_DUMMY(Sint64 dt_i2) = 0; - ERTS_DECLARE_DUMMY(Sint64 dt_i3) = 0; - ERTS_DECLARE_DUMMY(Sint64 dt_i4) = 0; #ifdef HAVE_DTRACE + char *dt_utag = NULL; + char *dt_s1 = NULL, *dt_s2 = NULL; + Sint64 dt_i1 = 0; + Sint64 dt_i2 = 0; + Sint64 dt_i3 = 0; + Sint64 dt_i4 = 0; dt_private *dt_priv = get_dt_private(0); #endif /* HAVE_DTRACE */ @@ -2513,8 +2543,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); +#ifdef HAVE_DTRACE dt_s1 = d->b; - dt_utag = name + strlen(d->b) + 1; + dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; +#endif d->command = command; d->invoke = invoke_mkdir; d->free = free_data; @@ -2526,8 +2558,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); +#ifdef HAVE_DTRACE dt_s1 = d->b; - dt_utag = name + strlen(d->b) + 1; + dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; +#endif d->command = command; d->invoke = invoke_rmdir; d->free = free_data; @@ -2539,8 +2573,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); +#ifdef HAVE_DTRACE dt_s1 = d->b; - dt_utag = name + strlen(d->b) + 1; + dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; +#endif d->command = command; d->invoke = invoke_delete_file; d->free = free_data; @@ -2557,10 +2593,12 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); - dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); +#ifdef HAVE_DTRACE + dt_s1 = d->b; dt_s2 = d->b + namelen; - dt_utag = buf + namelen + strlen(dt_s2) + 1; + dt_utag = buf + namelen + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; +#endif d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2574,8 +2612,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); +#ifdef HAVE_DTRACE dt_s1 = d->b; - dt_utag = name + strlen(d->b) + 1; + dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; +#endif d->command = command; d->invoke = invoke_chdir; d->free = free_data; @@ -2587,7 +2627,9 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); d->drive = *(uchar*)buf; +#ifdef HAVE_DTRACE dt_utag = buf + 1; +#endif d->command = command; d->invoke = invoke_pwd; d->free = free_data; @@ -2603,8 +2645,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); +#ifdef HAVE_DTRACE dt_s1 = d->b; - dt_utag = name + strlen(d->b) + 1; + dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; +#endif d->dir_handle = NULL; d->command = command; d->invoke = invoke_readdir; @@ -2629,9 +2673,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) dir_handle = NULL; resbuf[0] = FILE_RESP_LFNAME; +#ifdef HAVE_DTRACE dt_s1 = name; - dt_utag = name + strlen(dt_s1) + 1; - + dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; +#endif /* Fill the buffer with multiple directory listings before sending it to the * receiving process. READDIR_CHUNKS is minimum number of files sent to the * receiver. @@ -2680,11 +2725,13 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); d->flags = get_int32((uchar*)buf); - dt_i1 = d->flags; name = buf+4; FILENAME_COPY(d->b, name); +#ifdef HAVE_DTRACE + dt_i1 = d->flags; dt_s1 = d->b; - dt_utag = name + strlen(d->b) + 1; + dt_utag = name + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; +#endif d->command = command; d->invoke = invoke_open; d->free = free_data; @@ -2696,9 +2743,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); - dt_utag = name; d->fd = fd; +#ifdef HAVE_DTRACE + dt_utag = name; dt_i1 = fd; +#endif d->command = command; d->invoke = invoke_fdatasync; d->free = free_data; @@ -2710,9 +2759,11 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); - dt_utag = name; d->fd = fd; +#ifdef HAVE_DTRACE + dt_utag = name; dt_i1 = fd; +#endif d->command = command; d->invoke = invoke_fsync; d->free = free_data; @@ -2728,13 +2779,15 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); - dt_utag = name + strlen(d->b) + 1; d->fd = fd; +#ifdef HAVE_DTRACE + dt_utag = name + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; if (command == FILE_LSTAT) { dt_s1 = d->b; } else { dt_i1 = fd; } +#endif d->command = command; d->invoke = invoke_flstat; d->free = free_data; @@ -2746,11 +2799,13 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data)); - dt_utag = name; d->flags = desc->flags; d->fd = fd; +#ifdef HAVE_DTRACE + dt_utag = name; dt_i1 = fd; dt_i2 = d->flags; +#endif d->command = command; d->invoke = invoke_truncate; d->free = free_data; @@ -2764,18 +2819,20 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(buf + 9*4) + FILENAME_CHARSIZE); d->info.mode = get_int32(buf + 0 * 4); - dt_i1 = d->info.mode; d->info.uid = get_int32(buf + 1 * 4); - dt_i2 = d->info.uid; d->info.gid = get_int32(buf + 2 * 4); - dt_i3 = d->info.gid; d->info.accessTime = (time_t)((Sint64)get_int64(buf + 3 * 4)); d->info.modifyTime = (time_t)((Sint64)get_int64(buf + 5 * 4)); d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4)); FILENAME_COPY(d->b, buf + 9*4); +#ifdef HAVE_DTRACE + dt_i1 = d->info.mode; + dt_i2 = d->info.uid; + dt_i3 = d->info.gid; dt_s1 = d->b; - dt_utag = buf + 9 * 4 + strlen(d->b) + 1; + dt_utag = buf + 9 * 4 + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; +#endif d->command = command; d->invoke = invoke_write_info; d->free = free_data; @@ -2788,8 +2845,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); FILENAME_COPY(d->b, name); +#ifdef HAVE_DTRACE dt_s1 = d->b; - dt_utag = name + strlen(d->b) + 1; + dt_utag = name + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; +#endif d->command = command; d->invoke = invoke_readlink; d->free = free_data; @@ -2801,8 +2860,10 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); FILENAME_COPY(d->b, name); +#ifdef HAVE_DTRACE dt_s1 = d->b; - dt_utag = name + strlen(d->b) + 1; + dt_utag = name + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; +#endif d->command = command; d->invoke = invoke_altname; d->free = free_data; @@ -2822,10 +2883,12 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); - dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); +#ifdef HAVE_DTRACE + dt_s1 = d->b; dt_s2 = d->b + namelen; - dt_utag = buf + namelen + strlen(dt_s2) + 1; + dt_utag = buf + namelen + FILENAME_BYTELEN(dt_s2) + FILENAME_CHARSIZE; +#endif d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2846,10 +2909,12 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) + FILENAME_BYTELEN(new_name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); - dt_s1 = d->b; FILENAME_COPY(d->b + namelen, new_name); +#ifdef HAVE_DTRACE + dt_s1 = d->b; dt_s2 = d->b + namelen; - dt_utag = buf + namelen + strlen(dt_s2) + 1; + dt_utag = buf + namelen + FILENAME_BYTELEN(dt_s2) + FILENAME_CHARSIZE; +#endif d->flags = desc->flags; d->fd = fd; d->command = command; @@ -2864,18 +2929,20 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data)); d->fd = fd; - dt_i1 = d->fd; d->command = command; d->invoke = invoke_fadvise; d->free = free_data; d->level = 2; d->c.fadvise.offset = get_int64((uchar*) buf); - dt_i2 = d->c.fadvise.offset; d->c.fadvise.length = get_int64(((uchar*) buf) + sizeof(Sint64)); - dt_i3 = d->c.fadvise.length; d->c.fadvise.advise = get_int32(((uchar*) buf) + 2 * sizeof(Sint64)); +#ifdef HAVE_DTRACE + dt_i1 = d->fd; + dt_i2 = d->c.fadvise.offset; + dt_i3 = d->c.fadvise.length; dt_i4 = d->c.fadvise.advise; dt_utag = buf + 3 * sizeof(Sint64); +#endif goto done; } @@ -2920,8 +2987,6 @@ file_flush(ErlDrvData e) { #endif #ifdef HAVE_DTRACE dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); -#else - dt_private *dt_priv = NULL; #endif TRACE_C('f'); @@ -2933,8 +2998,11 @@ file_flush(ErlDrvData e) { #ifdef DEBUG r = #endif - flush_write(desc, NULL, dt_priv, - (desc->d == NULL) ? NULL : desc->d->sched_utag); + flush_write(desc, NULL +#ifdef HAVE_DTRACE + , dt_priv, (desc->d == NULL) ? NULL : desc->d->sched_utag +#endif + ); /* Only possible reason for bad return value is ENOMEM, and * there is nobody to tell... */ @@ -2978,8 +3046,6 @@ file_timeout(ErlDrvData e) { enum e_timer timer_state = desc->timer_state; #ifdef HAVE_DTRACE dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); -#else - dt_private *dt_priv = NULL; #endif TRACE_C('t'); @@ -2998,8 +3064,11 @@ file_timeout(ErlDrvData e) { #ifdef DEBUG int r = #endif - flush_write(desc, NULL, dt_priv, - (desc->d == NULL) ? NULL : desc->d->sched_utag); + flush_write(desc, NULL +#ifdef HAVE_DTRACE + , dt_priv, (desc->d == NULL) ? NULL : desc->d->sched_utag +#endif + ); /* Only possible reason for bad return value is ENOMEM, and * there is nobody to tell... */ @@ -3021,15 +3090,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { int p, q; int err; struct t_data *d = NULL; +#ifdef HAVE_DTRACE Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; - ERTS_DECLARE_DUMMY(Sint64 dt_i4) = 0; + Sint64 dt_i4 = 0; char *dt_utag = NULL; - ERTS_DECLARE_DUMMY(char *dt_s1) = NULL; -#ifdef HAVE_DTRACE + char *dt_s1 = NULL; dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); -#else - dt_private *dt_priv = NULL; #endif + TRACE_C('v'); p = 0; q = 1; @@ -3048,9 +3116,15 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { switch (command) { case FILE_CLOSE: { +#ifdef HAVE_DTRACE dt_utag = EV_CHAR_P(ev, p, q); +#endif flush_read(desc); - if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + if (flush_write_check_error(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } @@ -3061,9 +3135,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; - dt_i1 = d->fd; d->flags = desc->flags; +#ifdef HAVE_DTRACE + dt_i1 = d->fd; dt_i2 = d->flags; +#endif d->invoke = invoke_close; d->free = free_data; d->level = 2; @@ -3086,8 +3162,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } +#ifdef HAVE_DTRACE dt_utag = EV_CHAR_P(ev, p, q); - if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { +#endif + if (flush_write_check_error(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } @@ -3095,7 +3177,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { if (desc->read_bufsize == 0 && desc->read_binp != NULL && desc->read_size > 0) { /* We have allocated a buffer for line mode but should not really have a read-ahead buffer... */ - if (lseek_flush_read(desc, &err, dt_priv) < 0) { + if (lseek_flush_read(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } @@ -3171,14 +3257,16 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; - dt_i1 = d->fd; d->flags = desc->flags; - dt_i2 = d->flags; d->c.read.binp = desc->read_binp; d->c.read.bin_offset = desc->read_offset + desc->read_size; d->c.read.bin_size = desc->read_binp->orig_size - d->c.read.bin_offset; d->c.read.size = size; +#ifdef HAVE_DTRACE + dt_i1 = d->fd; + dt_i2 = d->flags; dt_i3 = d->c.read.size; +#endif driver_binary_inc_refc(d->c.read.binp); d->invoke = invoke_read; d->free = free_read; @@ -3196,12 +3284,22 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { * allocated binary + dealing with offsets and lengts are done in file_async ready * for this OP. */ +#ifdef HAVE_DTRACE dt_utag = EV_CHAR_P(ev, p, q); - if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { +#endif + if (flush_write_check_error(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size != 1+strlen(dt_utag)+1) { + if (ev->size != 1 +#ifdef HAVE_DTRACE + + FILENAME_BYTELEN(dt_utag) + FILENAME_CHARSIZE +#endif + ) { /* Wrong command length */ reply_posix_error(desc, EINVAL); goto done; @@ -3253,41 +3351,43 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; - dt_i1 = d->fd; d->flags = desc->flags; - dt_i2 = d->flags; d->c.read_line.binp = desc->read_binp; d->c.read_line.read_offset = desc->read_offset; d->c.read_line.read_size = desc->read_size; +#ifdef HAVE_DTRACE + dt_i1 = d->fd; + dt_i2 = d->flags; dt_i3 = d->c.read_line.read_offset; +#endif #if !ALWAYS_READ_LINE_AHEAD d->c.read_line.read_ahead = (desc->read_bufsize > 0); -#endif +#ifdef HAVE_DTRACE dt_i4 = d->c.read_line.read_ahead; +#endif +#endif driver_binary_inc_refc(d->c.read.binp); d->invoke = invoke_read_line; d->free = free_read_line; d->level = 1; cq_enq(desc, d); } goto done; - case FILE_WRITE: { + case FILE_WRITE: { /* Dtrace: The dtrace user tag is not last in message, + but follows the message tag directly. + This is handled specially in prim_file.erl */ ErlDrvSizeT skip = 1; ErlDrvSizeT size = ev->size - skip; +#ifdef HAVE_DTRACE dt_utag = EV_CHAR_P(ev, p, q); - skip += strlen(dt_utag) + 1; + skip += FILENAME_BYTELEN(dt_utag) + FILENAME_CHARSIZE; size = ev->size - skip; - /* - * Interesting dependency on using port # for key to async - * I/O worker pool thread: lseek_flush_read() can enqueue a - * lseek() op. If that lseek() were scheduled on a different - * thread than the write that we'll enqueue later in this case, - * then Bad Things could happen. This DTrace work is probably - * well worthwhile to get a sense of how often there's head-of- - * line blocking/unfairness during busy file I/O because of the - * mapping of port #/key -> thread. - */ - if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { +#endif + if (lseek_flush_read(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } @@ -3314,8 +3414,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { driver_set_timer(desc->port, desc->write_delay); } } else { - if ((d = async_write(desc, &err, !0, size, - &dt_i1, &dt_i2, &dt_i3)) == NULL) { + if ((d = async_write(desc, &err, !0, size +#ifdef HAVE_DTRACE + , &dt_i1, &dt_i2, &dt_i3 +#endif + )) == NULL) { MUTEX_UNLOCK(desc->q_mtx); reply_posix_error(desc, err); goto done; @@ -3325,27 +3428,46 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } } goto done; /* case FILE_WRITE */ - case FILE_PWRITEV: { + case FILE_PWRITEV: { /* Dtrace: The dtrace user tag is not last in message, + but follows the message tag directly. + This is handled specially in prim_file.erl */ Uint32 i, j, n; size_t total; - char tmp; +#ifdef HAVE_DTRACE + char dt_tmp; int dt_utag_bytes = 1; dt_utag = EV_CHAR_P(ev, p, q); - while (EV_GET_CHAR(ev, &tmp, &p, &q) && tmp != '\0') { + /* This will work for UTF-8, but not for UTF-16 - extra reminder here */ +#ifdef FILENAMES_16BIT +#error 16bit characters in filenames and dtrace in combination is not supported. +#endif + while (EV_GET_CHAR(ev, &dt_tmp, &p, &q) && dt_tmp != '\0') { dt_utag_bytes++; } - if (ev->size < 1+4+dt_utag_bytes +#endif + if (ev->size < 1+4 +#ifdef HAVE_DTRACE + + dt_utag_bytes +#endif || !EV_GET_UINT32(ev, &n, &p, &q)) { /* Buffer too short to contain even the number of pos/size specs */ reply_Uint_posix_error(desc, 0, EINVAL); goto done; } - if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { + if (lseek_flush_read(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_Uint_posix_error(desc, 0, err); goto done; } - if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + if (flush_write_check_error(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_Uint_posix_error(desc, 0, err); goto done; } @@ -3358,7 +3480,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } goto done; } - if (ev->size < 1+4+8*(2*n)+dt_utag_bytes) { + if (ev->size < 1+4+8*(2*n) +#ifdef HAVE_DTRACE + + dt_utag_bytes +#endif + ) { /* Buffer too short to contain even the pos/size specs */ reply_Uint_posix_error(desc, 0, EINVAL); goto done; @@ -3372,9 +3498,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; - dt_i1 = d->fd; d->flags = desc->flags; +#ifdef HAVE_DTRACE + dt_i1 = d->fd; dt_i2 = d->flags; +#endif d->c.pwritev.port = desc->port; d->c.pwritev.q_mtx = desc->q_mtx; d->c.pwritev.n = n; @@ -3412,14 +3540,20 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } } d->c.pwritev.size = total; +#ifdef HAVE_DTRACE dt_i3 = d->c.pwritev.size; +#endif d->c.pwritev.free_size = 0; if (j == 0) { /* Trivial case - nothing to write */ EF_FREE(d); reply_Uint(desc, 0); } else { - ErlDrvSizeT skip = 1 + 4 + 8 * (2*n) + dt_utag_bytes; + ErlDrvSizeT skip = 1 + 4 + 8 * (2*n) +#ifdef HAVE_DTRACE + + dt_utag_bytes +#endif + ; if (skip + total != ev->size) { /* Actual amount of data does not match * total of all pos/size specs @@ -3440,33 +3574,55 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } } goto done; /* case FILE_PWRITEV: */ - case FILE_PREADV: { + case FILE_PREADV: { /* Dtrace: The dtrace user tag is not last in message, + but follows the message tag directly. + This is handled specially in prim_file.erl */ register void * void_ptr; Uint32 i, n; ErlIOVec *res_ev; - char tmp; +#ifdef HAVE_DTRACE + char dt_tmp; int dt_utag_bytes = 1; - + /* This will work for UTF-8, but not for UTF-16 - extra reminder here */ +#ifdef FILENAMES_16BIT +#error 16bit characters in filenames and dtrace in combination is not supported. +#endif dt_utag = EV_CHAR_P(ev, p, q); - while (EV_GET_CHAR(ev, &tmp, &p, &q) && tmp != '\0') { + while (EV_GET_CHAR(ev, &dt_tmp, &p, &q) && dt_tmp != '\0') { dt_utag_bytes++; } - if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { +#endif + if (lseek_flush_read(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } - if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + if (flush_write_check_error(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } - if (ev->size < 1+8+dt_utag_bytes + if (ev->size < 1+8 +#ifdef HAVE_DTRACE + + dt_utag_bytes +#endif || !EV_GET_UINT32(ev, &n, &p, &q) || !EV_GET_UINT32(ev, &n, &p, &q)) { /* Buffer too short to contain even the number of pos/size specs */ reply_posix_error(desc, EINVAL); goto done; } - if (ev->size < 1+8+8*(2*n)+dt_utag_bytes) { + if (ev->size < 1+8+8*(2*n) +#ifdef HAVE_DTRACE + + dt_utag_bytes +#endif + ) { /* Buffer wrong length to contain the pos/size specs */ reply_posix_error(desc, EINVAL); goto done; @@ -3485,9 +3641,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; - dt_i1 = d->fd; d->flags = desc->flags; +#ifdef HAVE_DTRACE + dt_i1 = d->fd; dt_i2 = d->flags; +#endif d->c.preadv.n = n; d->c.preadv.cnt = 0; d->c.preadv.size = 0; @@ -3515,7 +3673,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else size = ((size_t)sizeH<<32) | sizeL; #endif +#ifdef HAVE_DTRACE dt_i3 += size; +#endif if (! (res_ev->binv[i] = driver_alloc_binary(size))) { reply_posix_error(desc, ENOMEM); break; @@ -3572,17 +3732,30 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } +#ifdef HAVE_DTRACE dt_utag = EV_CHAR_P(ev, p, q); - if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { +#endif + if (lseek_flush_read(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } - if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + if (flush_write_check_error(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } - if ((d = async_lseek(desc, &err, !0, offset, origin, - &dt_i1, &dt_i2, &dt_i3)) == NULL) { + if ((d = async_lseek(desc, &err, !0, offset, origin +#ifdef HAVE_DTRACE + , &dt_i1, &dt_i2, &dt_i3 +#endif + )) == NULL) { reply_posix_error(desc, err); goto done; } @@ -3595,11 +3768,22 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, ENOENT); goto done; } +#ifndef HAVE_DTRACE + /* In the dtrace case, the iov has an extra element, the dtrace utag - we will need + another test to see that + the filename is in a single buffer: */ if (ev->size-1 != ev->iov[q].iov_len-p) { /* Name not in one single buffer */ reply_posix_error(desc, EINVAL); goto done; } +#else + if (((byte *)ev->iov[q].iov_base)[ev->iov[q].iov_len-1] != '\0') { + /* Name not in one single buffer */ + reply_posix_error(desc, EINVAL); + goto done; + } +#endif filename = EV_CHAR_P(ev, p, q); d = EF_ALLOC(sizeof(struct t_data) -1 + FILENAME_BYTELEN(filename) + FILENAME_CHARSIZE); if (! d) { @@ -3610,8 +3794,22 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->reply = !0; /* Copy name */ FILENAME_COPY(d->b, filename); - dt_s1 = d->b; - dt_utag = filename + strlen(d->b) + 1; +#ifdef HAVE_DTRACE + { + char dt_tmp; + + /* This will work for UTF-8, but not for UTF-16 - extra reminder here */ +#ifdef FILENAMES_16BIT +#error 16bit characters in filenames and dtrace in combination is not supported. +#endif + while (EV_GET_CHAR(ev, &dt_tmp, &p, &q) && dt_tmp != '\0') + ; + dt_s1 = d->b; + dt_utag = EV_CHAR_P(ev, p, q); + if (*dt_utag != 0) + fprintf(stderr,"dt_utag = %s\r\n",dt_utag); + } +#endif d->c.read_file.binp = NULL; d->invoke = invoke_read_file; d->free = free_read_file; @@ -3650,12 +3848,22 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } +#ifdef HAVE_DTRACE dt_utag = EV_CHAR_P(ev, p, q); - if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { +#endif + if (lseek_flush_read(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } - if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + if (flush_write_check_error(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } @@ -3672,13 +3880,15 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->command = command; d->reply = !0; d->fd = desc->fd; - dt_i1 = d->fd; d->flags = desc->flags; - dt_i2 = d->flags; d->c.preadv.offsets[0] = hdr_offset; - dt_i3 = d->c.preadv.offsets[0]; d->c.preadv.size = max_size; +#ifdef HAVE_DTRACE + dt_i1 = d->fd; + dt_i2 = d->flags; + dt_i3 = d->c.preadv.offsets[0]; dt_i4 = d->c.preadv.size; +#endif res_ev = &d->c.preadv.eiov; /* XXX possible alignment problems here for weird machines */ res_ev->iov = void_ptr = d + 1; @@ -3700,12 +3910,17 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } +#ifdef HAVE_DTRACE dt_i1 = opt; dt_utag = EV_CHAR_P(ev, p, q); +#endif switch (opt) { case FILE_OPT_DELAYED_WRITE: { Uint32 sizeH, sizeL, delayH, delayL; - if (ev->size != 1+1+4*sizeof(Uint32)+strlen(dt_utag)+1 + if (ev->size != 1+1+4*sizeof(Uint32) +#ifdef HAVE_DTRACE + + FILENAME_BYTELEN(dt_utag) + FILENAME_CHARSIZE +#endif || !EV_GET_UINT32(ev, &sizeH, &p, &q) || !EV_GET_UINT32(ev, &sizeL, &p, &q) || !EV_GET_UINT32(ev, &delayH, &p, &q) @@ -3732,13 +3947,18 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else desc->write_delay = ((unsigned long)delayH << 32) | delayL; #endif +#ifdef HAVE_DTRACE dt_i2 = desc->write_delay; +#endif TRACE_C('K'); reply_ok(desc); } goto done; case FILE_OPT_READ_AHEAD: { Uint32 sizeH, sizeL; - if (ev->size != 1+1+2*sizeof(Uint32)+strlen(dt_utag)+1 + if (ev->size != 1+1+2*sizeof(Uint32) +#ifdef HAVE_DTRACE + + FILENAME_BYTELEN(dt_utag)+FILENAME_CHARSIZE +#endif || !EV_GET_UINT32(ev, &sizeH, &p, &q) || !EV_GET_UINT32(ev, &sizeL, &p, &q)) { /* Buffer has wrong length to contain the option values */ @@ -3754,7 +3974,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else desc->read_bufsize = ((size_t)sizeH << 32) | sizeL; #endif +#ifdef HAVE_DTRACE dt_i2 = desc->read_bufsize; +#endif TRACE_C('K'); reply_ok(desc); } goto done; @@ -3841,11 +4063,19 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } /* switch(command) */ - if (lseek_flush_read(desc, &err, dt_priv, dt_utag) < 0) { + if (lseek_flush_read(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } - if (flush_write_check_error(desc, &err, dt_priv, dt_utag) < 0) { + if (flush_write_check_error(desc, &err +#ifdef HAVE_DTRACE + , dt_priv, dt_utag +#endif + ) < 0) { reply_posix_error(desc, err); goto done; } else { diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index 6778fe353c..88c07ab4eb 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 46ce3ab1a4..f7861514ae 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -25,59 +25,39 @@ %%% Interface towards a single file's contents. Uses ?FD_DRV. %% Generic file contents operations - --export([ - open/2, open/3, - close/1, close/2, - datasync/1, datasync/2, - sync/1, sync/2, - advise/4, advise/5, - position/2, position/3, - truncate/1, truncate/2, - write/2, write/3, - pwrite/2, pwrite/3, pwrite/4, - read/2, read/3, - read_line/1, read_line/2, - pread/2, pread/3, pread/4, - copy/3, copy/4, - sendfile/10 - ]). +-export([open/2, close/1, datasync/1, sync/1, advise/4, position/2, truncate/1, + write/2, pwrite/2, pwrite/3, read/2, read_line/1, pread/2, pread/3, + copy/3, sendfile/10]). %% Specialized file operations --export([open/1]). --export([read_file/1, read_file/2, read_file/3, write_file/2, write_file/3]). --export([ipread_s32bu_p32bu/3, ipread_s32bu_p32bu/4]). +-export([open/1, open/3]). +-export([read_file/1, read_file/2, write_file/2]). +-export([ipread_s32bu_p32bu/3]). %%% Interface towards file system and metadata. Uses ?DRV. %% Takes an optional port (opens a ?DRV port per default) as first argument. - --export([ - get_cwd/0, get_cwd/1, get_cwd/3, - set_cwd/1, set_cwd/3, - delete/1, delete/2, delete/3, - rename/2, rename/3, rename/4, - make_dir/1, make_dir/3, - del_dir/1, del_dir/3, - read_file_info/1, read_file_info/2, read_file_info/3, read_file_info/4, - altname/1, altname/3, - write_file_info/2, write_file_info/4, write_file_info/5, - make_link/2, make_link/3, make_link/4, - make_symlink/2, make_symlink/3, make_symlink/4, - read_link/1, read_link/3, - read_link_info/1, read_link_info/2, read_link_info/3, read_link_info/4, - list_dir/1, list_dir/3 - ]). +-export([get_cwd/0, get_cwd/1, get_cwd/2, + set_cwd/1, set_cwd/2, + delete/1, delete/2, + rename/2, rename/3, + make_dir/1, make_dir/2, + del_dir/1, del_dir/2, + read_file_info/1, read_file_info/2, read_file_info/3, + altname/1, altname/2, + write_file_info/2, write_file_info/3, write_file_info/4, + make_link/2, make_link/3, + make_symlink/2, make_symlink/3, + read_link/1, read_link/2, + read_link_info/1, read_link_info/2, read_link_info/3, + list_dir/1, list_dir/2]). %% How to start and stop the ?DRV port. -export([start/0, stop/1]). %% Debug exports --export([open_int/4, open_int/5, open_mode/1, open_mode/4]). - -%% For DTrace/Systemtap tracing --export([get_dtrace_utag/0]). +-export([open_int/4, open_mode/1, open_mode/4]). %%%----------------------------------------------------------------- %%% Includes and defines @@ -175,21 +155,30 @@ %%% Supposed to be called by applications through module file. -%% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}. -open(File, ModeList) -> - open(File, ModeList, get_dtrace_utag()). +%% Opens a file using the driver port Port. Returns {error, Reason} +%% | {ok, FileDescriptor} +open(Port, File, ModeList) when is_port(Port), + (is_list(File) orelse is_binary(File)), + is_list(ModeList) -> + case open_mode(ModeList) of + {Mode, _Portopts, _Setopts} -> + open_int(Port, File, Mode, []); + Reason -> + {error, Reason} + end; +open(_,_,_) -> + {error, badarg}. -open(File, ModeList, DTraceUtag) - when (is_list(File) orelse is_binary(File)), - is_list(ModeList), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> +%% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}. +open(File, ModeList) when (is_list(File) orelse is_binary(File)), + is_list(ModeList) -> case open_mode(ModeList) of {Mode, Portopts, Setopts} -> - open_int({?FD_DRV, Portopts}, File, Mode, Setopts, DTraceUtag); + open_int({?FD_DRV, Portopts},File, Mode, Setopts); Reason -> {error, Reason} end; -open(_, _, _) -> +open(_, _) -> {error, badarg}. %% Opens a port that can be used for open/3 or read_file/2. @@ -204,34 +193,29 @@ open(Portopts) when is_list(Portopts) -> open(_) -> {error, badarg}. -open_int(Arg, File, Mode, Setopts) -> - open_int(Arg, File, Mode, Setopts, get_dtrace_utag()). - -open_int({Driver, Portopts}, File, Mode, Setopts, DTraceUtag) -> - %% TODO: add DTraceUtag to drv_open()? +open_int({Driver, Portopts}, File, Mode, Setopts) -> case drv_open(Driver, Portopts) of {ok, Port} -> - open_int(Port, File, Mode, Setopts, DTraceUtag); + open_int(Port, File, Mode, Setopts); {error, _} = Error -> Error end; -open_int(Port, File, Mode, Setopts, DTraceUtag) -> +open_int(Port, File, Mode, Setopts) -> M = Mode band ?EFILE_MODE_MASK, - case drv_command(Port, [<>, - pathname(File), enc_utag(DTraceUtag)]) of + case drv_command(Port, [<>, pathname(File)]) of {ok, Number} -> - open_int_setopts(Port, Number, Setopts, DTraceUtag); + open_int_setopts(Port, Number, Setopts); Error -> drv_close(Port), Error end. -open_int_setopts(Port, Number, [], _DTraceUtag) -> +open_int_setopts(Port, Number, []) -> {ok, #file_descriptor{module = ?MODULE, data = {Port, Number}}}; -open_int_setopts(Port, Number, [Cmd | Tail], DTraceUtag) -> - case drv_command(Port, [Cmd, enc_utag(DTraceUtag)]) of +open_int_setopts(Port, Number, [Cmd | Tail]) -> + case drv_command(Port, Cmd) of ok -> - open_int_setopts(Port, Number, Tail, DTraceUtag); + open_int_setopts(Port, Number, Tail); Error -> drv_close(Port), Error @@ -241,64 +225,50 @@ open_int_setopts(Port, Number, [Cmd | Tail], DTraceUtag) -> %% Returns ok. -close(Arg) -> - close(Arg, get_dtrace_utag()). - -close(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) - when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - case drv_command(Port, [<>, enc_utag(DTraceUtag)]) of +close(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> + case drv_command(Port, <>) of ok -> drv_close(Port); Error -> Error end; %% Closes a port opened with open/1. -close(Port, _DTraceUtag) when is_port(Port) -> +close(Port) when is_port(Port) -> drv_close(Port). --define(ADVISE(Offs, Len, Adv, BUtag), +-define(ADVISE(Offs, Len, Adv), <>). + Adv:32/signed>>). %% Returns {error, Reason} | ok. -advise(FD, Offset, Length, Advise) -> - advise(FD, Offset, Length, Advise, get_dtrace_utag()). - advise(#file_descriptor{module = ?MODULE, data = {Port, _}}, - Offset, Length, Advise, DTraceUtag) - when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - BUtag = term_to_binary(enc_utag(DTraceUtag)), + Offset, Length, Advise) -> case Advise of normal -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL, BUtag), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NORMAL), drv_command(Port, Cmd); random -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM, BUtag), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_RANDOM), drv_command(Port, Cmd); sequential -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL, BUtag), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_SEQUENTIAL), drv_command(Port, Cmd); will_need -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED, BUtag), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_WILLNEED), drv_command(Port, Cmd); dont_need -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED, BUtag), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_DONTNEED), drv_command(Port, Cmd); no_reuse -> - Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE, BUtag), + Cmd = ?ADVISE(Offset, Length, ?POSIX_FADV_NOREUSE), drv_command(Port, Cmd); _ -> {error, einval} end. %% Returns {error, Reason} | ok. -write(Desc, Bytes) -> - write(Desc, Bytes, get_dtrace_utag()). - -write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes, DTraceUtag) - when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - %% This is rare case where DTraceUtag is not at end of command list. - case drv_command(Port, [?FILE_WRITE,enc_utag(DTraceUtag),Bytes]) of +write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> + case drv_command_nt(Port, [?FILE_WRITE,erlang:prepend_vm_utag_data(Bytes)],false,undefined) of {ok, _Size} -> ok; Error -> @@ -308,40 +278,39 @@ write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes, DTraceUtag) %% Returns ok | {error, {WrittenCount, Reason}} pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) when is_list(L) -> - pwrite_int(Port, L, 0, [], [], get_dtrace_utag()). + pwrite_int(Port, L, 0, [], []). -pwrite_int(_, [], 0, [], [], _DTraceUtag) -> +pwrite_int(_, [], 0, [], []) -> ok; -pwrite_int(Port, [], N, Spec, Data, DTraceUtag) -> - Header = list_to_binary([<>, enc_utag(DTraceUtag), - <>, reverse(Spec)]), - case drv_command_raw(Port, [Header | reverse(Data)]) of +pwrite_int(Port, [], N, Spec, Data) -> + Header = list_to_binary([?FILE_PWRITEV, erlang:prepend_vm_utag_data(<>) | reverse(Spec)]), + case drv_command_nt(Port, [Header | reverse(Data)], false, undefined) of {ok, _Size} -> ok; Error -> Error end; -pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data, DTraceUtag) +pwrite_int(Port, [{Offs, Bytes} | T], N, Spec, Data) when is_integer(Offs) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag); + pwrite_int(Port, T, N, Spec, Data, Offs, Bytes); true -> {error, einval} end; -pwrite_int(_, [_|_], _N, _Spec, _Data, _DTraceUtag) -> +pwrite_int(_, [_|_], _N, _Spec, _Data) -> {error, badarg}. -pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag) +pwrite_int(Port, T, N, Spec, Data, Offs, Bin) when is_binary(Bin) -> Size = byte_size(Bin), pwrite_int(Port, T, N+1, [<> | Spec], - [Bin | Data], DTraceUtag); -pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag) -> + [Bin | Data]); +pwrite_int(Port, T, N, Spec, Data, Offs, Bytes) -> try list_to_binary(Bytes) of Bin -> - pwrite_int(Port, T, N, Spec, Data, Offs, Bin, DTraceUtag) + pwrite_int(Port, T, N, Spec, Data, Offs, Bin) catch error:Reason -> {error, Reason} @@ -350,28 +319,11 @@ pwrite_int(Port, T, N, Spec, Data, Offs, Bytes, DTraceUtag) -> %% Returns {error, Reason} | ok. -pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag) - when is_list(L), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - pwrite_int(Port, L, 0, [], [], DTraceUtag); - -pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) +pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes) when is_integer(Offs) -> - pwrite_int2(Port, Offs, Bytes, get_dtrace_utag()); -pwrite(#file_descriptor{module = ?MODULE}, _, _) -> - {error, badarg}. - -pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Bytes, DTraceUtag) - when is_integer(Offs), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - pwrite_int2(Port, Offs, Bytes, DTraceUtag); -pwrite(#file_descriptor{module = ?MODULE}, _, _, _DTraceUtag) -> - {error, badarg}. - -pwrite_int2(Port, Offs, Bytes, DTraceUtag) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - case pwrite_int(Port, [], 0, [], [], Offs, Bytes, DTraceUtag) of + case pwrite_int(Port, [], 0, [], [], Offs, Bytes) of {error, {_, Reason}} -> {error, Reason}; Result -> @@ -379,30 +331,22 @@ pwrite_int2(Port, Offs, Bytes, DTraceUtag) -> end; true -> {error, einval} - end. - -%% Returns {error, Reason} | ok. -datasync(FD) -> - datasync(FD, get_dtrace_utag()). + end; +pwrite(#file_descriptor{module = ?MODULE}, _, _) -> + {error, badarg}. -datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) - when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - drv_command(Port, [?FILE_FDATASYNC, enc_utag(DTraceUtag)]). %% Returns {error, Reason} | ok. -sync(FD) -> - sync(FD, get_dtrace_utag()). +datasync(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> + drv_command(Port, [?FILE_FDATASYNC]). -sync(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) - when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - drv_command(Port, [?FILE_FSYNC, enc_utag(DTraceUtag)]). +%% Returns {error, Reason} | ok. +sync(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> + drv_command(Port, [?FILE_FSYNC]). %% Returns {ok, Data} | eof | {error, Reason}. -read_line(FD) -> - read_line(FD, get_dtrace_utag()). - -read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) -> - case drv_command(Port, [<>, enc_utag(DTraceUtag)]) of +read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> + case drv_command(Port, <>) of {ok, {0, _Data}} -> eof; {ok, {_Size, Data}} -> @@ -422,17 +366,11 @@ read_line(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) -> end. %% Returns {ok, Data} | eof | {error, Reason}. -read(FD, Size) -> - read(FD, Size, get_dtrace_utag()). - -read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size, DTraceUtag) - when is_integer(Size), - 0 =< Size, - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> +read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size) + when is_integer(Size), 0 =< Size -> if Size < ?LARGEFILESIZE -> - case drv_command(Port, [<>, - enc_utag(DTraceUtag)]) of + case drv_command(Port, <>) of {ok, {0, _Data}} when Size =/= 0 -> eof; {ok, {_Size, Data}} -> @@ -441,8 +379,7 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size, DTraceUtag) %% Garbage collecting here might help if %% the current processes have some old binaries left. erlang:garbage_collect(), - case drv_command(Port, [<>, - enc_utag(DTraceUtag)]) of + case drv_command(Port, <>) of {ok, {0, _Data}} when Size =/= 0 -> eof; {ok, {_Size, Data}} -> @@ -460,43 +397,35 @@ read(#file_descriptor{module = ?MODULE, data = {Port, _}}, Size, DTraceUtag) %% Returns {ok, [Data|eof, ...]} | {error, Reason} pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) when is_list(L) -> - pread_int(Port, L, 0, [], get_dtrace_utag()). + pread_int(Port, L, 0, []). -pread_int(_, [], 0, [], _DTraceUtag) -> +pread_int(_, [], 0, []) -> {ok, []}; -pread_int(Port, [], N, Spec, DTraceUtag) -> - drv_command(Port, [<>, enc_utag(DTraceUtag), - <<0:32, N:32>>, reverse(Spec)]); -pread_int(Port, [{Offs, Size} | T], N, Spec, DTraceUtag) +pread_int(Port, [], N, Spec) -> + drv_command_nt(Port, [?FILE_PREADV, erlang:prepend_vm_utag_data(<<0:32, N:32>>) | reverse(Spec)],false, undefined); +pread_int(Port, [{Offs, Size} | T], N, Spec) when is_integer(Offs), is_integer(Size), 0 =< Size -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> - pread_int(Port, T, N+1, [<> | Spec], - DTraceUtag); + pread_int(Port, T, N+1, [<> | Spec]); true -> {error, einval} end; -pread_int(_, [_|_], _N, _Spec, _DTraceUtag) -> +pread_int(_, [_|_], _N, _Spec) -> {error, badarg}. + + %% Returns {ok, Data} | eof | {error, Reason}. -pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L, DTraceUtag) - when is_list(L), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - pread_int(Port, L, 0, [], get_dtrace_utag()); -pread(FD, Offs, Size) +pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) when is_integer(Offs), is_integer(Size), 0 =< Size -> - pread(FD, Offs, Size, get_dtrace_utag()). - -pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size, DTraceUtag) - when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> - case drv_command(Port, - [<>, enc_utag(DTraceUtag), - <<0:32, 1:32, Offs:64/signed, Size:64>>]) of + case drv_command_nt(Port, + [?FILE_PREADV, erlang:prepend_vm_utag_data(<<0:32, 1:32, + Offs:64/signed, Size:64>>)], false, undefined) of {ok, [eof]} -> eof; {ok, [Data]} -> @@ -507,22 +436,17 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size, DTraceUt true -> {error, einval} end; -pread(_, _, _, _) -> +pread(#file_descriptor{module = ?MODULE, data = {_, _}}, _, _) -> {error, badarg}. %% Returns {ok, Position} | {error, Reason}. -position(FD, At) -> - position(FD, At, get_dtrace_utag()). - -position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At, DTraceUtag) - when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> +position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At) -> case lseek_position(At) of {Offs, Whence} when -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE -> - drv_command(Port, [<>, - enc_utag(DTraceUtag)]); + drv_command(Port, <>); {_, _} -> {error, einval}; Reason -> @@ -530,89 +454,63 @@ position(#file_descriptor{module = ?MODULE, data = {Port, _}}, At, DTraceUtag) end. %% Returns {error, Reaseon} | ok. -truncate(FD) -> - truncate(FD, get_dtrace_utag()). - -truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}, DTraceUtag) - when (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - drv_command(Port, [<>, enc_utag(DTraceUtag)]). +truncate(#file_descriptor{module = ?MODULE, data = {Port, _}}) -> + drv_command(Port, <>). %% Returns {error, Reason} | {ok, BytesCopied} -copy(Source, Dest, Length) -> - copy(Source, Dest, Length, get_dtrace_utag()). - copy(#file_descriptor{module = ?MODULE} = Source, #file_descriptor{module = ?MODULE} = Dest, - Length, DTraceUtag) + Length) when is_integer(Length), Length >= 0; - is_atom(Length), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + is_atom(Length) -> %% XXX Should be moved down to the driver for optimization. - file:copy_opened(Source, Dest, Length, DTraceUtag). - + file:copy_opened(Source, Dest, Length). -ipread_s32bu_p32bu(FD, Offs, Arg) -> - ipread_s32bu_p32bu(FD, Offs, Arg, get_dtrace_utag()). ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}} = Handle, Offs, - Infinity, - DTraceUtag) - when is_atom(Infinity), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + Infinity) when is_atom(Infinity) -> ipread_s32bu_p32bu(Handle, Offs, (1 bsl 31)-1); ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, - MaxSize, - DTraceUtag) - when is_integer(Offs), - is_integer(MaxSize), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> + MaxSize) + when is_integer(Offs), is_integer(MaxSize) -> if -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, 0 =< MaxSize, MaxSize < (1 bsl 31) -> - drv_command(Port, [<>, enc_utag(DTraceUtag)]); + drv_command(Port, <>); true -> {error, einval} end; ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}}, _Offs, - _MaxSize, - _DTraceUtag) -> + _MaxSize) -> {error, badarg}. %% Returns {ok, Contents} | {error, Reason} read_file(File) when (is_list(File) orelse is_binary(File)) -> - read_file(File, get_dtrace_utag()); -read_file(_) -> - {error, badarg}. - -read_file(File, DTraceUtag) - when (is_list(File) orelse is_binary(File)), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag))-> case drv_open(?FD_DRV, [binary]) of {ok, Port} -> - Result = read_file(Port, File, DTraceUtag), + Result = read_file(Port, File), close(Port), Result; {error, _} = Error -> Error end; -read_file(_, _) -> +read_file(_) -> {error, badarg}. %% Takes a Port opened with open/1. -read_file(Port, File, DTraceUtag) when is_port(Port), +read_file(Port, File) when is_port(Port), (is_list(File) orelse is_binary(File)) -> - Cmd = [?FILE_READ_FILE | - list_to_binary([pathname(File), enc_utag(DTraceUtag)])], + Cmd = [?FILE_READ_FILE | pathname(File)], case drv_command(Port, Cmd) of {error, enomem} -> %% It could possibly help to do a @@ -624,30 +522,22 @@ read_file(Port, File, DTraceUtag) when is_port(Port), Result -> Result end; -read_file(_,_,_) -> +read_file(_,_) -> {error, badarg}. %% Returns {error, Reason} | ok. -write_file(File, Bin) -> - write_file(File, Bin, get_dtrace_utag()). - -write_file(File, Bin, DTraceUtag) - when (is_list(File) orelse is_binary(File)), - (is_list(DTraceUtag) orelse is_binary(DTraceUtag)) -> - OldUtag = put(dtrace_utag, DTraceUtag), % TODO: API? +write_file(File, Bin) when (is_list(File) orelse is_binary(File)) -> case open(File, [binary, write]) of {ok, Handle} -> Result = write(Handle, Bin), close(Handle), - put(dtrace_utag, OldUtag), Result; Error -> - put(dtrace_utag, OldUtag), Error end; -write_file(_, _, _) -> +write_file(_, _) -> {error, badarg}. @@ -711,56 +601,54 @@ stop(Port) when is_port(Port) -> -%% get_cwd/{0,1,3} +%% get_cwd/{0,1,2} get_cwd() -> - get_cwd_int(0, get_dtrace_utag()). + get_cwd_int(0). get_cwd(Port) when is_port(Port) -> - get_cwd_int(Port, 0, get_dtrace_utag()); + get_cwd_int(Port, 0); get_cwd([]) -> - get_cwd_int(0, get_dtrace_utag()); + get_cwd_int(0); get_cwd([Letter, $: | _]) when $a =< Letter, Letter =< $z -> - get_cwd_int(Letter - $a + 1, get_dtrace_utag()); + get_cwd_int(Letter - $a + 1); get_cwd([Letter, $: | _]) when $A =< Letter, Letter =< $Z -> - get_cwd_int(Letter - $A + 1, get_dtrace_utag()); + get_cwd_int(Letter - $A + 1); get_cwd([_|_]) -> {error, einval}; get_cwd(_) -> {error, badarg}. -get_cwd(Port, [], DTraceUtag) when is_port(Port) -> - get_cwd_int(Port, 0, DTraceUtag); -get_cwd(Port, no_drive, DTraceUtag) when is_port(Port) -> - get_cwd_int(Port, 0, DTraceUtag); -get_cwd(Port, [Letter, $: | _], DTraceUtag) +get_cwd(Port, []) when is_port(Port) -> + get_cwd_int(Port, 0); +get_cwd(Port, [Letter, $: | _]) when is_port(Port), $a =< Letter, Letter =< $z -> - get_cwd_int(Port, Letter - $a + 1, DTraceUtag); -get_cwd(Port, [Letter, $: | _], DTraceUtag) + get_cwd_int(Port, Letter - $a + 1); +get_cwd(Port, [Letter, $: | _]) when is_port(Port), $A =< Letter, Letter =< $Z -> - get_cwd_int(Port, Letter - $A + 1, DTraceUtag); -get_cwd(Port, [_|_], _DTraceUtag) when is_port(Port) -> + get_cwd_int(Port, Letter - $A + 1); +get_cwd(Port, [_|_]) when is_port(Port) -> {error, einval}; -get_cwd(_, _, _DTraceUtag) -> +get_cwd(_, _) -> {error, badarg}. -get_cwd_int(Drive, DTraceUtag) -> - get_cwd_int({?DRV, [binary]}, Drive, DTraceUtag). +get_cwd_int(Drive) -> + get_cwd_int({?DRV, [binary]}, Drive). -get_cwd_int(Port, Drive, DTraceUtag) -> - drv_command(Port, list_to_binary([?FILE_PWD, Drive, enc_utag(DTraceUtag)])). +get_cwd_int(Port, Drive) -> + drv_command(Port, <>). -%% set_cwd/{1,3} +%% set_cwd/{1,2} set_cwd(Dir) -> - set_cwd_int({?DRV, [binary]}, Dir, get_dtrace_utag()). + set_cwd_int({?DRV, [binary]}, Dir). -set_cwd(Port, Dir, DTraceUtag) when is_port(Port) -> - set_cwd_int(Port, Dir, DTraceUtag). +set_cwd(Port, Dir) when is_port(Port) -> + set_cwd_int(Port, Dir). -set_cwd_int(Port, Dir0, DTraceUtag) -> +set_cwd_int(Port, Dir0) -> Dir = (catch case os:type() of @@ -770,7 +658,7 @@ set_cwd_int(Port, Dir0, DTraceUtag) -> %% must call get_cwd from here and use %% absname/2, since %% absname/1 uses file:get_cwd ... - case get_cwd_int(Port, 0, "") of + case get_cwd_int(Port, 0) of {ok, AbsPath} -> filename:absname(Dir0, AbsPath); _Badcwd -> @@ -781,86 +669,78 @@ set_cwd_int(Port, Dir0, DTraceUtag) -> end), %% Dir is now either a string or an EXIT tuple. %% An EXIT tuple will fail in the following catch. - drv_command(Port, [?FILE_CHDIR, pathname(Dir), enc_utag(DTraceUtag)]). + drv_command(Port, [?FILE_CHDIR, pathname(Dir)]). -%% delete/{1,2,3} +%% delete/{1,2} delete(File) -> - delete_int({?DRV, [binary]}, File, get_dtrace_utag()). + delete_int({?DRV, [binary]}, File). delete(Port, File) when is_port(Port) -> - delete_int(Port, File, get_dtrace_utag()). + delete_int(Port, File). -delete(Port, File, DTraceUtag) when is_port(Port) -> - delete_int(Port, File, DTraceUtag). +delete_int(Port, File) -> + drv_command(Port, [?FILE_DELETE, pathname(File)]). -delete_int(Port, File, DTraceUtag) -> - drv_command(Port, [?FILE_DELETE, pathname(File), enc_utag(DTraceUtag)]). - -%% rename/{2,3,4} +%% rename/{2,3} rename(From, To) -> - rename_int({?DRV, [binary]}, From, To, get_dtrace_utag()). + rename_int({?DRV, [binary]}, From, To). rename(Port, From, To) when is_port(Port) -> - rename_int(Port, From, To, get_dtrace_utag()). - -rename(Port, From, To, DTraceUtag) when is_port(Port) -> - rename_int(Port, From, To, DTraceUtag). + rename_int(Port, From, To). -rename_int(Port, From, To, DTraceUtag) -> - drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To), - enc_utag(DTraceUtag)]). +rename_int(Port, From, To) -> + drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To)]). -%% make_dir/{1,3} +%% make_dir/{1,2} make_dir(Dir) -> - make_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). + make_dir_int({?DRV, [binary]}, Dir). -make_dir(Port, Dir, DTraceUtag) when is_port(Port) -> - make_dir_int(Port, Dir, DTraceUtag). +make_dir(Port, Dir) when is_port(Port) -> + make_dir_int(Port, Dir). -make_dir_int(Port, Dir, DTraceUtag) -> - drv_command(Port, [?FILE_MKDIR, pathname(Dir), enc_utag(DTraceUtag)]). +make_dir_int(Port, Dir) -> + drv_command(Port, [?FILE_MKDIR, pathname(Dir)]). -%% del_dir/{1,3} +%% del_dir/{1,2} del_dir(Dir) -> - del_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). + del_dir_int({?DRV, [binary]}, Dir). + +del_dir(Port, Dir) when is_port(Port) -> + del_dir_int(Port, Dir). -del_dir(Port, Dir, DTraceUtag) when is_port(Port) -> - del_dir_int(Port, Dir, DTraceUtag). +del_dir_int(Port, Dir) -> + drv_command(Port, [?FILE_RMDIR, pathname(Dir)]). -del_dir_int(Port, Dir, DTraceUtag) -> - drv_command(Port, [?FILE_RMDIR, pathname(Dir), enc_utag(DTraceUtag)]). -%% read_file_info/{1,2,3,4} + +%% read_file_info/{1,2,3} read_file_info(File) -> - read_file_info_int({?DRV, [binary]}, File, local, get_dtrace_utag()). + read_file_info_int({?DRV, [binary]}, File, local). read_file_info(Port, File) when is_port(Port) -> - read_file_info_int(Port, File, local, get_dtrace_utag()); + read_file_info_int(Port, File, local); read_file_info(File, Opts) -> - read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local), get_dtrace_utag()). - -read_file_info(Port, File, Opts) when is_port(Port), is_list(Opts) -> - read_file_info_int(Port, File, plgv(time, Opts, local), get_dtrace_utag()). + read_file_info_int({?DRV, [binary]}, File, plgv(time, Opts, local)). -read_file_info(Port, File, Opts, DTraceUtag) when is_port(Port) -> - read_file_info_int(Port, File, plgv(time, Opts, local), DTraceUtag). +read_file_info(Port, File, Opts) when is_port(Port) -> + read_file_info_int(Port, File, plgv(time, Opts, local)). -read_file_info_int(Port, File, TimeType, DTraceUtag) -> +read_file_info_int(Port, File, TimeType) -> try - case drv_command(Port, [?FILE_FSTAT, pathname(File), enc_utag(DTraceUtag)]) of + case drv_command(Port, [?FILE_FSTAT, pathname(File)]) of {ok, FI} -> {ok, FI#file_info{ ctime = from_seconds(FI#file_info.ctime, TimeType), mtime = from_seconds(FI#file_info.mtime, TimeType), @@ -872,33 +752,30 @@ read_file_info_int(Port, File, TimeType, DTraceUtag) -> error:_ -> {error, badarg} end. -%% altname/{1,3} -altname(File) -> - altname_int({?DRV, [binary]}, File, get_dtrace_utag()). +%% altname/{1,2} -altname(Port, File, DTraceUtag) when is_port(Port) -> - altname_int(Port, File, DTraceUtag). +altname(File) -> + altname_int({?DRV, [binary]}, File). -altname_int(Port, File, DTraceUtag) -> - drv_command(Port, [?FILE_ALTNAME, pathname(File), enc_utag(DTraceUtag)]). +altname(Port, File) when is_port(Port) -> + altname_int(Port, File). +altname_int(Port, File) -> + drv_command(Port, [?FILE_ALTNAME, pathname(File)]). -%% write_file_info/{2,3,4,5} +%% write_file_info/{2,3,4} write_file_info(File, Info) -> - write_file_info_int({?DRV, [binary]}, File, Info, local, get_dtrace_utag()). + write_file_info_int({?DRV, [binary]}, File, Info, local). write_file_info(Port, File, Info) when is_port(Port) -> - write_file_info_int(Port, File, Info, local, get_dtrace_utag()); + write_file_info_int(Port, File, Info, local); write_file_info(File, Info, Opts) -> - write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local), get_dtrace_utag()). + write_file_info_int({?DRV, [binary]}, File, Info, plgv(time, Opts, local)). write_file_info(Port, File, Info, Opts) when is_port(Port) -> - write_file_info_int(Port, File, Info, plgv(time, Opts, local), get_dtrace_utag()). - -write_file_info(Port, File, Info, Opts, DTraceUtag) when is_port(Port) -> - write_file_info_int(Port, File, Info, plgv(time, Opts, local), DTraceUtag). + write_file_info_int(Port, File, Info, plgv(time, Opts, local)). write_file_info_int(Port, File, #file_info{mode=Mode, @@ -907,8 +784,7 @@ write_file_info_int(Port, File, atime=Atime0, mtime=Mtime0, ctime=Ctime0}, - TimeType, - DTraceUtag) -> + TimeType) -> % Atime and/or Mtime might be undefined % - use localtime() for atime, if atime is undefined @@ -927,13 +803,12 @@ write_file_info_int(Port, File, int_to_int64bytes(to_seconds(Atime, TimeType)), int_to_int64bytes(to_seconds(Mtime, TimeType)), int_to_int64bytes(to_seconds(Ctime, TimeType)), - pathname(File), - enc_utag(DTraceUtag) - ]) + pathname(File)]) catch error:_ -> {error, badarg} end. + file_info_validate_atime(Atime, _) when Atime =/= undefined -> Atime; file_info_validate_atime(undefined, local) -> erlang:localtime(); file_info_validate_atime(undefined, universal) -> erlang:universaltime(); @@ -945,72 +820,63 @@ file_info_validate_mtime(Mtime, _) -> Mtime. file_info_validate_ctime(undefined, Mtime) -> Mtime; file_info_validate_ctime(Ctime, _) -> Ctime. -%% make_link/{2,3,4} +%% make_link/{2,3} make_link(Old, New) -> - make_link_int({?DRV, [binary]}, Old, New, get_dtrace_utag()). + make_link_int({?DRV, [binary]}, Old, New). make_link(Port, Old, New) when is_port(Port) -> - make_link_int(Port, Old, New, get_dtrace_utag()). + make_link_int(Port, Old, New). -make_link(Port, Old, New, DTraceUtag) when is_port(Port) -> - make_link_int(Port, Old, New, DTraceUtag). +make_link_int(Port, Old, New) -> + drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New)]). -make_link_int(Port, Old, New, DTraceUtag) -> - drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New), - enc_utag(DTraceUtag)]). - -%% make_symlink/{2,3,4} +%% make_symlink/{2,3} make_symlink(Old, New) -> - make_symlink_int({?DRV, [binary]}, Old, New, get_dtrace_utag()). + make_symlink_int({?DRV, [binary]}, Old, New). make_symlink(Port, Old, New) when is_port(Port) -> - make_symlink_int(Port, Old, New, get_dtrace_utag()). - -make_symlink(Port, Old, New, DTraceUtag) when is_port(Port) -> - make_symlink_int(Port, Old, New, DTraceUtag). + make_symlink_int(Port, Old, New). -make_symlink_int(Port, Old, New, DTraceUtag) -> - drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New), - enc_utag(DTraceUtag)]). +make_symlink_int(Port, Old, New) -> + drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New)]). -%% read_link/{1,3} +%% read_link/{2,3} read_link(Link) -> - read_link_int({?DRV, [binary]}, Link, get_dtrace_utag()). + read_link_int({?DRV, [binary]}, Link). -read_link(Port, Link, DTraceUtag) when is_port(Port) -> - read_link_int(Port, Link, DTraceUtag). +read_link(Port, Link) when is_port(Port) -> + read_link_int(Port, Link). -read_link_int(Port, Link, DTraceUtag) -> - drv_command(Port, [?FILE_READLINK, pathname(Link), enc_utag(DTraceUtag)]). +read_link_int(Port, Link) -> + drv_command(Port, [?FILE_READLINK, pathname(Link)]). -%% read_link_info/{1,2,3,4} +%% read_link_info/{2,3} read_link_info(Link) -> - read_link_info_int({?DRV, [binary]}, Link, local, get_dtrace_utag()). + read_link_info_int({?DRV, [binary]}, Link, local). read_link_info(Port, Link) when is_port(Port) -> - read_link_info_int(Port, Link, local, get_dtrace_utag()); + read_link_info_int(Port, Link, local); + read_link_info(Link, Opts) -> - read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local), get_dtrace_utag()). + read_link_info_int({?DRV, [binary]}, Link, plgv(time, Opts, local)). read_link_info(Port, Link, Opts) when is_port(Port) -> - read_link_info_int(Port, Link, plgv(time, Opts, local), get_dtrace_utag()). + read_link_info_int(Port, Link, plgv(time, Opts, local)). -read_link_info(Port, Link, Opts, DTraceUtag) when is_port(Port) -> - read_link_info_int(Port, Link, plgv(time, Opts, local), DTraceUtag). -read_link_info_int(Port, Link, TimeType, DTraceUtag) -> +read_link_info_int(Port, Link, TimeType) -> try - case drv_command(Port, [?FILE_LSTAT, pathname(Link), enc_utag(DTraceUtag)]) of + case drv_command(Port, [?FILE_LSTAT, pathname(Link)]) of {ok, FI} -> {ok, FI#file_info{ ctime = from_seconds(FI#file_info.ctime, TimeType), mtime = from_seconds(FI#file_info.mtime, TimeType), @@ -1022,16 +888,16 @@ read_link_info_int(Port, Link, TimeType, DTraceUtag) -> error:_ -> {error, badarg} end. -%% list_dir/{1,3} +%% list_dir/{1,2} list_dir(Dir) -> - list_dir_int({?DRV, [binary]}, Dir, get_dtrace_utag()). + list_dir_int({?DRV, [binary]}, Dir). -list_dir(Port, Dir, DTraceUtag) when is_port(Port) -> - list_dir_int(Port, Dir, DTraceUtag). +list_dir(Port, Dir) when is_port(Port) -> + list_dir_int(Port, Dir). -list_dir_int(Port, Dir, DTraceUtag) -> - drv_command(Port, [?FILE_READDIR, pathname(Dir), enc_utag(DTraceUtag)], []). +list_dir_int(Port, Dir) -> + drv_command(Port, [?FILE_READDIR, pathname(Dir)], []). @@ -1057,12 +923,17 @@ drv_open(Driver, Portopts) -> %% Closes a port in a safe way. Returns ok. drv_close(Port) -> - try erlang:port_close(Port) catch error:_ -> ok end, - receive %% Ugly workaround in case the caller==owner traps exits - {'EXIT', Port, _Reason} -> - ok - after 0 -> - ok + Save = erlang:spread_utag(false), + try + try erlang:port_close(Port) catch error:_ -> ok end, + receive %% Ugly workaround in case the caller==owner traps exits + {'EXIT', Port, _Reason} -> + ok + after 0 -> + ok + end + after + erlang:restore_utag(Save) end. @@ -1072,9 +943,6 @@ drv_close(Port) -> %% then closed after the result has been received. %% Returns {ok, Result} or {error, Reason}. -drv_command_raw(Port, Command) -> - drv_command(Port, Command, false, undefined). - drv_command(Port, Command) -> drv_command(Port, Command, undefined). @@ -1090,7 +958,8 @@ drv_command(Port, Command, R) -> end. drv_command(Port, Command, Validated, R) when is_port(Port) -> - try erlang:port_command(Port, Command) of + Save = erlang:spread_utag(false), + try erlang:port_command(Port, erlang:append_vm_utag_data(Command)) of true -> drv_get_response(Port, R) catch @@ -1109,6 +978,8 @@ drv_command(Port, Command, Validated, R) when is_port(Port) -> end; error:Reason -> {error, Reason} + after + erlang:restore_utag(Save) end; drv_command({Driver, Portopts}, Command, Validated, R) -> case drv_open(Driver, Portopts) of @@ -1119,6 +990,30 @@ drv_command({Driver, Portopts}, Command, Validated, R) -> Error -> Error end. +drv_command_nt(Port, Command, Validated, R) when is_port(Port) -> + Save = erlang:spread_utag(false), + try erlang:port_command(Port, Command) of + true -> + drv_get_response(Port, R) + catch + %% If the Command is valid, knowing that the port is a port, + %% a badarg error must mean it is a dead port, that is: + %% a currently invalid filehandle, -> einval, not badarg. + error:badarg when Validated -> + {error, einval}; + error:badarg -> + try erlang:iolist_size(Command) of + _ -> % Valid + {error, einval} + catch + error:_ -> + {error, badarg} + end; + error:Reason -> + {error, Reason} + after + erlang:restore_utag(Save) + end. @@ -1469,6 +1364,7 @@ reverse(L, T) -> lists:reverse(L, T). pathname(File) -> (catch prim_file:internal_name2native(File)). + %% proplist:get_value/3 plgv(K, [{K, V}|_], _) -> V; plgv(K, [_|KVs], D) -> plgv(K, KVs, D); @@ -1492,16 +1388,3 @@ to_seconds({_,_} = Datetime, universal) -> erlang:universaltime_to_posixtime(Datetime); to_seconds({_,_} = Datetime, local) -> erlang:universaltime_to_posixtime(erlang:localtime_to_universaltime(Datetime)). - -get_dtrace_utag() -> - %% We cannot call dtrace:get_utag() because this is prim_file.erl. - %% We must reimplement it here. - case get('_dtrace_utag_@_@') of - undefined -> - <<>>; - X -> - X - end. - -enc_utag(UTag) -> - [UTag, 0]. diff --git a/lib/dtrace/c_src/Makefile.in b/lib/dtrace/c_src/Makefile.in index 831ce5ce75..4d5f59a63d 100644 --- a/lib/dtrace/c_src/Makefile.in +++ b/lib/dtrace/c_src/Makefile.in @@ -76,7 +76,7 @@ before_DTrace_OBJS = $(OBJDIR)/dtrace$(TYPEMARKER).o ## NIF_MAKEFILE = $(PRIVDIR)/Makefile # Higher-level makefiles says that we can only compile on UNIX flavors -NIF_LIB = $(LIBDIR)/dtrace$(TYPEMARKER).so +NIF_LIB = $(LIBDIR)/dtrace$(TYPEMARKER).@DED_EXT@ ifeq ($(HOST_OS),) HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess) @@ -121,14 +121,14 @@ $(OBJDIR)/%$(TYPEMARKER).o: %.c $(DTRACE_USER_HEADER) $(INSTALL_DIR) $(OBJDIR) $(CC) -c -o $@ $(ALL_CFLAGS) $< -$(LIBDIR)/dtrace$(TYPEMARKER).so: $(OBJS) +$(NIF_LIB): $(OBJS) $(INSTALL_DIR) $(LIBDIR) $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) clean: - rm -f $(LIBDIR)/dtrace.so - rm -f $(LIBDIR)/dtrace.debug.so - rm -f $(LIBDIR)/dtrace.valgrind.so + rm -f $(LIBDIR)/dtrace.@DED_EXT@ + rm -f $(LIBDIR)/dtrace.debug.@DED_EXT@ + rm -f $(LIBDIR)/dtrace.valgrind.@DED_EXT@ rm -f $(OBJDIR)/dtrace.o rm -f $(OBJDIR)/dtrace.debug.o rm -f $(OBJDIR)/dtrace.valgrind.o diff --git a/lib/dtrace/examples/efile_drv.d b/lib/dtrace/examples/efile_drv.d index c9c8080dba..085995ce58 100644 --- a/lib/dtrace/examples/efile_drv.d +++ b/lib/dtrace/examples/efile_drv.d @@ -71,7 +71,8 @@ erlang*:::efile_drv-entry arg4 == NULL ? "" : copyinstr(arg4), arg5 == NULL ? "" : copyinstr(arg5), arg6, arg7, /* NOTE: port name in args[10] is experimental */ - copyinstr((user_addr_t) args[10])) + (args[10] == NULL) ? + "?" : copyinstr((user_addr_t) args[10])); } erlang*:::efile_drv-int* diff --git a/lib/dtrace/src/dtrace.erl b/lib/dtrace/src/dtrace.erl index 6951c03215..71a1a3480e 100644 --- a/lib/dtrace/src/dtrace.erl +++ b/lib/dtrace/src/dtrace.erl @@ -35,12 +35,10 @@ %%% then the driver will ignore the user's input and use a default %%% value of 0 or NULL, respectively. --define(DTRACE_UT_KEY, '_dtrace_utag_@_@'). % Match prim_file:get_dtrace_utag()! - -export([init/0, available/0, user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). --export([put_utag/1, get_utag/0]). +-export([put_utag/1, get_utag/0, get_utag_data/0, spread_utag/1, restore_utag/1]). -export([scaff/0]). % Development only -export([user_trace_i4s4/9]). % Know what you're doing! @@ -188,24 +186,29 @@ user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> false end. --spec put_utag(undefined | iolist()) -> ok. - -put_utag(undefined) -> - put_utag(<<>>); -put_utag(T) when is_binary(T) -> - put(?DTRACE_UT_KEY, T), - ok; -put_utag(T) when is_list(T) -> - put(?DTRACE_UT_KEY, list_to_binary(T)), - ok. +-spec put_utag(undefined | iodata()) -> binary() | undefined. +put_utag(Data) -> + erlang:put_utag(unicode:characters_to_binary(Data)). +-spec get_utag() -> binary() | undefined. get_utag() -> - case get(?DTRACE_UT_KEY) of - undefined -> - <<>>; - X -> - X - end. + erlang:get_utag(). + +-spec get_utag_data() -> binary() | undefined. +%% Gets utag if set, otherwise the spread utag data from last incoming message +get_utag_data() -> + erlang:get_utag_data(). + +-spec spread_utag(boolean()) -> true | {non_neg_integer(), binary() | []}. +%% Makes the utag behave as a sequential trace token, will spread with messages to be picked up by someone using +%% get_utag_data or get_drv_utag_data. +spread_utag(B) -> + erlang:spread_utag(B). + +-spec restore_utag(true | {non_neg_integer(), binary() | []}) -> true. +restore_utag(T) -> + erlang:restore_utag(T). + %% Scaffolding to write tedious code: quick brute force and not 100% correct. diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index a7ce17eb53..260f216725 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -614,6 +614,10 @@ type(erlang, adler32_combine, 3, Xs) -> type(erlang, append, 2, Xs) -> type(erlang, '++', 2, Xs); % alias type(erlang, append_element, 2, Xs) -> strict(arg_types(erlang, append_element, 2), Xs, fun (_) -> t_tuple() end); +type(erlang, append_vm_utag_data, 1, Xs) -> + strict(arg_types(erlang, append_vm_utag_data, 1), + Xs, + fun(_) -> t_iodata() end); type(erlang, apply, 2, Xs) -> Fun = fun ([X, _Y]) -> case t_is_fun(X) of @@ -800,6 +804,10 @@ type(erlang, get_module_info, 2, Xs) -> type(erlang, get_stacktrace, 0, _) -> t_list(t_tuple([t_atom(), t_atom(), t_sup([t_arity(), t_list()]), t_list()])); +type(erlang, get_utag, 0, _) -> + t_sup(t_binary(), t_atom('undefined')); +type(erlang, get_utag_data, 0, _) -> + t_sup(t_binary(), t_atom('undefined')); type(erlang, group_leader, 0, _) -> t_pid(); type(erlang, group_leader, 2, Xs) -> strict(arg_types(erlang, group_leader, 2), Xs, @@ -1186,6 +1194,10 @@ type(erlang, port_set_data, 2, Xs) -> strict(arg_types(erlang, port_set_data, 2), Xs, fun (_) -> t_atom('true') end); type(erlang, pre_loaded, 0, _) -> t_list(t_atom()); +type(erlang, prepend_vm_utag_data, 1, Xs) -> + strict(arg_types(erlang, prepend_vm_utag_data, 1), + Xs, + fun(_) -> t_iodata() end); type(erlang, process_display, 2, _) -> t_atom('true'); type(erlang, process_flag, 2, Xs) -> T_process_flag_returns = t_sup([t_boolean(), t_atom(), t_non_neg_integer()]), @@ -1303,6 +1315,9 @@ type(erlang, purge_module, 1, Xs) -> fun (_) -> t_atom('true') end); type(erlang, put, 2, Xs) -> strict(arg_types(erlang, put, 2), Xs, fun (_) -> t_any() end); +type(erlang, put_utag, 1, Xs) -> + strict(arg_types(erlang, put_utag, 1), Xs, + fun(_) -> t_sup(t_binary(), t_atom('undefined')) end); type(erlang, raise, 3, _) -> t_none(); type(erlang, read_timer, 1, Xs) -> strict(arg_types(erlang, read_timer, 1), Xs, @@ -1312,6 +1327,8 @@ type(erlang, ref_to_list, 1, Xs) -> type(erlang, register, 2, Xs) -> strict(arg_types(erlang, register, 2), Xs, fun (_) -> t_atom('true') end); type(erlang, registered, 0, _) -> t_list(t_atom()); +type(erlang, restore_utag, 1, Xs) -> + strict(arg_types(erlang, restore_utag, 1), Xs, fun(_) -> t_atom('true') end); type(erlang, resume_process, 1, Xs) -> strict(arg_types(erlang, resume_process, 1), Xs, fun (_) -> t_any() end); %% TODO: overapproximation -- fix this @@ -1426,6 +1443,10 @@ type(erlang, spawn_opt, 4, Xs) -> type(erlang, split_binary, 2, Xs) -> strict(arg_types(erlang, split_binary, 2), Xs, fun (_) -> t_tuple([t_binary(), t_binary()]) end); +type(erlang, spread_utag, 1, Xs) -> + strict(arg_types(erlang, spread_utag, 1), Xs, + fun(_) -> t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), + t_atom('true')) end); type(erlang, start_timer, 3, Xs) -> strict(arg_types(erlang, start_timer, 3), Xs, fun (_) -> t_reference() end); type(erlang, statistics, 1, Xs) -> @@ -3422,6 +3443,8 @@ arg_types(erlang, append, 2) -> arg_types(erlang, '++', 2); arg_types(erlang, append_element, 2) -> [t_tuple(), t_any()]; +arg_types(erlang, append_vm_utag_data, 1) -> + [t_iodata()]; arg_types(erlang, apply, 2) -> [t_sup(t_tuple([t_module(), t_atom()]), @@ -3547,6 +3570,10 @@ arg_types(erlang, get_module_info, 1) -> [t_atom()]; arg_types(erlang, get_module_info, 2) -> [t_atom(), t_module_info_2()]; +arg_types(erlang, get_utag, 0) -> + []; +arg_types(erlang, get_utag_data, 0) -> + []; arg_types(erlang, group_leader, 0) -> []; arg_types(erlang, group_leader, 2) -> @@ -3763,6 +3790,8 @@ arg_types(erlang, port_set_data, 2) -> [t_sup(t_port(), t_atom()), t_any()]; arg_types(erlang, pre_loaded, 0) -> []; +arg_types(erlang, prepend_vm_utag_data, 1) -> + [t_iodata()]; arg_types(erlang, process_display, 2) -> [t_pid(), t_atom('backtrace')]; arg_types(erlang, process_flag, 2) -> @@ -3789,6 +3818,8 @@ arg_types(erlang, purge_module, 1) -> [t_atom()]; arg_types(erlang, put, 2) -> [t_any(), t_any()]; +arg_types(erlang, put_utag, 1) -> + [t_sup(t_binary(), t_atom('undefined'))]; arg_types(erlang, raise, 3) -> OldStyleType = t_list(t_tuple([t_atom(), t_atom(), t_sup([t_arity(), t_list()])])), @@ -3802,6 +3833,8 @@ arg_types(erlang, register, 2) -> [t_atom(), t_sup(t_port(), t_pid())]; arg_types(erlang, registered, 0) -> []; +arg_types(erlang, restore_utag, 1) -> + [t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), t_atom('true'))]; arg_types(erlang, resume_process, 1) -> [t_pid()]; % intended for debugging only arg_types(erlang, round, 1) -> @@ -3860,6 +3893,8 @@ arg_types(erlang, spawn_opt, 4) -> [t_node(), t_atom(), t_list(), t_list(t_spawn_options())]; arg_types(erlang, split_binary, 2) -> [t_binary(), t_non_neg_integer()]; +arg_types(erlang, spread_utag, 1) -> + [t_boolean()]; arg_types(erlang, start_timer, 3) -> [t_non_neg_integer(), t_sup(t_pid(), t_atom()), t_any()]; arg_types(erlang, statistics, 1) -> diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index aecb9f7923..3a618976f5 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -39,7 +39,7 @@ -export([ipread_s32bu_p32bu/3]). %% Generic file contents. -export([open/2, close/1, advise/4, - read/2, write/2, + read/2, write/2, pread/2, pread/3, pwrite/2, pwrite/3, read_line/1, position/2, truncate/1, datasync/1, sync/1, @@ -62,7 +62,7 @@ %% Internal export to prim_file and ram_file until they implement %% an efficient copy themselves. --export([copy_opened/4]). +-export([copy_opened/3]). -export([ipread_s32bu_p32bu_int/3]). @@ -166,7 +166,7 @@ pid2name(Pid) when is_pid(Pid) -> Reason :: posix(). get_cwd() -> - call(get_cwd, [no_drive, get_dtrace_utag()]). + call(get_cwd, []). -spec get_cwd(Drive) -> {ok, Dir} | {error, Reason} when Drive :: string(), @@ -174,21 +174,21 @@ get_cwd() -> Reason :: posix() | badarg. get_cwd(Drive) -> - check_and_call(get_cwd, [file_name(Drive), get_dtrace_utag()]). + check_and_call(get_cwd, [file_name(Drive)]). -spec set_cwd(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. set_cwd(Dirname) -> - check_and_call(set_cwd, [file_name(Dirname), get_dtrace_utag()]). + check_and_call(set_cwd, [file_name(Dirname)]). -spec delete(Filename) -> ok | {error, Reason} when Filename :: name(), Reason :: posix() | badarg. delete(Name) -> - check_and_call(delete, [file_name(Name), get_dtrace_utag()]). + check_and_call(delete, [file_name(Name)]). -spec rename(Source, Destination) -> ok | {error, Reason} when Source :: name(), @@ -196,21 +196,21 @@ delete(Name) -> Reason :: posix() | badarg. rename(From, To) -> - check_and_call(rename, [file_name(From), file_name(To), get_dtrace_utag()]). + check_and_call(rename, [file_name(From), file_name(To)]). -spec make_dir(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. make_dir(Name) -> - check_and_call(make_dir, [file_name(Name), get_dtrace_utag()]). + check_and_call(make_dir, [file_name(Name)]). -spec del_dir(Dir) -> ok | {error, Reason} when Dir :: name(), Reason :: posix() | badarg. del_dir(Name) -> - check_and_call(del_dir, [file_name(Name), get_dtrace_utag()]). + check_and_call(del_dir, [file_name(Name)]). -spec read_file_info(Filename) -> {ok, FileInfo} | {error, Reason} when Filename :: name(), @@ -218,7 +218,7 @@ del_dir(Name) -> Reason :: posix() | badarg. read_file_info(Name) -> - check_and_call(read_file_info, [file_name(Name), get_dtrace_utag()]). + check_and_call(read_file_info, [file_name(Name)]). -spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when Filename :: name(), @@ -227,12 +227,12 @@ read_file_info(Name) -> Reason :: posix() | badarg. read_file_info(Name, Opts) when is_list(Opts) -> - check_and_call(read_file_info, [file_name(Name), Opts, get_dtrace_utag()]). + check_and_call(read_file_info, [file_name(Name), Opts]). -spec altname(Name :: name()) -> any(). altname(Name) -> - check_and_call(altname, [file_name(Name), get_dtrace_utag()]). + check_and_call(altname, [file_name(Name)]). -spec read_link_info(Name) -> {ok, FileInfo} | {error, Reason} when Name :: name(), @@ -240,7 +240,7 @@ altname(Name) -> Reason :: posix() | badarg. read_link_info(Name) -> - check_and_call(read_link_info, [file_name(Name), get_dtrace_utag()]). + check_and_call(read_link_info, [file_name(Name)]). -spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when Name :: name(), @@ -249,7 +249,7 @@ read_link_info(Name) -> Reason :: posix() | badarg. read_link_info(Name, Opts) when is_list(Opts) -> - check_and_call(read_link_info, [file_name(Name),Opts, get_dtrace_utag()]). + check_and_call(read_link_info, [file_name(Name),Opts]). -spec read_link(Name) -> {ok, Filename} | {error, Reason} when @@ -258,7 +258,7 @@ read_link_info(Name, Opts) when is_list(Opts) -> Reason :: posix() | badarg. read_link(Name) -> - check_and_call(read_link, [file_name(Name), get_dtrace_utag()]). + check_and_call(read_link, [file_name(Name)]). -spec write_file_info(Filename, FileInfo) -> ok | {error, Reason} when Filename :: name(), @@ -266,7 +266,7 @@ read_link(Name) -> Reason :: posix() | badarg. write_file_info(Name, Info = #file_info{}) -> - check_and_call(write_file_info, [file_name(Name), Info, get_dtrace_utag()]). + check_and_call(write_file_info, [file_name(Name), Info]). -spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when Filename :: name(), @@ -275,7 +275,7 @@ write_file_info(Name, Info = #file_info{}) -> Reason :: posix() | badarg. write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> - check_and_call(write_file_info, [file_name(Name), Info, Opts, get_dtrace_utag()]). + check_and_call(write_file_info, [file_name(Name), Info, Opts]). -spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when Dir :: name(), @@ -283,7 +283,7 @@ write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> Reason :: posix() | badarg. list_dir(Name) -> - check_and_call(list_dir, [file_name(Name), get_dtrace_utag()]). + check_and_call(list_dir, [file_name(Name)]). -spec read_file(Filename) -> {ok, Binary} | {error, Reason} when Filename :: name(), @@ -291,7 +291,7 @@ list_dir(Name) -> Reason :: posix() | badarg | terminated | system_limit. read_file(Name) -> - check_and_call(read_file, [file_name(Name), get_dtrace_utag()]). + check_and_call(read_file, [file_name(Name)]). -spec make_link(Existing, New) -> ok | {error, Reason} when Existing :: name(), @@ -299,7 +299,7 @@ read_file(Name) -> Reason :: posix() | badarg. make_link(Old, New) -> - check_and_call(make_link, [file_name(Old), file_name(New), get_dtrace_utag()]). + check_and_call(make_link, [file_name(Old), file_name(New)]). -spec make_symlink(Existing, New) -> ok | {error, Reason} when Existing :: name(), @@ -307,7 +307,7 @@ make_link(Old, New) -> Reason :: posix() | badarg. make_symlink(Old, New) -> - check_and_call(make_symlink, [file_name(Old), file_name(New), get_dtrace_utag()]). + check_and_call(make_symlink, [file_name(Old), file_name(New)]). -spec write_file(Filename, Bytes) -> ok | {error, Reason} when Filename :: name(), @@ -315,7 +315,7 @@ make_symlink(Old, New) -> Reason :: posix() | badarg | terminated | system_limit. write_file(Name, Bin) -> - check_and_call(write_file, [file_name(Name), make_binary(Bin), get_dtrace_utag()]). + check_and_call(write_file, [file_name(Name), make_binary(Bin)]). %% This whole operation should be moved to the file_server and prim_file %% when it is time to change file server protocol again. @@ -367,7 +367,7 @@ raw_write_file_info(Name, #file_info{} = Info) -> case check_args(Args) of ok -> [FileName] = Args, - ?PRIM_FILE:write_file_info(FileName, Info, get_dtrace_utag()); + ?PRIM_FILE:write_file_info(FileName, Info); Error -> Error end. @@ -400,7 +400,7 @@ open(Item, ModeList) when is_list(ModeList) -> [FileName | _] = Args, %% We rely on the returned Handle (in {ok, Handle}) %% being a pid() or a #file_descriptor{} - ?PRIM_FILE:open(FileName, ModeList, get_dtrace_utag()); + ?PRIM_FILE:open(FileName, ModeList); Error -> Error end @@ -421,7 +421,7 @@ open(Item, ModeList) when is_list(ModeList) -> case check_args(Args) of ok -> [FileName | _] = Args, - call(open, [FileName, ModeList, get_dtrace_utag()]); + call(open, [FileName, ModeList]); Error -> Error end @@ -466,10 +466,7 @@ close(_) -> advise(File, Offset, Length, Advise) when is_pid(File) -> R = file_request(File, {advise, Offset, Length, Advise}), wait_file_reply(File, R); -advise(#file_descriptor{module = prim_file = Module} = Handle, Offset, Length, Advise) -> - Module:advise(Handle, Offset, Length, Advise, get_dtrace_utag()); advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:advise(Handle, Offset, Length, Advise); advise(_, _, _, _) -> {error, badarg}. @@ -480,25 +477,17 @@ advise(_, _, _, _) -> Data :: string() | binary(), Reason :: posix() | badarg | terminated. -read(File, Sz) -> - read(File, Sz, get_dtrace_utag()). - -read(File, Sz, _DTraceUtag) - when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 -> +read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 -> case io:request(File, {get_chars, '', Sz}) of Data when is_list(Data); is_binary(Data) -> {ok, Data}; Other -> Other end; -read(#file_descriptor{module = prim_file = Module} = Handle, Sz, DTraceUtag) - when is_integer(Sz), Sz >= 0 -> - Module:read(Handle, Sz, DTraceUtag); -read(#file_descriptor{module = Module} = Handle, Sz, _DTraceUtag) +read(#file_descriptor{module = Module} = Handle, Sz) when is_integer(Sz), Sz >= 0 -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:read(Handle, Sz); -read(_, _, _) -> +read(_, _) -> {error, badarg}. -spec read_line(IoDevice) -> {ok, Data} | eof | {error, Reason} when @@ -513,10 +502,7 @@ read_line(File) when (is_pid(File) orelse is_atom(File)) -> Other -> Other end; -read_line(#file_descriptor{module = prim_file = Module} = Handle) -> - Module:read_line(Handle, get_dtrace_utag()); read_line(#file_descriptor{module = Module} = Handle) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:read_line(Handle); read_line(_) -> {error, badarg}. @@ -530,10 +516,7 @@ read_line(_) -> pread(File, L) when is_pid(File), is_list(L) -> pread_int(File, L, []); -pread(#file_descriptor{module = prim_file = Module} = Handle, L) when is_list(L) -> - Module:pread(Handle, L, get_dtrace_utag()); pread(#file_descriptor{module = Module} = Handle, L) when is_list(L) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pread(Handle, L); pread(_, _) -> {error, badarg}. @@ -565,7 +548,6 @@ pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 -> wait_file_reply(File, R); pread(#file_descriptor{module = Module} = Handle, Offs, Sz) when is_integer(Sz), Sz >= 0 -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pread(Handle, Offs, Sz); pread(_, _, _) -> {error, badarg}. @@ -575,22 +557,16 @@ pread(_, _, _) -> Bytes :: iodata(), Reason :: posix() | badarg | terminated. -write(File, Bytes) -> - write(File, Bytes, get_dtrace_utag()). - -write(File, Bytes, _DTraceUtag) when (is_pid(File) orelse is_atom(File)) -> +write(File, Bytes) when (is_pid(File) orelse is_atom(File)) -> case make_binary(Bytes) of Bin when is_binary(Bin) -> io:request(File, {put_chars,Bin}); Error -> Error end; -write(#file_descriptor{module = prim_file = Module} = Handle, Bytes, DTraceUtag) -> - Module:write(Handle, Bytes, DTraceUtag); -write(#file_descriptor{module = Module} = Handle, Bytes, _DTraceUtag) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. +write(#file_descriptor{module = Module} = Handle, Bytes) -> Module:write(Handle, Bytes); -write(_, _, _) -> +write(_, _) -> {error, badarg}. -spec pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}} when @@ -601,10 +577,7 @@ write(_, _, _) -> pwrite(File, L) when is_pid(File), is_list(L) -> pwrite_int(File, L, 0); -pwrite(#file_descriptor{module = prim_file = Module} = Handle, L) when is_list(L) -> - Module:pwrite(Handle, L, get_dtrace_utag()); pwrite(#file_descriptor{module = Module} = Handle, L) when is_list(L) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pwrite(Handle, L); pwrite(_, _) -> {error, badarg}. @@ -631,7 +604,6 @@ pwrite(File, At, Bytes) when is_pid(File) -> R = file_request(File, {pwrite, At, Bytes}), wait_file_reply(File, R); pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:pwrite(Handle, Offs, Bytes); pwrite(_, _, _) -> {error, badarg}. @@ -643,10 +615,7 @@ pwrite(_, _, _) -> datasync(File) when is_pid(File) -> R = file_request(File, datasync), wait_file_reply(File, R); -datasync(#file_descriptor{module = prim_file = Module} = Handle) -> - Module:datasync(Handle, get_dtrace_utag()); datasync(#file_descriptor{module = Module} = Handle) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:datasync(Handle); datasync(_) -> {error, badarg}. @@ -658,10 +627,7 @@ datasync(_) -> sync(File) when is_pid(File) -> R = file_request(File, sync), wait_file_reply(File, R); -sync(#file_descriptor{module = prim_file = Module} = Handle) -> - Module:sync(Handle, get_dtrace_utag()); sync(#file_descriptor{module = Module} = Handle) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:sync(Handle); sync(_) -> {error, badarg}. @@ -675,10 +641,7 @@ sync(_) -> position(File, At) when is_pid(File) -> R = file_request(File, {position,At}), wait_file_reply(File, R); -position(#file_descriptor{module = prim_file = Module} = Handle, At) -> - Module:position(Handle, At, get_dtrace_utag()); position(#file_descriptor{module = Module} = Handle, At) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:position(Handle, At); position(_, _) -> {error, badarg}. @@ -690,10 +653,7 @@ position(_, _) -> truncate(File) when is_pid(File) -> R = file_request(File, truncate), wait_file_reply(File, R); -truncate(#file_descriptor{module = prim_file = Module} = Handle) -> - Module:truncate(Handle, get_dtrace_utag()); truncate(#file_descriptor{module = Module} = Handle) -> - %% DTrace TODO: ram_file and other file drivers not yet DTrace'ified. Module:truncate(Handle); truncate(_) -> {error, badarg}. @@ -734,7 +694,7 @@ copy_int(Source, Dest, Length) when is_pid(Source), is_pid(Dest); is_pid(Source), is_record(Dest, file_descriptor); is_record(Source, file_descriptor), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, get_dtrace_utag()); + copy_opened_int(Source, Dest, Length, 0); %% Copy between open raw files, both handled by the same module copy_int(#file_descriptor{module = Module} = Source, #file_descriptor{module = Module} = Dest, @@ -743,14 +703,14 @@ copy_int(#file_descriptor{module = Module} = Source, %% Copy between open raw files of different modules copy_int(#file_descriptor{} = Source, #file_descriptor{} = Dest, Length) -> - copy_opened_int(Source, Dest, Length, get_dtrace_utag()); + copy_opened_int(Source, Dest, Length, 0); %% Copy between filenames, let the server do the copy copy_int({SourceName, SourceOpts}, {DestName, DestOpts}, Length) when is_list(SourceOpts), is_list(DestOpts) -> check_and_call(copy, [file_name(SourceName), SourceOpts, file_name(DestName), DestOpts, - Length, get_dtrace_utag()]); + Length]); %% Filename -> open file; must open Source and do client copy copy_int({SourceName, SourceOpts}, Dest, Length) when is_list(SourceOpts), is_pid(Dest); @@ -761,8 +721,7 @@ copy_int({SourceName, SourceOpts}, Dest, Length) Source -> case open(Source, [read | SourceOpts]) of {ok, Handle} -> - Result = copy_opened_int(Handle, Dest, Length, - get_dtrace_utag()), + Result = copy_opened_int(Handle, Dest, Length, 0), close(Handle), Result; {error, _} = Error -> @@ -779,8 +738,7 @@ copy_int(Source, {DestName, DestOpts}, Length) Dest -> case open(Dest, [write | DestOpts]) of {ok, Handle} -> - Result = copy_opened_int(Source, Handle, Length, - get_dtrace_utag()), + Result = copy_opened_int(Source, Handle, Length, 0), close(Handle), Result; {error, _} = Error -> @@ -815,46 +773,45 @@ copy_int(Source, Dest, Length) -> -copy_opened(Source, Dest, Length, DTraceUtag) +copy_opened(Source, Dest, Length) when is_integer(Length), Length >= 0; is_atom(Length) -> - copy_opened_int(Source, Dest, Length, DTraceUtag); -copy_opened(_, _, _, _) -> + copy_opened_int(Source, Dest, Length); +copy_opened(_, _, _) -> {error, badarg}. %% Here we know that Length is either an atom or an integer >= 0 %% (by the way, atoms > integers) -copy_opened_int(Source, Dest, Length, DTraceUtag) +copy_opened_int(Source, Dest, Length) when is_pid(Source), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, 0, DTraceUtag); -copy_opened_int(Source, Dest, Length, DTraceUtag) + copy_opened_int(Source, Dest, Length, 0); +copy_opened_int(Source, Dest, Length) when is_pid(Source), is_record(Dest, file_descriptor) -> - copy_opened_int(Source, Dest, Length, 0, DTraceUtag); -copy_opened_int(Source, Dest, Length, DTraceUtag) + copy_opened_int(Source, Dest, Length, 0); +copy_opened_int(Source, Dest, Length) when is_record(Source, file_descriptor), is_pid(Dest) -> - copy_opened_int(Source, Dest, Length, 0, DTraceUtag); -copy_opened_int(Source, Dest, Length, DTraceUtag) + copy_opened_int(Source, Dest, Length, 0); +copy_opened_int(Source, Dest, Length) when is_record(Source, file_descriptor), is_record(Dest, file_descriptor) -> - copy_opened_int(Source, Dest, Length, 0, DTraceUtag); -copy_opened_int(_, _, _, _) -> + copy_opened_int(Source, Dest, Length, 0); +copy_opened_int(_, _, _) -> {error, badarg}. %% Here we know that Source and Dest are handles to open files, Length is %% as above, and Copied is an integer >= 0 %% Copy loop in client process -copy_opened_int(_, _, Length, Copied, _DTraceUtag) - when Length =< 0 -> % atom() > integer() +copy_opened_int(_, _, Length, Copied) when Length =< 0 -> % atom() > integer() {ok, Copied}; -copy_opened_int(Source, Dest, Length, Copied, DTraceUtag) -> +copy_opened_int(Source, Dest, Length, Copied) -> N = if Length > 65536 -> 65536; true -> Length end, % atom() > integer() ! - case read(Source, N, DTraceUtag) of + case read(Source, N) of {ok, Data} -> M = if is_binary(Data) -> byte_size(Data); is_list(Data) -> length(Data) end, - case write(Dest, Data, DTraceUtag) of + case write(Dest, Data) of ok -> if M < N -> %% Got less than asked for - must be end of file @@ -864,8 +821,7 @@ copy_opened_int(Source, Dest, Length, Copied, DTraceUtag) -> NewLength = if is_atom(Length) -> Length; true -> Length-M end, - copy_opened_int(Source, Dest, NewLength, Copied+M, - DTraceUtag) + copy_opened_int(Source, Dest, NewLength, Copied+M) end; {error, _} = Error -> Error @@ -885,8 +841,6 @@ copy_opened_int(Source, Dest, Length, Copied, DTraceUtag) -> ipread_s32bu_p32bu(File, Pos, MaxSize) when is_pid(File) -> ipread_s32bu_p32bu_int(File, Pos, MaxSize); -ipread_s32bu_p32bu(#file_descriptor{module = prim_file = Module} = Handle, Pos, MaxSize) -> - Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize, get_dtrace_utag()); ipread_s32bu_p32bu(#file_descriptor{module = Module} = Handle, Pos, MaxSize) -> Module:ipread_s32bu_p32bu(Handle, Pos, MaxSize); ipread_s32bu_p32bu(_, _, _) -> @@ -1467,7 +1421,10 @@ call(Command, Args) when is_list(Args) -> check_and_call(Command, Args) when is_list(Args) -> case check_args(Args) of ok -> - call(Command, Args); + X = erlang:spread_utag(true), + Y = call(Command, Args), + erlang:restore_utag(X), + Y; Error -> Error end. @@ -1502,6 +1459,3 @@ wait_file_reply(From, Ref) -> %% receive {'EXIT', From, _} -> ok after 0 -> ok end, {error, terminated} end. - -get_dtrace_utag() -> - dtrace:get_utag(). diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index cc0343031b..14da9c1a55 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -21,7 +21,7 @@ %% A simple file server for io to one file instance per server instance. -export([format_error/1]). --export([start/4, start_link/4]). +-export([start/3, start_link/3]). -export([count_and_find/3]). @@ -43,18 +43,18 @@ format_error({_Line, Mod, Reason}) -> format_error(ErrorId) -> erl_posix_msg:message(ErrorId). -start(Owner, FileName, ModeList, DTraceUtag) +start(Owner, FileName, ModeList) when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) -> - do_start(spawn, Owner, FileName, ModeList, DTraceUtag). + do_start(spawn, Owner, FileName, ModeList). -start_link(Owner, FileName, ModeList, DTraceUtag) +start_link(Owner, FileName, ModeList) when is_pid(Owner), (is_list(FileName) orelse is_binary(FileName)), is_list(ModeList) -> - do_start(spawn_link, Owner, FileName, ModeList, DTraceUtag). + do_start(spawn_link, Owner, FileName, ModeList). %%%----------------------------------------------------------------- %%% Server starter, dispatcher and helpers -do_start(Spawn, Owner, FileName, ModeList, DTraceUtag) -> +do_start(Spawn, Owner, FileName, ModeList) -> Self = self(), Ref = make_ref(), Pid = @@ -63,12 +63,11 @@ do_start(Spawn, Owner, FileName, ModeList, DTraceUtag) -> %% process_flag(trap_exit, true), case parse_options(ModeList) of {ReadMode, UnicodeMode, Opts} -> - case ?PRIM_FILE:open(FileName, Opts, DTraceUtag) of + case ?PRIM_FILE:open(FileName, Opts) of {error, Reason} = Error -> Self ! {Ref, Error}, exit(Reason); {ok, Handle} -> - put(dtrace_utag, DTraceUtag), % TODO: API? %% XXX must I handle R6 nodes here? M = erlang:monitor(process, Owner), Self ! {Ref, ok}, diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl index 82adc45795..fc6cd823c9 100644 --- a/lib/kernel/src/file_server.erl +++ b/lib/kernel/src/file_server.erl @@ -76,7 +76,6 @@ stop() -> init([]) -> process_flag(trap_exit, true), - put(dtrace_utag, atom_to_list(?FILE_SERVER)), case ?PRIM_FILE:start() of {ok, Handle} -> ets:new(?FILE_IO_SERVER_TABLE, [named_table]), @@ -100,9 +99,9 @@ init([]) -> {'reply', 'eof' | 'ok' | {'error', term()} | {'ok', term()}, state()} | {'stop', 'normal', 'stopped', state()}. -handle_call({open, Name, ModeList, DTraceUtag}, {Pid, _Tag} = _From, Handle) +handle_call({open, Name, ModeList}, {Pid, _Tag} = _From, Handle) when is_list(ModeList) -> - Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList, DTraceUtag), + Child = ?FILE_IO_SERVER:start_link(Pid, Name, ModeList), case Child of {ok, P} when is_pid(P) -> ets:insert(?FILE_IO_SERVER_TABLE, {P, Name}); @@ -111,86 +110,87 @@ handle_call({open, Name, ModeList, DTraceUtag}, {Pid, _Tag} = _From, Handle) end, {reply, Child, Handle}; -handle_call({open, _Name, _Mode, _DTraceUtag}, _From, Handle) -> +handle_call({open, _Name, _Mode}, _From, Handle) -> {reply, {error, einval}, Handle}; -handle_call({read_file, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file(Name, DTraceUtag), Handle}; +handle_call({read_file, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file(Name), Handle}; -handle_call({write_file, Name, Bin, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file(Name, Bin, DTraceUtag), Handle}; +handle_call({write_file, Name, Bin}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file(Name, Bin), Handle}; -handle_call({set_cwd, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:set_cwd(Handle, Name, DTraceUtag), Handle}; +handle_call({set_cwd, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:set_cwd(Handle, Name), Handle}; -handle_call({delete, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:delete(Handle, Name, DTraceUtag), Handle}; +handle_call({delete, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:delete(Handle, Name), Handle}; -handle_call({rename, Fr, To, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:rename(Handle, Fr, To, DTraceUtag), Handle}; +handle_call({rename, Fr, To}, _From, Handle) -> + {reply, ?PRIM_FILE:rename(Handle, Fr, To), Handle}; -handle_call({make_dir, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:make_dir(Handle, Name, DTraceUtag), Handle}; +handle_call({make_dir, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:make_dir(Handle, Name), Handle}; -handle_call({del_dir, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:del_dir(Handle, Name, DTraceUtag), Handle}; +handle_call({del_dir, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:del_dir(Handle, Name), Handle}; -handle_call({list_dir, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:list_dir(Handle, Name, DTraceUtag), Handle}; +handle_call({list_dir, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:list_dir(Handle, Name), Handle}; handle_call(get_cwd, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle, no_drive, "TODO-fixme"), Handle}; -handle_call({get_cwd, no_drive, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle, no_drive, DTraceUtag), Handle}; -handle_call({get_cwd, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:get_cwd(Handle, Name, DTraceUtag), Handle}; + {reply, ?PRIM_FILE:get_cwd(Handle), Handle}; +handle_call({get_cwd}, _From, Handle) -> + {reply, ?PRIM_FILE:get_cwd(Handle), Handle}; +handle_call({get_cwd, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:get_cwd(Handle, Name), Handle}; -handle_call({read_file_info, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file_info(Handle, Name, [], DTraceUtag), Handle}; -handle_call({read_file_info, Name, Opts, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts, DTraceUtag), Handle}; +handle_call({read_file_info, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name), Handle}; -handle_call({altname, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:altname(Handle, Name, DTraceUtag), Handle}; +handle_call({read_file_info, Name, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts), Handle}; -handle_call({write_file_info, Name, Info, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, [], DTraceUtag), Handle}; -handle_call({write_file_info, Name, Info, Opts, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts, DTraceUtag), Handle}; +handle_call({altname, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:altname(Handle, Name), Handle}; -handle_call({read_link_info, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link_info(Handle, Name, [], DTraceUtag), Handle}; -handle_call({read_link_info, Name, Opts, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts, DTraceUtag), Handle}; +handle_call({write_file_info, Name, Info}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info), Handle}; -handle_call({read_link, Name, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:read_link(Handle, Name, DTraceUtag), Handle}; +handle_call({write_file_info, Name, Info, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts), Handle}; -handle_call({make_link, Old, New, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:make_link(Handle, Old, New, DTraceUtag), Handle}; +handle_call({read_link_info, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name), Handle}; -handle_call({make_symlink, Old, New, DTraceUtag}, _From, Handle) -> - {reply, ?PRIM_FILE:make_symlink(Handle, Old, New, DTraceUtag), Handle}; +handle_call({read_link_info, Name, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts), Handle}; -handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length, DTraceUtag}, +handle_call({read_link, Name}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link(Handle, Name), Handle}; + +handle_call({make_link, Old, New}, _From, Handle) -> + {reply, ?PRIM_FILE:make_link(Handle, Old, New), Handle}; + +handle_call({make_symlink, Old, New}, _From, Handle) -> + {reply, ?PRIM_FILE:make_symlink(Handle, Old, New), Handle}; + +handle_call({copy, SourceName, SourceOpts, DestName, DestOpts, Length}, _From, Handle) -> Reply = - case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts], - DTraceUtag) of + case ?PRIM_FILE:open(SourceName, [read, binary | SourceOpts]) of {ok, Source} -> SourceReply = case ?PRIM_FILE:open(DestName, - [write, binary | DestOpts], - DTraceUtag) of + [write, binary | DestOpts]) of {ok, Dest} -> DestReply = - ?PRIM_FILE:copy(Source, Dest, Length, DTraceUtag), - ?PRIM_FILE:close(Dest, DTraceUtag), + ?PRIM_FILE:copy(Source, Dest, Length), + ?PRIM_FILE:close(Dest), DestReply; {error, _} = Error -> Error end, - ?PRIM_FILE:close(Source, DTraceUtag), + ?PRIM_FILE:close(Source), SourceReply; {error, _} = Error -> Error diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 9575762b12..3e2202922c 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -70,7 +70,7 @@ %% compile time. -define(PRIM_FILE_call(F, H, A), case H of - [] -> apply(?PRIM_FILE, F, A -- ["utag"]); + [] -> apply(?PRIM_FILE, F, A); _ -> apply(?PRIM_FILE, F, [H | A]) end). @@ -255,31 +255,31 @@ make_del_dir(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_mk-dir"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), - ?line {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), - ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), - ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line {error, eexist} = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), + ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), % Make sure we are not in a directory directly under test_server % as that would result in eacess errors when trying to delere '..', % because there are processes having that directory as current. - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), ?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), try %% Check that we get an error when trying to create... %% a deep directory ?line NewDir2 = filename:join(RootDir, atom_to_list(?MODULE) ++"_mk-dir-noexist/foo"), - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2, "utag"]), + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]), %% a nameless directory - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, ["", "utag"]), + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]), %% a directory with illegal name - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir', "utag"]), + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']), %% a directory with illegal name, even if it's a (bad) list - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}], "utag"]), + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]), %% Maybe this isn't an error, exactly, but worth mentioning anyway: %% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])), @@ -292,17 +292,17 @@ make_del_dir(Config, Handle, Suffix) -> %% Try deleting some bad directories %% Deleting the parent directory to the current, sounds dangerous, huh? %% Don't worry ;-) the parent directory should never be empty, right? - ?line case ?PRIM_FILE_call(del_dir, Handle, ["..", "utag"]) of + ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of {error, eexist} -> ok; {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, - ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, ["", "utag"]), - ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}], "utag"]), + ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), + ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), ?line test_server:timetrap_cancel(Dog) after - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir, "utag"]) + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir]) end, ok. @@ -324,7 +324,7 @@ cur_dir_0(Config, Handle) -> %% Find out the current dir, and cd to it ;-) ?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []), ?line Dir1 = BaseDir ++ "", %% Check that it's a string - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), ?line DirName = atom_to_list(?MODULE) ++ case Handle of [] -> @@ -336,40 +336,40 @@ cur_dir_0(Config, Handle) -> %% Make a new dir, and cd to that ?line RootDir = ?config(priv_dir,Config), ?line NewDir = filename:join(RootDir, DirName), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), ?line io:format("cd to ~s",[NewDir]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), %% Create a file in the new current directory, and check that it %% really is created there ?line UncommonName = "uncommon.fil", ?line {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]), ?line ok = ?PRIM_FILE:close(Fd), - ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), + ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), ?line true = lists:member(UncommonName,NewDirFiles), %% Delete the directory and return to the old current directory %% and check that the created file isn't there (too!) ?line expect({error, einval}, {error, eacces}, {error, eexist}, - ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"])), - ?line ?PRIM_FILE_call(delete, Handle, [UncommonName, "utag"]), - ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), + ?PRIM_FILE_call(del_dir, Handle, [NewDir])), + ?line ?PRIM_FILE_call(delete, Handle, [UncommonName]), + ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), ?line io:format("cd back to ~s",[Dir1]), - ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir, "utag"]), - ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir, "utag"]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1, "utag"]), + ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), + ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), ?line io:format("cd back to ~s",[Dir1]), - ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, [".", "utag"]), + ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), ?line false = lists:member(UncommonName,OldDirFiles), %% Try doing some bad things ?line {error, badarg} = - ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}, "utag"]), + ?PRIM_FILE_call(set_cwd, Handle, [{foo,bar}]), ?line {error, enoent} = - ?PRIM_FILE_call(set_cwd, Handle, ["", "utag"]), + ?PRIM_FILE_call(set_cwd, Handle, [""]), ?line {error, enoent} = - ?PRIM_FILE_call(set_cwd, Handle, [".......a......", "utag"]), + ?PRIM_FILE_call(set_cwd, Handle, [".......a......"]), ?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []), %% Still there? @@ -405,10 +405,10 @@ cur_dir_1(Config, Handle) -> ?line case os:type() of {unix, _} -> ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:", "utag"]); + ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); vxworks -> ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:", "utag"]); + ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); {win32, _} -> win_cur_dir_1(Config, Handle) end, @@ -422,7 +422,7 @@ win_cur_dir_1(_Config, Handle) -> %% and try to get current directory for that drive. ?line [Drive, $:|_] = BaseDir, - ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:], "utag"]), + ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, [[Drive, $:]]), io:format("BaseDir = ~s\n", [BaseDir]), %% Unfortunately, there is no way to move away from the @@ -1027,7 +1027,7 @@ file_write_file_info(Config, Handle, Suffix) -> ?line ok = ?PRIM_FILE:write_file(Name, "hello"), ?line Time = {{1997, 01, 02}, {12, 35, 42}}, ?line Info = #file_info{mode=8#400, atime=Time, mtime=Time, ctime=Time}, - ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info, "utag"]), + ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, Info]), %% Read back the times. @@ -1050,12 +1050,12 @@ file_write_file_info(Config, Handle, Suffix) -> %% Make the file writable again. ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#600}, "utag"]), + [Name, #file_info{mode=8#600}]), ?line ok = ?PRIM_FILE:write_file(Name, "hello again"), %% And unwritable. ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#400}, "utag"]), + [Name, #file_info{mode=8#400}]), ?line {error, eacces} = ?PRIM_FILE:write_file(Name, "hello again"), %% Write the times again. @@ -1063,7 +1063,7 @@ file_write_file_info(Config, Handle, Suffix) -> ?line NewTime = {{1997, 02, 15}, {13, 18, 20}}, ?line NewInfo = #file_info{atime=NewTime, mtime=NewTime, ctime=NewTime}, - ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo, "utag"]), + ?line ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, NewInfo]), ?line {ok, ActualInfo2} = ?PRIM_FILE_call(read_file_info, Handle, [Name]), ?line #file_info{atime=NewActAtime, mtime=NewTime, @@ -1081,7 +1081,7 @@ file_write_file_info(Config, Handle, Suffix) -> %% Make the file writeable again, so that we can remove the %% test suites ... :-) ?line ?PRIM_FILE_call(write_file_info, Handle, - [Name, #file_info{mode=8#600}, "utag"]), + [Name, #file_info{mode=8#600}]), ?line test_server:timetrap_cancel(Dog), ok. @@ -1390,11 +1390,11 @@ delete(Config, Handle, Suffix) -> %% Check that the file is readable ?line {ok, Fd2} = ?PRIM_FILE:open(Name, [read]), ?line ok = ?PRIM_FILE:close(Fd2), - ?line ok = ?PRIM_FILE_call(delete, Handle, [Name, "utag"]), + ?line ok = ?PRIM_FILE_call(delete, Handle, [Name]), %% Check that the file is not readable anymore ?line {error, _} = ?PRIM_FILE:open(Name, [read]), %% Try deleting a nonexistent file - ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name, "utag"]), + ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name]), ?line test_server:timetrap_cancel(Dog), ok. @@ -1895,14 +1895,14 @@ make_link(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_make_link"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), ?line Name = filename:join(NewDir, "a_file"), ?line ok = ?PRIM_FILE:write_file(Name, "some contents\n"), ?line Alias = filename:join(NewDir, "an_alias"), ?line Result = - case ?PRIM_FILE_call(make_link, Handle, [Name, Alias, "utag"]) of + case ?PRIM_FILE_call(make_link, Handle, [Name, Alias]) of {error, enotsup} -> {skipped, "Links not supported on this platform"}; ok -> @@ -1913,12 +1913,12 @@ make_link(Config, Handle, Suffix) -> %% since they are not used on symbolic links. ?line {ok, Info} = - ?PRIM_FILE_call(read_link_info, Handle, [Name, "utag"]), + ?PRIM_FILE_call(read_link_info, Handle, [Name]), ?line {ok, Info} = - ?PRIM_FILE_call(read_link_info, Handle, [Alias, "utag"]), + ?PRIM_FILE_call(read_link_info, Handle, [Alias]), ?line #file_info{links = 2, type = regular} = Info, ?line {error, eexist} = - ?PRIM_FILE_call(make_link, Handle, [Name, Alias, "utag"]), + ?PRIM_FILE_call(make_link, Handle, [Name, Alias]), ok end, @@ -1956,30 +1956,30 @@ symlinks(Config, Handle, Suffix) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) ++"_make_symlink"++Suffix), - ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), ?line Name = filename:join(NewDir, "a_plain_file"), ?line ok = ?PRIM_FILE:write_file(Name, "some stupid content\n"), ?line Alias = filename:join(NewDir, "a_symlink_alias"), ?line Result = - case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias, "utag"]) of + case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias]) of {error, enotsup} -> {skipped, "Links not supported on this platform"}; ok -> ?line {ok, Info1} = - ?PRIM_FILE_call(read_file_info, Handle, [Name, "utag"]), + ?PRIM_FILE_call(read_file_info, Handle, [Name]), ?line {ok, Info1} = - ?PRIM_FILE_call(read_file_info, Handle, [Alias, "utag"]), + ?PRIM_FILE_call(read_file_info, Handle, [Alias]), ?line {ok, Info1} = - ?PRIM_FILE_call(read_link_info, Handle, [Name, "utag"]), + ?PRIM_FILE_call(read_link_info, Handle, [Name]), ?line #file_info{links = 1, type = regular} = Info1, ?line {ok, Info2} = - ?PRIM_FILE_call(read_link_info, Handle, [Alias, "utag"]), + ?PRIM_FILE_call(read_link_info, Handle, [Alias]), ?line #file_info{links=1, type=symlink} = Info2, ?line {ok, Name} = - ?PRIM_FILE_call(read_link, Handle, [Alias, "utag"]), + ?PRIM_FILE_call(read_link, Handle, [Alias]), ok end, @@ -2003,7 +2003,7 @@ list_dir_limit(Config) when is_list(Config) -> ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE)++"_list_dir_limit"), ?line {ok, Handle1} = ?PRIM_FILE:start(), - ?line ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir, "utag"]), + ?line ok = ?PRIM_FILE_call(make_dir, Handle1, [NewDir]), Ref = erlang:start_timer(MaxTime*1000, self(), []), ?line Result = list_dir_limit_loop(NewDir, Handle1, Ref, MaxNumber, 0), ?line Time = case erlang:cancel_timer(Ref) of @@ -2054,7 +2054,7 @@ list_dir_limit_loop(Dir, Handle, Ref, N, Cnt) -> end. list_dir_check(Dir, Handle, Cnt) -> - case ?PRIM_FILE:list_dir(Handle, Dir, "utag") of + case ?PRIM_FILE:list_dir(Handle, Dir) of {ok, ListDir} -> case length(ListDir) of Cnt -> -- cgit v1.2.3 From cca350ef2206a81c0f8969071f412f07b87413a1 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Fri, 2 Mar 2012 18:41:17 +0100 Subject: Change to more specific configure options for dtrace --- configure.in | 12 +- erts/configure.in | 76 ++++++++--- erts/emulator/beam/beam_emu.c | 35 +++-- erts/emulator/beam/bif.c | 60 ++++++--- erts/emulator/beam/dist.c | 10 +- erts/emulator/beam/dtrace-wrapper.h | 6 +- erts/emulator/beam/erl_alloc.c | 2 +- erts/emulator/beam/erl_bif_ddll.c | 2 +- erts/emulator/beam/erl_bif_info.c | 2 +- erts/emulator/beam/erl_bif_timer.c | 2 +- erts/emulator/beam/erl_bif_trace.c | 12 +- erts/emulator/beam/erl_db_util.c | 4 +- erts/emulator/beam/erl_gc.c | 6 +- erts/emulator/beam/erl_lock_check.c | 2 +- erts/emulator/beam/erl_message.c | 70 +++++----- erts/emulator/beam/erl_message.h | 6 +- erts/emulator/beam/erl_nif.c | 2 +- erts/emulator/beam/erl_process.c | 12 +- erts/emulator/beam/erl_process.h | 4 +- erts/emulator/beam/erl_trace.c | 16 +-- erts/emulator/beam/io.c | 10 +- erts/emulator/beam/utils.c | 2 +- erts/emulator/drivers/common/efile_drv.c | 214 +++++++++++++++---------------- 23 files changed, 324 insertions(+), 243 deletions(-) diff --git a/configure.in b/configure.in index 0d54dcd3a3..c7e6e9ecf9 100644 --- a/configure.in +++ b/configure.in @@ -225,10 +225,14 @@ AC_ARG_ENABLE(native-libs, AS_HELP_STRING([--enable-native-libs], [compile Erlang libraries to native code])) -AC_ARG_ENABLE(dtrace, -AS_HELP_STRING([--enable-dtrace], - [Enable DTrace probes])) - +AC_ARG_WITH(dynamic-trace, +AS_HELP_STRING([--with-dynamic-trace={dtrace|systemtap}], + [specify use of dynamic trace framework, dtrace or systemtap]) +AS_HELP_STRING([--without-dynamic-trace], + [don't enable any dynamic tracing (default)])) +AC_ARG_ENABLE(vm-probes, +AS_HELP_STRING([--enable-vm-probes], + [add dynamic trace probes to the Beam VM (only possible if --with-dynamic-trace is enabled, and then default)])) AC_ARG_WITH(javac, AS_HELP_STRING([--with-javac=JAVAC], [specify Java compiler to use]) AS_HELP_STRING([--with-javac], [use a Java compiler if found (default)]) diff --git a/erts/configure.in b/erts/configure.in index 88c73a7371..15ca2209b7 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -276,6 +276,59 @@ else [Define to enable hrvtime() on Linux systems with perfctr extension]) fi + +AC_ARG_WITH(dynamic-trace, +AS_HELP_STRING([--with-dynamic-trace={dtrace|systemtap}], + [specify use of dynamic trace framework, dtrace or systemtap]) +AS_HELP_STRING([--without-dynamic-trace], + [don't enable any dynamic tracing (default)])) + +if test X"$with_dynamic_trace" = X""; then + with_dynamic_trace=no +fi + +case "$with_dynamic_trace" in + no) DYNAMIC_TRACE_FRAMEWORK=;; + dtrace) + AC_DEFINE(USE_DTRACE,[1], + [Define if you want to use dtrace for dynamic tracing]) + DYNAMIC_TRACE_FRAMEWORK=dtrace;; + systemtap) + AC_DEFINE(USE_SYSTEMTAP,[1], + [Define if you want to use systemtap for dynamic tracing]) + DYNAMIC_TRACE_FRAMEWORK=systemtap;; + *) + AC_MSG_ERROR(Unknown dynamic tracing framework specified with --with-dynamic-trace!);; +esac + +if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then + AC_DEFINE(USE_DYNAMIC_TRACE,[1], + [Define if you want to use dynamic tracing]) +fi + +AC_ARG_ENABLE(vm-probes, +AS_HELP_STRING([--enable-vm-probes], + [add dynamic trace probes to the Beam VM (only possible if --with-dynamic-trace is enabled, and then default)]), + [ case "$enableval" in + no) use_vm_probes=no ;; + *) + if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then + use_vm_probes=yes ; + else + AC_MSG_ERROR(Can not enable VM probes without any dynamic tracing framework!); + fi;; + esac ], if test X"$DYNAMIC_TRACE_FRAMEWORK" != X""; then + use_vm_probes=yes ; + else + use_vm_probes=no + fi) + +if test X"$use_vm_probes" = X"yes"; then + AC_DEFINE(USE_VM_PROBES,[1], + [Define to enable VM dynamic trace probes]) +fi + + AC_ARG_ENABLE(clock-gettime, AS_HELP_STRING([--enable-clock-gettime], [use clock-gettime for time correction]), @@ -3548,20 +3601,14 @@ LM_FIND_EMU_CC dnl dnl DTrace dnl - -AC_MSG_CHECKING(if --enable-dtrace option specified) -AC_ARG_ENABLE(dtrace, - [AC_HELP_STRING([--enable-dtrace], - [Configure with dtrace static probes])], - [enable_dtrace="$enable_dtrace"]) dnl, [enable_dtrace="no"]) - -if test "$enable_dtrace" = "yes"; then +case $DYNAMIC_TRACE_FRAMEWORK in + dtrace|systemtap) AC_CHECK_TOOL(DTRACE, dtrace, none) - test "$DTRACE" = "none" && AC_MSG_ERROR([No dtrace utility found.]) -else - AC_MSG_RESULT([not specified]) -fi - + test "$DTRACE" = "none" && AC_MSG_ERROR([No dtrace utility found.]); + enable_dtrace_test=yes;; + *) enable_dtrace_test=no;; +esac + AC_SUBST(DTRACE) AC_SUBST(DTRACE_CPP) @@ -3584,7 +3631,7 @@ case $OPSYS in : # Nothing to do ;; esac -if test "$enable_dtrace" = "yes" ; then +if test "$enable_dtrace_test" = "yes" ; then if test "$DTRACE" = "dtrace" ; then AC_CHECK_HEADERS(sys/sdt.h) # The OS X version of dtrace prints a spurious line here. @@ -3603,7 +3650,6 @@ if test "$enable_dtrace" = "yes" ; then AC_MSG_NOTICE([dtrace precompilation for 1-stage DTrace successful]) fi DTRACE_ENABLED=yes - AC_DEFINE(HAVE_DTRACE, 1, [Define to enable DTrace probes (or SystemTap probes on Linux systems)]) case $OPSYS in linux) : # No extra libs to add to LIBS diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index deeb7357d6..763d15e101 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1051,7 +1051,7 @@ init_emulator(void) # define REG_tmp_arg2 #endif -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES #define DTRACE_CALL(p, m, f, a) \ if (DTRACE_ENABLED(function_entry)) { \ @@ -1111,7 +1111,7 @@ init_emulator(void) DTRACE2(nif_return, process_name, mfa); \ } -#else /* HAVE_DTRACE */ +#else /* USE_VM_PROBES */ #define DTRACE_CALL(p, m, f, a) do {} while (0) #define DTRACE_RETURN(p, m, f, a) do {} while (0) @@ -1120,7 +1120,7 @@ init_emulator(void) #define DTRACE_NIF_ENTRY(p, m, f, a) do {} while (0) #define DTRACE_NIF_RETURN(p, m, f, a) do {} while (0) -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ void dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) @@ -1892,34 +1892,49 @@ void process_main(void) save_calls(c_p, &exp_receive); } if (ERL_MESSAGE_TOKEN(msgp) == NIL) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (DT_UTAG(c_p) != NIL) { if (DT_UTAG_FLAGS(c_p) & DT_UTAG_PERMANENT) { SEQ_TRACE_TOKEN(c_p) = am_have_dt_utag; +#ifdef DTRACE_TAG_HARDDEBUG if (DT_UTAG_FLAGS(c_p) & DT_UTAG_SPREADING) - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) stop spreading tag %T with message %T\r\n",c_p->id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp)); + erts_fprintf(stderr, + "Dtrace -> (%T) stop spreading " + "tag %T with message %T\r\n", + c_p->id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp)); +#endif } else { - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) kill tag %T with message %T\r\n",c_p->id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp)); +#ifdef DTRACE_TAG_HARDDEBUG + erts_fprintf(stderr, + "Dtrace -> (%T) kill tag %T with " + "message %T\r\n", + c_p->id,DT_UTAG(c_p),ERL_MESSAGE_TERM(msgp)); +#endif DT_UTAG(c_p) = NIL; SEQ_TRACE_TOKEN(c_p) = NIL; } } else { #endif SEQ_TRACE_TOKEN(c_p) = NIL; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES } DT_UTAG_FLAGS(c_p) &= ~DT_UTAG_SPREADING; #endif } else if (ERL_MESSAGE_TOKEN(msgp) != am_undefined) { Eterm msg; SEQ_TRACE_TOKEN(c_p) = ERL_MESSAGE_TOKEN(msgp); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (ERL_MESSAGE_TOKEN(msgp) == am_have_dt_utag) { if (DT_UTAG(c_p) == NIL) { DT_UTAG(c_p) = ERL_MESSAGE_DT_UTAG(msgp); } DT_UTAG_FLAGS(c_p) |= DT_UTAG_SPREADING; - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) receive tag (%T) with message %T\r\n",c_p->id, DT_UTAG(c_p), ERL_MESSAGE_TERM(msgp)); +#ifdef DTRACE_TAG_HARDDEBUG + erts_fprintf(stderr, + "Dtrace -> (%T) receive tag (%T) " + "with message %T\r\n", + c_p->id, DT_UTAG(c_p), ERL_MESSAGE_TERM(msgp)); +#endif } else { #endif ASSERT(is_tuple(SEQ_TRACE_TOKEN(c_p))); @@ -1935,7 +1950,7 @@ void process_main(void) msg = ERL_MESSAGE_TERM(msgp); seq_trace_output(SEQ_TRACE_TOKEN(c_p), msg, SEQ_TRACE_RECEIVE, c_p->id, c_p); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES } #endif } diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 6478e54996..2adc713959 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -564,7 +564,7 @@ erts_queue_monitor_message(Process *p, tup = TUPLE5(hp, am_DOWN, ref_copy, type, item_copy, reason_copy); erts_queue_message(p, p_locksp, bp, tup, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -1949,7 +1949,7 @@ do_send(Process *p, Eterm to, Eterm msg, int suspend) { save_calls(p, &exp_send); if (SEQ_TRACE_TOKEN(p) != NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES && SEQ_TRACE_TOKEN(p) != am_have_dt_utag #endif ) { @@ -4234,7 +4234,7 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) for (i = 0; i < erts_max_processes; i++) { if (process_tab[i] != (Process*) 0) { Process* p = process_tab[i]; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES p->seq_trace_token = (p->dt_utag != NIL) ? am_have_dt_utag : NIL; #else p->seq_trace_token = NIL; @@ -4244,7 +4244,7 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p); mp = p->msg.first; while(mp != NULL) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ERL_MESSAGE_TOKEN(mp) = (ERL_MESSAGE_DT_UTAG(mp) != NIL) ? am_have_dt_utag : NIL; #else ERL_MESSAGE_TOKEN(mp) = NIL; @@ -4649,7 +4649,7 @@ BIF_RETTYPE get_module_info_2(BIF_ALIST_2) BIF_RETTYPE put_utag_1(BIF_ALIST_1) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm otag; if (BIF_ARG_1 == am_undefined) { otag = (DT_UTAG(BIF_P) == NIL) ? am_undefined : DT_UTAG(BIF_P); @@ -4677,7 +4677,7 @@ BIF_RETTYPE put_utag_1(BIF_ALIST_1) BIF_RETTYPE get_utag_0(BIF_ALIST_0) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES BIF_RET((DT_UTAG(BIF_P) == NIL || !(DT_UTAG_FLAGS(BIF_P) & DT_UTAG_PERMANENT)) ? am_undefined : DT_UTAG(BIF_P)); #else BIF_RET(am_undefined); @@ -4685,7 +4685,7 @@ BIF_RETTYPE get_utag_0(BIF_ALIST_0) } BIF_RETTYPE get_utag_data_0(BIF_ALIST_0) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES BIF_RET((DT_UTAG(BIF_P) == NIL) ? am_undefined : DT_UTAG(BIF_P)); #else BIF_RET(am_undefined); @@ -4693,7 +4693,7 @@ BIF_RETTYPE get_utag_data_0(BIF_ALIST_0) } BIF_RETTYPE prepend_vm_utag_data_1(BIF_ALIST_1) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm b; Eterm *hp; hp = HAlloc(BIF_P,2); @@ -4720,7 +4720,7 @@ BIF_RETTYPE prepend_vm_utag_data_1(BIF_ALIST_1) } BIF_RETTYPE append_vm_utag_data_1(BIF_ALIST_1) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm b; Eterm *hp; hp = HAlloc(BIF_P,2); @@ -4747,23 +4747,31 @@ BIF_RETTYPE append_vm_utag_data_1(BIF_ALIST_1) } BIF_RETTYPE spread_utag_1(BIF_ALIST_1) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm ret; Eterm *hp; #endif if (BIF_ARG_1 != am_true && BIF_ARG_1 != am_false) { BIF_ERROR(BIF_P,BADARG); } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES hp = HAlloc(BIF_P,3); ret = TUPLE2(hp,make_small(DT_UTAG_FLAGS(BIF_P)),DT_UTAG(BIF_P)); if (DT_UTAG(BIF_P) != NIL) { if (BIF_ARG_1 == am_true) { DT_UTAG_FLAGS(BIF_P) |= DT_UTAG_SPREADING; - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) start spreading tag %T\r\n",BIF_P->id,DT_UTAG(BIF_P)); +#ifdef DTRACE_TAG_HARDDEBUG + erts_fprintf(stderr, + "Dtrace -> (%T) start spreading tag %T\r\n", + BIF_P->id,DT_UTAG(BIF_P)); +#endif } else { DT_UTAG_FLAGS(BIF_P) &= ~DT_UTAG_SPREADING; - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) stop spreading tag %T\r\n",BIF_P->id,DT_UTAG(BIF_P)); +#ifdef DTRACE_TAG_HARDDEBUG + erts_fprintf(stderr, + "Dtrace -> (%T) stop spreading tag %T\r\n", + BIF_P->id,DT_UTAG(BIF_P)); +#endif } } BIF_RET(ret); @@ -4773,7 +4781,7 @@ BIF_RETTYPE spread_utag_1(BIF_ALIST_1) } BIF_RETTYPE restore_utag_1(BIF_ALIST_1) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm *tpl; Uint x; if (is_not_tuple(BIF_ARG_1)) { @@ -4785,7 +4793,11 @@ BIF_RETTYPE restore_utag_1(BIF_ALIST_1) } if (tpl[2] == NIL) { if (DT_UTAG(BIF_P) != NIL) { - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) restore Killing tag!\r\n",BIF_P->id); +#ifdef DTRACE_TAG_HARDDEBUG + erts_fprintf(stderr, + "Dtrace -> (%T) restore Killing tag!\r\n", + BIF_P->id); +#endif } DT_UTAG(BIF_P) = NIL; if (SEQ_TRACE_TOKEN(BIF_P) == am_have_dt_utag) { @@ -4794,11 +4806,21 @@ BIF_RETTYPE restore_utag_1(BIF_ALIST_1) DT_UTAG_FLAGS(BIF_P) = 0; } else { x = unsigned_val(tpl[1]) & (DT_UTAG_SPREADING | DT_UTAG_PERMANENT); - if (!(x & DT_UTAG_SPREADING) && (DT_UTAG_FLAGS(BIF_P) & DT_UTAG_SPREADING)) { - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) restore stop spreading tag %T\r\n",BIF_P->id,tpl[2]); - } else if ((x & DT_UTAG_SPREADING) && !(DT_UTAG_FLAGS(BIF_P) & DT_UTAG_SPREADING)) { - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) restore start spreading tag %T\r\n",BIF_P->id,tpl[2]); +#ifdef DTRACE_TAG_HARDDEBUG + + if (!(x & DT_UTAG_SPREADING) && (DT_UTAG_FLAGS(BIF_P) & + DT_UTAG_SPREADING)) { + erts_fprintf(stderr, + "Dtrace -> (%T) restore stop spreading " + "tag %T\r\n", + BIF_P->id, tpl[2]); + } else if ((x & DT_UTAG_SPREADING) && + !(DT_UTAG_FLAGS(BIF_P) & DT_UTAG_SPREADING)) { + erts_fprintf(stderr, + "Dtrace -> (%T) restore start spreading " + "tag %T\r\n",BIF_P->id,tpl[2]); } +#endif DT_UTAG_FLAGS(BIF_P) = x; DT_UTAG(BIF_P) = tpl[2]; if (SEQ_TRACE_TOKEN(BIF_P) == NIL) { diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 43fc910054..a44caa36db 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -383,7 +383,7 @@ static void doit_node_link_net_exits(ErtsLink *lnk, void *vnecp) Eterm *hp = erts_alloc_message_heap(3,&bp,&ohp,rp,&rp_locks); tup = TUPLE2(hp, am_nodedown, name); erts_queue_message(rp, &rp_locks, bp, tup, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -755,7 +755,7 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) UseTmpHeapNoproc(5); if (SEQ_TRACE_TOKEN(sender) != NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES && SEQ_TRACE_TOKEN(sender) != am_have_dt_utag #endif ) { @@ -808,7 +808,7 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) UseTmpHeapNoproc(6); if (SEQ_TRACE_TOKEN(sender) != NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES && SEQ_TRACE_TOKEN(sender) != am_have_dt_utag #endif ) { @@ -864,7 +864,7 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, UseTmpHeapNoproc(6); if (token != NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES && token != am_have_dt_utag #endif ) { @@ -3111,7 +3111,7 @@ send_nodes_mon_msg(Process *rp, ASSERT(hend == hp); erts_queue_message(rp, rp_locksp, bp, msg, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/beam/dtrace-wrapper.h b/erts/emulator/beam/dtrace-wrapper.h index b633058e90..9d1e55fc43 100644 --- a/erts/emulator/beam/dtrace-wrapper.h +++ b/erts/emulator/beam/dtrace-wrapper.h @@ -42,7 +42,7 @@ #define DTRACE_CHARBUF(name, size) \ char name##_BUFFER[size], *name = name##_BUFFER -#ifdef HAVE_DTRACE +#if defined(USE_DYNAMIC_TRACE) && defined(USE_VM_PROBES) #include "erlang_dtrace.h" @@ -87,7 +87,7 @@ STAP_PROBE10(provider,probe,(parm1),(parm2),(parm3),(parm4),(parm5),(parm6),(parm7),(parm8),(parm9),(parm10)) #endif /* STAP_PROBE_ADDR */ -#else /* HAVE_DTRACE */ +#else /* USE_DYNAMIC_TRACE && USE_VM_PROBES */ /* Render all macros to do nothing */ #define DTRACE_ENABLED(name) 0 @@ -104,6 +104,6 @@ #define DTRACE11(name, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \ do {} while (0) -#endif /* HAVE_DTRACE */ +#endif /* USE_DYNAMIC_TRACE && USE_VM_PROBES */ #endif /* __DTRACE_WRAPPER_H */ diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index d575e30092..8130d5c576 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -3002,7 +3002,7 @@ reply_alloc_info(void *vair) } erts_queue_message(rp, &rp_locks, bp, msg, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index b58c5ab761..bcfdacb91c 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1763,7 +1763,7 @@ static void notify_proc(Process *proc, Eterm ref, Eterm driver_name, Eterm type, mess = TUPLE5(hp,type,r,am_driver,driver_name,tag); } erts_queue_message(proc, &rp_locks, bp, mess, am_undefined -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 90bbb34927..618acc5117 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -115,7 +115,7 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE #ifdef VALGRIND " [valgrind-compiled]" #endif -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES " [dtrace]" #endif "\n"); diff --git a/erts/emulator/beam/erl_bif_timer.c b/erts/emulator/beam/erl_bif_timer.c index fbc2f08c09..0002f8374f 100644 --- a/erts/emulator/beam/erl_bif_timer.c +++ b/erts/emulator/beam/erl_bif_timer.c @@ -374,7 +374,7 @@ bif_timer_timeout(ErtsBifTimer* btm) } erts_queue_message(rp, &rp_locks, bp, message, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index c518aa6866..1ef4b07c24 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -1744,13 +1744,13 @@ Eterm erts_seq_trace(Process *p, Eterm arg1, Eterm arg2, return THE_NON_VALUE; } if (build_result) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES old_value = (SEQ_TRACE_TOKEN(p) == am_have_dt_utag) ? NIL : SEQ_TRACE_TOKEN(p); #else old_value = SEQ_TRACE_TOKEN(p); #endif } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES SEQ_TRACE_TOKEN(p) = (DT_UTAG(p) != NIL) ? am_have_dt_utag : NIL; #else SEQ_TRACE_TOKEN(p) = NIL; @@ -1768,7 +1768,7 @@ new_seq_trace_token(Process* p) Eterm* hp; if (SEQ_TRACE_TOKEN(p) == NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES || SEQ_TRACE_TOKEN(p) == am_have_dt_utag #endif ) { @@ -1792,7 +1792,7 @@ BIF_RETTYPE erl_seq_trace_info(Process *p, Eterm item) } if (SEQ_TRACE_TOKEN(p) == NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES || SEQ_TRACE_TOKEN(p) == am_have_dt_utag #endif ) { @@ -1853,7 +1853,7 @@ BIF_RETTYPE seq_trace_info_1(BIF_ALIST_1) BIF_RETTYPE seq_trace_print_1(BIF_ALIST_1) { if (SEQ_TRACE_TOKEN(BIF_P) == NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES || SEQ_TRACE_TOKEN(BIF_P) == am_have_dt_utag #endif ) { @@ -1876,7 +1876,7 @@ BIF_RETTYPE seq_trace_print_1(BIF_ALIST_1) BIF_RETTYPE seq_trace_print_2(BIF_ALIST_2) { if (SEQ_TRACE_TOKEN(BIF_P) == NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES || SEQ_TRACE_TOKEN(BIF_P) == am_have_dt_utag #endif ) { diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index eb05ceaaf1..be345e7c9b 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -2204,7 +2204,7 @@ restart: break; case matchIsSeqTrace: if (SEQ_TRACE_TOKEN(c_p) != NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES && SEQ_TRACE_TOKEN(c_p) != am_have_dt_utag #endif ) @@ -2232,7 +2232,7 @@ restart: break; case matchGetSeqToken: if (SEQ_TRACE_TOKEN(c_p) == NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES || SEQ_TRACE_TOKEN(c_p) == am_have_dt_utag #endif ) diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 6dfccfe52f..2e340a7ef1 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -1935,7 +1935,7 @@ setup_rootset(Process *p, Eterm *objv, int nobj, Rootset *rootset) roots[n].sz = 1; n++; } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (is_not_immed(p->dt_utag)) { roots[n].v = &p->dt_utag; roots[n].sz = 1; @@ -2478,7 +2478,7 @@ offset_mqueue(Process *p, Sint offs, char* area, Uint area_size) if (is_boxed(mesg) && in_area(ptr_val(mesg), area, area_size)) { ERL_MESSAGE_TOKEN(mp) = offset_ptr(mesg, offs); } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES mesg = ERL_MESSAGE_DT_UTAG(mp); if (is_boxed(mesg) && in_area(ptr_val(mesg), area, area_size)) { ERL_MESSAGE_DT_UTAG(mp) = offset_ptr(mesg, offs); @@ -2504,7 +2504,7 @@ offset_one_rootset(Process *p, Sint offs, char* area, Uint area_size, offset_heap_ptr(&p->fvalue, 1, offs, area, area_size); offset_heap_ptr(&p->ftrace, 1, offs, area, area_size); offset_heap_ptr(&p->seq_trace_token, 1, offs, area, area_size); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES offset_heap_ptr(&p->dt_utag, 1, offs, area, area_size); #endif offset_heap_ptr(&p->group_leader, 1, offs, area, area_size); diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index 561570c30e..5eb2a69242 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -183,7 +183,7 @@ static erts_lc_lock_order_t erts_lock_order[] = { { "save_ops_lock", NULL }, #endif #endif -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES { "efile_drv dtrace mutex", NULL }, #endif { "mtrace_buf", NULL }, diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index dc59b9c2c4..5d4dcaef6d 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -394,7 +394,7 @@ erts_queue_dist_message(Process *rcvr, tok_label, tok_lastcnt, tok_serial); } erts_queue_message(rcvr, rcvr_locks, mbuf, msg, token -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -403,14 +403,14 @@ erts_queue_dist_message(Process *rcvr, /* Enqueue message on external format */ ERL_MESSAGE_TERM(mp) = THE_NON_VALUE; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ERL_MESSAGE_DT_UTAG(mp) = NIL; if (token == am_have_dt_utag) { ERL_MESSAGE_TOKEN(mp) = NIL; } else { #endif ERL_MESSAGE_TOKEN(mp) = token; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES } #endif mp->next = NULL; @@ -445,7 +445,7 @@ erts_queue_message(Process* receiver, ErlHeapFragment* bp, Eterm message, Eterm seq_trace_token -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , Eterm dt_utag #endif ) @@ -489,7 +489,7 @@ erts_queue_message(Process* receiver, ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = seq_trace_token; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ERL_MESSAGE_DT_UTAG(mp) = dt_utag; #endif mp->next = NULL; @@ -567,7 +567,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) Sint offs; Uint sz; ErlHeapFragment *bp; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm utag; #endif @@ -579,7 +579,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) ErlHeapFragment *dbg_bp; Uint *dbg_hp, *dbg_thp_start; Uint dbg_term_sz, dbg_token_sz; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm dbg_utag; Uint dbg_utag_sz; #endif @@ -588,11 +588,11 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) bp = msg->data.heap_frag; term = ERL_MESSAGE_TERM(msg); token = ERL_MESSAGE_TOKEN(msg); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES utag = ERL_MESSAGE_DT_UTAG(msg); #endif if (!bp) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ASSERT(is_immed(term) && is_immed(token) && is_immed(utag)); #else ASSERT(is_immed(term) && is_immed(token)); @@ -604,7 +604,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) dbg_term_sz = size_object(term); dbg_token_sz = size_object(token); dbg_bp = new_message_buffer(dbg_term_sz + dbg_token_sz); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dbg_utag_sz = size_object(utag); dbg_bp = new_message_buffer(dbg_term_sz + dbg_token_sz + dbg_utag_sz ); #endif @@ -615,7 +615,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) dbg_hp = dbg_bp->mem; dbg_term = copy_struct(term, dbg_term_sz, &dbg_hp, &dbg_bp->off_heap); dbg_token = copy_struct(token, dbg_token_sz, &dbg_hp, &dbg_bp->off_heap); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dbg_utag = copy_struct(utag, dbg_utag_sz, &dbg_hp, &dbg_bp->off_heap); #endif dbg_thp_start = *hpp; @@ -623,7 +623,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) if (bp->next != NULL) { move_multi_frags(hpp, off_heap, bp, msg->m, -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES 3 #else 2 @@ -730,7 +730,7 @@ erts_move_msg_mbuf_to_heap(Eterm** hpp, ErlOffHeap* off_heap, ErlMessage *msg) ASSERT(hp > ptr_val(ERL_MESSAGE_TERM(msg))); #endif } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (is_not_immed(utag)) { ASSERT(in_heapfrag(ptr_val(utag), bp)); ERL_MESSAGE_DT_UTAG(msg) = offset_ptr(utag, offs); @@ -806,7 +806,7 @@ copy_done: #ifdef HARD_DEBUG ASSERT(eq(ERL_MESSAGE_TERM(msg), dbg_term)); ASSERT(eq(ERL_MESSAGE_TOKEN(msg), dbg_token)); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ASSERT(eq(ERL_MESSAGE_DT_UTAG(msg), dbg_utag)); #endif free_message_buffer(dbg_bp); @@ -903,7 +903,7 @@ erts_send_message(Process* sender, Eterm* hp; Eterm stoken = SEQ_TRACE_TOKEN(sender); Uint seq_trace_size = 0; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Uint dt_utag_size = 0; Eterm utag = NIL; #endif @@ -912,7 +912,7 @@ erts_send_message(Process* sender, msize = size_object(message); BM_SWAP_TIMER(size,send); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (stoken != am_have_dt_utag) { #endif @@ -920,7 +920,7 @@ erts_send_message(Process* sender, seq_trace_output(stoken, message, SEQ_TRACE_SEND, receiver->id, sender); seq_trace_size = 6; /* TUPLE5 */ -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES } if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) { dt_utag_size = size_object(DT_UTAG(sender)); @@ -930,7 +930,7 @@ erts_send_message(Process* sender, #endif bp = new_message_buffer(msize + seq_trace_size -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + dt_utag_size #endif ); @@ -943,21 +943,15 @@ erts_send_message(Process* sender, &bp->off_heap); message = copy_struct(message, msize, &hp, &bp->off_heap); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (DT_UTAG_FLAGS(sender) & DT_UTAG_SPREADING) { utag = copy_struct(DT_UTAG(sender), dt_utag_size, &hp, &bp->off_heap); - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) Spreading tag (%T) with message %T!\r\n",sender->id, utag, message); - } -#if 0 - DT_UTAG_FLAGS(sender) &= ~DT_UTAG_SPREADING; - if (!(DT_UTAG_FLAGS(sender) & DT_UTAG_PERMANENT)) { - erts_fprintf(stderr,"XXX: PaN: Dtrace -> (%T) Killing tag!\r\n",sender->id); - DT_UTAG(sender) = NIL; - if (SEQ_TRACE_TOKEN(sender) == am_have_dt_utag) { - SEQ_TRACE_TOKEN(sender) = NIL; - } - } +#ifdef DTRACE_TAG_HARDDEBUG + erts_fprintf(stderr, + "Dtrace -> (%T) Spreading tag (%T) with " + "message %T!\r\n",sender->id, utag, message); #endif + } #endif BM_MESSAGE_COPIED(msize); BM_SWAP_TIMER(copy,send); @@ -976,7 +970,7 @@ erts_send_message(Process* sender, bp, message, token -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , utag #endif ); @@ -1012,7 +1006,7 @@ erts_send_message(Process* sender, size_object(message)msize, tok_label, tok_lastcnt, tok_serial); ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ERL_MESSAGE_DT_UTAG(mp) = NIL; #endif mp->next = NULL; @@ -1057,7 +1051,7 @@ erts_send_message(Process* sender, mp->data.attached = NULL; ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ERL_MESSAGE_DT_UTAG(mp) = NIL; #endif mp->next = NULL; @@ -1094,7 +1088,7 @@ erts_send_message(Process* sender, DTRACE6(message_send, sender_name, receiver_name, msize, tok_label, tok_lastcnt, tok_serial); erts_queue_message(receiver, receiver_locks, bp, message, token -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -1121,7 +1115,7 @@ erts_send_message(Process* sender, (uint32_t)msize, tok_label, tok_lastcnt, tok_serial); ERL_MESSAGE_TERM(mp) = message; ERL_MESSAGE_TOKEN(mp) = NIL; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ERL_MESSAGE_DT_UTAG(mp) = NIL; #endif mp->next = NULL; @@ -1163,7 +1157,7 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp, ErlHeapFragment* bp = NULL; if (token != NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES && token != am_have_dt_utag #endif ) { @@ -1182,7 +1176,7 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp, seq_trace_output(token, save, SEQ_TRACE_SEND, to->id, NULL); temptoken = copy_struct(token, sz_token, &hp, &bp->off_heap); erts_queue_message(to, to_locksp, bp, save, temptoken -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -1203,7 +1197,7 @@ erts_deliver_exit_message(Eterm from, Process *to, ErtsProcLocks *to_locksp, : copy_struct(from, sz_from, &hp, ohp)); save = TUPLE3(hp, am_EXIT, from_copy, mess); erts_queue_message(to, to_locksp, bp, save, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h index 98321dd2c6..7678c7c753 100644 --- a/erts/emulator/beam/erl_message.h +++ b/erts/emulator/beam/erl_message.h @@ -70,7 +70,7 @@ typedef struct erl_mesg { ErlHeapFragment *heap_frag; void *attached; } data; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm m[3]; /* m[0] = message, m[1] = seq trace token, m[3] = dynamic trace user tag */ #else Eterm m[2]; /* m[0] = message, m[1] = seq trace token */ @@ -79,7 +79,7 @@ typedef struct erl_mesg { #define ERL_MESSAGE_TERM(mp) ((mp)->m[0]) #define ERL_MESSAGE_TOKEN(mp) ((mp)->m[1]) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES #define ERL_MESSAGE_DT_UTAG(mp) ((mp)->m[2]) #endif @@ -229,7 +229,7 @@ ErlHeapFragment* erts_resize_message_buffer(ErlHeapFragment *, Uint, void free_message_buffer(ErlHeapFragment *); void erts_queue_dist_message(Process*, ErtsProcLocks*, ErtsDistExternal *, Eterm); void erts_queue_message(Process*, ErtsProcLocks*, ErlHeapFragment*, Eterm, Eterm -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , Eterm dt_utag #endif ); diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index ebc771b016..156783d057 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -352,7 +352,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, flush_env(env); /* Needed for ERTS_HOLE_CHECK */ } erts_queue_message(rp, &rp_locks, frags, msg, am_undefined -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 6771e00c7e..f678d4159d 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -680,7 +680,7 @@ reply_sched_wall_time(void *vswtrp) } erts_queue_message(rp, &rp_locks, bp, msg, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -7264,7 +7264,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). p->seq_trace_lastcnt = 0; p->seq_trace_clock = 0; SEQ_TRACE_TOKEN(p) = NIL; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES DT_UTAG(p) = NIL; DT_UTAG_FLAGS(p) = 0; #endif @@ -7860,7 +7860,7 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp, Eterm exit_term, Uint term_size, Eterm token) { if (token == NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES || token == am_have_dt_utag #endif ) { @@ -7872,7 +7872,7 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp, hp = erts_alloc_message_heap(term_size, &bp, &ohp, to, to_locksp); mess = copy_struct(exit_term, term_size, &hp, ohp); erts_queue_message(to, to_locksp, bp, mess, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -7892,7 +7892,7 @@ send_exit_message(Process *to, ErtsProcLocks *to_locksp, seq_trace_output(token, mess, SEQ_TRACE_SEND, to->id, NULL); temp_token = copy_struct(token, sz_token, &hp, &bp->off_heap); erts_queue_message(to, to_locksp, bp, mess, temp_token -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -8002,7 +8002,7 @@ send_exit_signal(Process *c_p, /* current process if and only if (ERTS_PROC_IS_TRAPPING_EXITS(rp) && (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) { if (is_not_nil(token) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES && token != am_have_dt_utag #endif && token_update) diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 35b31b1009..cff0783bc4 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -683,7 +683,7 @@ struct process { Uint seq_trace_lastcnt; Eterm seq_trace_token; /* Sequential trace token (tuple size 5 see below) */ -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Eterm dt_utag; /* Place to store the dynamc trace user tag */ Uint dt_utag_flags; /* flag field for the dt_utag */ #endif @@ -1002,7 +1002,7 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; #define SEQ_TRACE_PRINT (1 << 2) #define SEQ_TRACE_TIMESTAMP (1 << 3) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES #define DT_UTAG_PERMANENT (1 << 0) #define DT_UTAG_SPREADING (1 << 1) #define DT_UTAG(P) ((P)->dt_utag) diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index a4aed0122b..4261cd03be 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -125,7 +125,7 @@ do { \ enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, (FPID), (TPID), (MSG), (BP)); \ } while(0) #else -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES #define ERTS_ENQ_TRACE_MSG(FPID, TPROC, MSG, BP) \ erts_queue_message((TPROC), NULL, (BP), (MSG), NIL, NIL) #else @@ -589,7 +589,7 @@ profile_send(Eterm from, Eterm message) { msg = copy_struct(message, sz, &hp, &bp->off_heap); erts_queue_message(profile_p, NULL, bp, msg, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -1004,7 +1004,7 @@ seq_trace_update_send(Process *p) Eterm seq_tracer = erts_get_system_seq_tracer(); ASSERT((is_tuple(SEQ_TRACE_TOKEN(p)) || is_nil(SEQ_TRACE_TOKEN(p)))); if ( (p->id == seq_tracer) || (SEQ_TRACE_TOKEN(p) == NIL) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES || (SEQ_TRACE_TOKEN(p) == am_have_dt_utag) #endif ) { @@ -1192,7 +1192,7 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, erts_smp_mtx_unlock(&smq_mtx); #else erts_queue_message(tracer, NULL, bp, mess, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); /* trace_token must be NIL here */ @@ -2487,7 +2487,7 @@ monitor_long_gc(Process *p, Uint time) { enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp); #else erts_queue_message(monitor_p, NULL, bp, msg, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -2563,7 +2563,7 @@ monitor_large_heap(Process *p) { enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp); #else erts_queue_message(monitor_p, NULL, bp, msg, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -2597,7 +2597,7 @@ monitor_generic(Process *p, Eterm type, Eterm spec) { enqueue_sys_msg(SYS_MSG_TYPE_SYSMON, p->id, NIL, msg, bp); #else erts_queue_message(monitor_p, NULL, bp, msg, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -3387,7 +3387,7 @@ sys_msg_dispatcher_func(void *unused) else { queue_proc_msg: erts_queue_message(proc,&proc_locks,smqp->bp,smqp->msg,NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 75ea53c2b7..9425576980 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -1565,7 +1565,7 @@ deliver_result(Eterm sender, Eterm pid, Eterm res) res = copy_struct(res, sz_res, &hp, ohp); tuple = TUPLE2(hp, sender, res); erts_queue_message(rp, &rp_locks, bp, tuple, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -1658,7 +1658,7 @@ static void deliver_read_message(Port* prt, Eterm to, hp += 3; erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -1815,7 +1815,7 @@ deliver_vec_message(Port* prt, /* Port */ hp += 3; erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -2785,7 +2785,7 @@ void driver_report_exit(int ix, int status) tuple = TUPLE2(hp, prt->id, tuple); erts_queue_message(rp, &rp_locks, bp, tuple, am_undefined -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); @@ -3339,7 +3339,7 @@ driver_deliver_term(ErlDrvPort port, } /* send message */ erts_queue_message(rp, &rp_locks, bp, mess, am_undefined -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 2efcd19162..5ab51fab50 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -1698,7 +1698,7 @@ static int do_send_to_logger(Eterm tag, Eterm gleader, char *buf, int len) } #else erts_queue_message(p, NULL /* only used for smp build */, bp, tuple3, NIL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , NIL #endif ); diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 62b582f76a..53cdb13db0 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -123,7 +123,7 @@ static ErlDrvSysInfo sys_info; /* For explanation of this var, see comment for same var in erl_async.c */ static unsigned gcc_optimizer_hack = 0; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES #define DTRACE_EFILE_BUFSIZ 128 @@ -148,11 +148,11 @@ typedef struct { } dt_private; dt_private *get_dt_private(int); -#else /* HAVE_DTRACE */ +#else /* USE_VM_PROBES */ #define DTRACE_INVOKE_SETUP(op) do {} while (0) #define DTRACE_INVOKE_SETUP_BY_NAME(op) do {} while (0) #define DTRACE_INVOKE_RETURN(op) do {} while (0) -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ /* #define TRACE 1 */ #ifdef TRACE @@ -208,7 +208,7 @@ dt_private *get_dt_private(int); #ifdef FILENAMES_16BIT -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES #error 16bit characters in filenames and dtrace in combination is not supported. #endif # define FILENAME_BYTELEN(Str) filename_len_16bit(Str) @@ -326,7 +326,7 @@ typedef struct { ErlDrvPDL q_mtx; /* Mutex for the driver queue, known by the emulator. Also used for mutual exclusion when accessing field(s) below. */ size_t write_buffered; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES int idnum; /* Unique ID # for this driver thread/desc */ char port_str[DTRACE_TERM_BUF_SIZE]; #endif @@ -427,7 +427,7 @@ struct t_data void (*free)(void *); int again; int reply; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES int sched_i1; Uint64 sched_i2; char sched_utag[DTRACE_EFILE_BUFSIZ+1]; @@ -727,10 +727,10 @@ file_init(void) : 0); driver_system_info(&sys_info, sizeof(ErlDrvSysInfo)); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES erts_mtx_init(&dt_driver_mutex, "efile_drv dtrace mutex"); pthread_key_create(&dt_driver_key, NULL); -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ return 0; } @@ -771,10 +771,10 @@ file_start(ErlDrvPort port, char* command) desc->write_error = 0; MUTEX_INIT(desc->q_mtx, port); /* Refc is one, referenced by emulator now */ desc->write_buffered = 0; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dtrace_drvport_str(port, desc->port_str); get_dt_private(0); /* throw away return value */ -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ return (ErlDrvData) desc; } @@ -2025,7 +2025,7 @@ static void cq_execute(file_descriptor *desc) { static struct t_data *async_write(file_descriptor *desc, int *errp, int reply, Uint32 reply_size -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ,Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3 #endif ) { @@ -2041,7 +2041,7 @@ static struct t_data *async_write(file_descriptor *desc, int *errp, d->c.writev.port = desc->port; d->c.writev.q_mtx = desc->q_mtx; d->c.writev.size = desc->write_buffered; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (dt_i1 != NULL) { *dt_i1 = d->fd; *dt_i2 = d->flags; @@ -2060,12 +2060,12 @@ static struct t_data *async_write(file_descriptor *desc, int *errp, } static int flush_write(file_descriptor *desc, int *errp -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_private *dt_priv, char *dt_utag #endif ) { int result = 0; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; #endif struct t_data *d = NULL; @@ -2073,7 +2073,7 @@ static int flush_write(file_descriptor *desc, int *errp MUTEX_LOCK(desc->q_mtx); if (desc->write_buffered > 0) { if ((d = async_write(desc, errp, 0, 0 -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ,&dt_i1, &dt_i2, &dt_i3 #endif )) == NULL) { @@ -2081,7 +2081,7 @@ static int flush_write(file_descriptor *desc, int *errp } } MUTEX_UNLOCK(desc->q_mtx); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (d != NULL) { d->sched_i1 = dt_priv->thread_num; d->sched_i2 = dt_priv->tag; @@ -2098,7 +2098,7 @@ static int flush_write(file_descriptor *desc, int *errp dt_utag, FILE_WRITE, NULL, NULL, dt_i1, dt_i2, dt_i3, 0, desc->port_str); } -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ return result; } @@ -2112,13 +2112,13 @@ static int check_write_error(file_descriptor *desc, int *errp) { } static int flush_write_check_error(file_descriptor *desc, int *errp -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_private *dt_priv, char *dt_utag #endif ) { int r; if ( (r = flush_write(desc, errp -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif )) != 0) { @@ -2131,7 +2131,7 @@ static int flush_write_check_error(file_descriptor *desc, int *errp static struct t_data *async_lseek(file_descriptor *desc, int *errp, int reply, Sint64 offset, int origin -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , Sint64 *dt_i1, Sint64 *dt_i2, Sint64 *dt_i3 #endif ) { @@ -2146,7 +2146,7 @@ static struct t_data *async_lseek(file_descriptor *desc, int *errp, int reply, d->reply = reply; d->c.lseek.offset = offset; d->c.lseek.origin = origin; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES if (dt_i1 != NULL) { *dt_i1 = d->fd; *dt_i2 = d->c.lseek.offset; @@ -2170,13 +2170,13 @@ static void flush_read(file_descriptor *desc) { } static int lseek_flush_read(file_descriptor *desc, int *errp -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES ,dt_private *dt_priv, char *dt_utag #endif ) { int r = 0; size_t read_size = desc->read_size; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; #endif struct t_data *d; @@ -2185,13 +2185,13 @@ static int lseek_flush_read(file_descriptor *desc, int *errp if (read_size != 0) { if ((d = async_lseek(desc, errp, 0, -((ssize_t)read_size), EFILE_SEEK_CUR -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , &dt_i1, &dt_i2, &dt_i3 #endif )) == NULL) { r = -1; } else { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES d->sched_i1 = dt_priv->thread_num; d->sched_i2 = dt_priv->tag; d->sched_utag[0] = '\0'; @@ -2206,7 +2206,7 @@ static int lseek_flush_read(file_descriptor *desc, int *errp DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, dt_utag, FILE_LSEEK, NULL, NULL, dt_i1, dt_i2, dt_i3, 0, desc->port_str); -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ } } return r; @@ -2224,7 +2224,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) struct t_data *d = (struct t_data *) data; char header[5]; /* result code + count */ char resbuf[RESBUFSIZE]; /* Result buffer. */ -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES int sched_i1 = d->sched_i1, sched_i2 = d->sched_i2, command = d->command, result_ok = d->result_ok, posix_errno = d->result_ok ? 0 : d->errInfo.posix_errno; @@ -2235,7 +2235,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) strncpy(sched_utag, d->sched_utag, DTRACE_EFILE_BUFSIZ); sched_utag[DTRACE_EFILE_BUFSIZ] = '\0'; } -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ TRACE_C('r'); @@ -2438,7 +2438,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) if (d->reply) { TRACE_C('K'); reply_ok(desc); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES result_ok = 1; #endif } @@ -2520,7 +2520,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) char* name; /* Points to the filename in buf. */ int command; struct t_data *d = NULL; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES char *dt_utag = NULL; char *dt_s1 = NULL, *dt_s2 = NULL; Sint64 dt_i1 = 0; @@ -2528,7 +2528,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) Sint64 dt_i3 = 0; Sint64 dt_i4 = 0; dt_private *dt_priv = get_dt_private(0); -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ TRACE_C('o'); @@ -2543,7 +2543,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; #endif @@ -2558,7 +2558,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; #endif @@ -2573,7 +2573,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; #endif @@ -2594,7 +2594,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_COPY(d->b, name); FILENAME_COPY(d->b + namelen, new_name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_s2 = d->b + namelen; dt_utag = buf + namelen + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; @@ -2612,7 +2612,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; #endif @@ -2627,7 +2627,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); d->drive = *(uchar*)buf; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = buf + 1; #endif d->command = command; @@ -2645,7 +2645,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_CHARSIZE); FILENAME_COPY(d->b, name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; #endif @@ -2673,7 +2673,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) dir_handle = NULL; resbuf[0] = FILE_RESP_LFNAME; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = name; dt_utag = name + FILENAME_BYTELEN(name) + FILENAME_CHARSIZE; #endif @@ -2710,7 +2710,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) reply_error(desc, &errInfo); return; } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, dt_utag, command, name, dt_s2, dt_i1, dt_i2, dt_i3, dt_i4, desc->port_str); @@ -2727,7 +2727,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d->flags = get_int32((uchar*)buf); name = buf+4; FILENAME_COPY(d->b, name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->flags; dt_s1 = d->b; dt_utag = name + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; @@ -2744,7 +2744,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data)); d->fd = fd; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = name; dt_i1 = fd; #endif @@ -2760,7 +2760,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data)); d->fd = fd; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = name; dt_i1 = fd; #endif @@ -2780,7 +2780,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_COPY(d->b, name); d->fd = fd; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = name + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; if (command == FILE_LSTAT) { dt_s1 = d->b; @@ -2801,7 +2801,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d->flags = desc->flags; d->fd = fd; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = name; dt_i1 = fd; dt_i2 = d->flags; @@ -2826,7 +2826,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d->info.cTime = (time_t)((Sint64)get_int64(buf + 7 * 4)); FILENAME_COPY(d->b, buf + 9*4); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->info.mode; dt_i2 = d->info.uid; dt_i3 = d->info.gid; @@ -2845,7 +2845,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); FILENAME_COPY(d->b, name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_utag = name + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; #endif @@ -2860,7 +2860,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) { d = EF_SAFE_ALLOC(sizeof(struct t_data) - 1 + RESBUFSIZE + 1); FILENAME_COPY(d->b, name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_utag = name + FILENAME_BYTELEN(d->b) + FILENAME_CHARSIZE; #endif @@ -2884,7 +2884,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_COPY(d->b, name); FILENAME_COPY(d->b + namelen, new_name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_s2 = d->b + namelen; dt_utag = buf + namelen + FILENAME_BYTELEN(dt_s2) + FILENAME_CHARSIZE; @@ -2910,7 +2910,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) FILENAME_COPY(d->b, name); FILENAME_COPY(d->b + namelen, new_name); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_s1 = d->b; dt_s2 = d->b + namelen; dt_utag = buf + namelen + FILENAME_BYTELEN(dt_s2) + FILENAME_CHARSIZE; @@ -2936,7 +2936,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) d->c.fadvise.offset = get_int64((uchar*) buf); d->c.fadvise.length = get_int64(((uchar*) buf) + sizeof(Sint64)); d->c.fadvise.advise = get_int32(((uchar*) buf) + 2 * sizeof(Sint64)); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->fd; dt_i2 = d->c.fadvise.offset; dt_i3 = d->c.fadvise.length; @@ -2956,7 +2956,7 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) done: if (d) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES d->sched_i1 = dt_priv->thread_num; d->sched_i2 = dt_priv->tag; d->sched_utag[0] = '\0'; @@ -2985,7 +2985,7 @@ file_flush(ErlDrvData e) { #ifdef DEBUG int r; #endif -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); #endif @@ -2999,7 +2999,7 @@ file_flush(ErlDrvData e) { r = #endif flush_write(desc, NULL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, (desc->d == NULL) ? NULL : desc->d->sched_utag #endif ); @@ -3044,7 +3044,7 @@ static void file_timeout(ErlDrvData e) { file_descriptor *desc = (file_descriptor *)e; enum e_timer timer_state = desc->timer_state; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_private *dt_priv = get_dt_private(dt_driver_io_worker_base); #endif @@ -3065,7 +3065,7 @@ file_timeout(ErlDrvData e) { int r = #endif flush_write(desc, NULL -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, (desc->d == NULL) ? NULL : desc->d->sched_utag #endif ); @@ -3090,7 +3090,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { int p, q; int err; struct t_data *d = NULL; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES Sint64 dt_i1 = 0, dt_i2 = 0, dt_i3 = 0; Sint64 dt_i4 = 0; char *dt_utag = NULL; @@ -3116,12 +3116,12 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { switch (command) { case FILE_CLOSE: { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = EV_CHAR_P(ev, p, q); #endif flush_read(desc); if (flush_write_check_error(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3136,7 +3136,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->reply = !0; d->fd = desc->fd; d->flags = desc->flags; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->fd; dt_i2 = d->flags; #endif @@ -3162,11 +3162,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = EV_CHAR_P(ev, p, q); #endif if (flush_write_check_error(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3178,7 +3178,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { /* We have allocated a buffer for line mode but should not really have a read-ahead buffer... */ if (lseek_flush_read(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3262,7 +3262,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->c.read.bin_offset = desc->read_offset + desc->read_size; d->c.read.bin_size = desc->read_binp->orig_size - d->c.read.bin_offset; d->c.read.size = size; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->fd; dt_i2 = d->flags; dt_i3 = d->c.read.size; @@ -3284,11 +3284,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { * allocated binary + dealing with offsets and lengts are done in file_async ready * for this OP. */ -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = EV_CHAR_P(ev, p, q); #endif if (flush_write_check_error(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3296,7 +3296,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (ev->size != 1 -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + FILENAME_BYTELEN(dt_utag) + FILENAME_CHARSIZE #endif ) { @@ -3355,14 +3355,14 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->c.read_line.binp = desc->read_binp; d->c.read_line.read_offset = desc->read_offset; d->c.read_line.read_size = desc->read_size; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->fd; dt_i2 = d->flags; dt_i3 = d->c.read_line.read_offset; #endif #if !ALWAYS_READ_LINE_AHEAD d->c.read_line.read_ahead = (desc->read_bufsize > 0); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i4 = d->c.read_line.read_ahead; #endif #endif @@ -3378,13 +3378,13 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { ErlDrvSizeT skip = 1; ErlDrvSizeT size = ev->size - skip; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = EV_CHAR_P(ev, p, q); skip += FILENAME_BYTELEN(dt_utag) + FILENAME_CHARSIZE; size = ev->size - skip; #endif if (lseek_flush_read(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3415,7 +3415,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } } else { if ((d = async_write(desc, &err, !0, size -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , &dt_i1, &dt_i2, &dt_i3 #endif )) == NULL) { @@ -3433,7 +3433,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { This is handled specially in prim_file.erl */ Uint32 i, j, n; size_t total; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES char dt_tmp; int dt_utag_bytes = 1; @@ -3447,7 +3447,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } #endif if (ev->size < 1+4 -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + dt_utag_bytes #endif || !EV_GET_UINT32(ev, &n, &p, &q)) { @@ -3456,7 +3456,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (lseek_flush_read(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3464,7 +3464,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (flush_write_check_error(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3481,7 +3481,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (ev->size < 1+4+8*(2*n) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + dt_utag_bytes #endif ) { @@ -3499,7 +3499,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->reply = !0; d->fd = desc->fd; d->flags = desc->flags; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->fd; dt_i2 = d->flags; #endif @@ -3540,7 +3540,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } } d->c.pwritev.size = total; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i3 = d->c.pwritev.size; #endif d->c.pwritev.free_size = 0; @@ -3550,7 +3550,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_Uint(desc, 0); } else { ErlDrvSizeT skip = 1 + 4 + 8 * (2*n) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + dt_utag_bytes #endif ; @@ -3580,7 +3580,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { register void * void_ptr; Uint32 i, n; ErlIOVec *res_ev; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES char dt_tmp; int dt_utag_bytes = 1; /* This will work for UTF-8, but not for UTF-16 - extra reminder here */ @@ -3593,7 +3593,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } #endif if (lseek_flush_read(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3601,7 +3601,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (flush_write_check_error(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3609,7 +3609,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (ev->size < 1+8 -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + dt_utag_bytes #endif || !EV_GET_UINT32(ev, &n, &p, &q) @@ -3619,7 +3619,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (ev->size < 1+8+8*(2*n) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + dt_utag_bytes #endif ) { @@ -3642,7 +3642,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->reply = !0; d->fd = desc->fd; d->flags = desc->flags; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->fd; dt_i2 = d->flags; #endif @@ -3673,7 +3673,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else size = ((size_t)sizeH<<32) | sizeL; #endif -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i3 += size; #endif if (! (res_ev->binv[i] = driver_alloc_binary(size))) { @@ -3732,11 +3732,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = EV_CHAR_P(ev, p, q); #endif if (lseek_flush_read(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3744,7 +3744,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (flush_write_check_error(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3752,7 +3752,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if ((d = async_lseek(desc, &err, !0, offset, origin -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , &dt_i1, &dt_i2, &dt_i3 #endif )) == NULL) { @@ -3768,7 +3768,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, ENOENT); goto done; } -#ifndef HAVE_DTRACE +#ifndef USE_VM_PROBES /* In the dtrace case, the iov has an extra element, the dtrace utag - we will need another test to see that the filename is in a single buffer: */ @@ -3794,7 +3794,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->reply = !0; /* Copy name */ FILENAME_COPY(d->b, filename); -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES { char dt_tmp; @@ -3848,11 +3848,11 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_utag = EV_CHAR_P(ev, p, q); #endif if (lseek_flush_read(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3860,7 +3860,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (flush_write_check_error(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -3883,7 +3883,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->flags = desc->flags; d->c.preadv.offsets[0] = hdr_offset; d->c.preadv.size = max_size; -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = d->fd; dt_i2 = d->flags; dt_i3 = d->c.preadv.offsets[0]; @@ -3910,7 +3910,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { reply_posix_error(desc, EINVAL); goto done; } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i1 = opt; dt_utag = EV_CHAR_P(ev, p, q); #endif @@ -3918,7 +3918,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_OPT_DELAYED_WRITE: { Uint32 sizeH, sizeL, delayH, delayL; if (ev->size != 1+1+4*sizeof(Uint32) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + FILENAME_BYTELEN(dt_utag) + FILENAME_CHARSIZE #endif || !EV_GET_UINT32(ev, &sizeH, &p, &q) @@ -3947,7 +3947,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else desc->write_delay = ((unsigned long)delayH << 32) | delayL; #endif -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i2 = desc->write_delay; #endif TRACE_C('K'); @@ -3956,7 +3956,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { case FILE_OPT_READ_AHEAD: { Uint32 sizeH, sizeL; if (ev->size != 1+1+2*sizeof(Uint32) -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES + FILENAME_BYTELEN(dt_utag)+FILENAME_CHARSIZE #endif || !EV_GET_UINT32(ev, &sizeH, &p, &q) @@ -3974,7 +3974,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #else desc->read_bufsize = ((size_t)sizeH << 32) | sizeL; #endif -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_i2 = desc->read_bufsize; #endif TRACE_C('K'); @@ -4064,7 +4064,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } /* switch(command) */ if (lseek_flush_read(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -4072,7 +4072,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { goto done; } if (flush_write_check_error(desc, &err -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES , dt_priv, dt_utag #endif ) < 0) { @@ -4094,7 +4094,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { done: if (d != NULL) { -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES /* * If d == NULL, then either: * 1). There was an error of some sort, or @@ -4119,7 +4119,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { cq_execute(desc); } -#ifdef HAVE_DTRACE +#ifdef USE_VM_PROBES dt_private * get_dt_private(int base) { @@ -4135,4 +4135,4 @@ get_dt_private(int base) } return dt_priv; } -#endif /* HAVE_DTRACE */ +#endif /* USE_VM_PROBES */ -- cgit v1.2.3 From db4ddca4d9709965121fba9a1f9cc68226f35a0c Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Mon, 5 Mar 2012 17:29:03 +0100 Subject: Correct some errors in the user tag spreading --- erts/emulator/beam/beam_emu.c | 2 +- erts/emulator/beam/dist.c | 4 ++-- erts/emulator/beam/erl_message.c | 6 +++--- erts/emulator/drivers/common/efile_drv.c | 18 +++++++++++++----- erts/preloaded/ebin/prim_file.beam | Bin 38764 -> 38764 bytes lib/dtrace/examples/user-probe.systemtap | 4 ++-- lib/kernel/src/file.erl | 11 ++++++----- lib/kernel/src/file_io_server.erl | 3 +++ 8 files changed, 30 insertions(+), 18 deletions(-) diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 763d15e101..8cfcbd0fb8 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1963,7 +1963,7 @@ void process_main(void) dtrace_proc_str(c_p, receiver_name); token2 = SEQ_TRACE_TOKEN(c_p); - if (token2 != NIL) { + if (token2 != NIL && token2 != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(token2)); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token2)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token2)); diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index a44caa36db..e93176ba4e 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -769,7 +769,7 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id); erts_snprintf(receiver_name, sizeof(receiver_name), "%T", remote); msize = size_object(message); - if (token != NIL) { + if (token != NIL && token != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); @@ -823,7 +823,7 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) erts_snprintf(receiver_name, sizeof(receiver_name), "{%T,%s}", remote_name, node_name); msize = size_object(message); - if (token != NIL) { + if (token != NIL && token != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 5d4dcaef6d..7de30d25ed 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -384,7 +384,7 @@ erts_queue_dist_message(Process *rcvr, DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(rcvr, receiver_name); - if (token != NIL) { + if (token != NIL && token != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); @@ -419,7 +419,7 @@ erts_queue_dist_message(Process *rcvr, DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(rcvr, receiver_name); - if (token != NIL) { + if (token != NIL && token != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(token)); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(token)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); @@ -957,7 +957,7 @@ erts_send_message(Process* sender, BM_SWAP_TIMER(copy,send); if (DTRACE_ENABLED(message_send)) { - if (stoken != NIL) { + if (stoken != NIL && stoken != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(stoken)); tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(stoken)); tok_serial = signed_val(SEQ_TRACE_T_SERIAL(stoken)); diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 53cdb13db0..b33a8d210b 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -2711,9 +2711,15 @@ file_output(ErlDrvData e, char* buf, ErlDrvSizeT count) return; } #ifdef USE_VM_PROBES - DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, + if (dt_utag != NULL && dt_utag[0] == '\0') { + dt_utag = NULL; + } + + DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag, dt_utag, command, name, dt_s2, dt_i1, dt_i2, dt_i3, dt_i4, desc->port_str); + DTRACE6(efile_drv_return, dt_priv->thread_num, dt_priv->tag++, + dt_utag, command, 1, 0); #endif TRACE_C('R'); driver_output2(desc->port, resbuf, 1, NULL, 0); @@ -3806,8 +3812,6 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { ; dt_s1 = d->b; dt_utag = EV_CHAR_P(ev, p, q); - if (*dt_utag != 0) - fprintf(stderr,"dt_utag = %s\r\n",dt_utag); } #endif d->c.read_file.binp = NULL; @@ -4108,8 +4112,12 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { d->sched_i2 = dt_priv->tag; d->sched_utag[0] = '\0'; if (dt_utag != NULL) { - strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); - d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + if (dt_utag[0] == '\0') { + dt_utag = NULL; + } else { + strncpy(d->sched_utag, dt_utag, sizeof(d->sched_utag) - 1); + d->sched_utag[sizeof(d->sched_utag) - 1] = '\0'; + } } DTRACE11(efile_drv_entry, dt_priv->thread_num, dt_priv->tag++, dt_utag, command, dt_s1, NULL, dt_i1, dt_i2, dt_i3, dt_i4, diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index 88c07ab4eb..ea6d2cb8c6 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/lib/dtrace/examples/user-probe.systemtap b/lib/dtrace/examples/user-probe.systemtap index c80bf94697..84a45709e8 100644 --- a/lib/dtrace/examples/user-probe.systemtap +++ b/lib/dtrace/examples/user-probe.systemtap @@ -28,12 +28,12 @@ * environment. */ -probe process("dtrace.so").mark("user_trace-s1") +probe process("dyntrace.so").mark("user_trace-s1") { printf("%s\n", user_string($arg1)); } -probe process("dtrace.so").mark("user_trace-i4s4") +probe process("dyntrace.so").mark("user_trace-i4s4") { printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", user_string($arg1), diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 3a618976f5..b281151778 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1416,15 +1416,16 @@ mode_list(_) -> %% Functions for communicating with the file server call(Command, Args) when is_list(Args) -> - gen_server:call(?FILE_SERVER, list_to_tuple([Command | Args]), infinity). + X = erlang:spread_utag(true), + Y = gen_server:call(?FILE_SERVER, list_to_tuple([Command | Args]), + infinity), + erlang:restore_utag(X), + Y. check_and_call(Command, Args) when is_list(Args) -> case check_args(Args) of ok -> - X = erlang:spread_utag(true), - Y = call(Command, Args), - erlang:restore_utag(X), - Y; + call(Command, Args); Error -> Error end. diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index 14da9c1a55..6369a5250c 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -57,9 +57,11 @@ start_link(Owner, FileName, ModeList) do_start(Spawn, Owner, FileName, ModeList) -> Self = self(), Ref = make_ref(), + Utag = erlang:spread_utag(true), Pid = erlang:Spawn( fun() -> + erlang:restore_utag(Utag), %% process_flag(trap_exit, true), case parse_options(ModeList) of {ReadMode, UnicodeMode, Opts} -> @@ -84,6 +86,7 @@ do_start(Spawn, Owner, FileName, ModeList) -> exit(Reason1) end end), + erlang:restore_utag(Utag), Mref = erlang:monitor(process, Pid), receive {Ref, {error, _Reason} = Error} -> -- cgit v1.2.3 From 0889c9860f5d07fc87db6bfc287b9a3ddc764aa1 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Thu, 8 Mar 2012 16:05:16 +0100 Subject: Move dtrace erlang code and NIF into runtime_tools Also make dyntrace NIF's load in on_load instead of init/0 --- erts/configure.in | 1 - lib/Makefile | 2 +- lib/dtrace/Makefile | 36 --- lib/dtrace/c_src/Makefile | 4 - lib/dtrace/c_src/Makefile.in | 151 ----------- lib/dtrace/c_src/dtrace.c | 168 ------------- lib/dtrace/c_src/dtrace_user.d | 53 ---- lib/dtrace/ebin/.placeholder | 0 lib/dtrace/examples/dist.d | 62 ----- lib/dtrace/examples/dist.systemtap | 76 ------ lib/dtrace/examples/driver1.d | 114 --------- lib/dtrace/examples/driver1.systemtap | 125 --------- lib/dtrace/examples/efile_drv.d | 104 -------- lib/dtrace/examples/efile_drv.systemtap | 112 --------- lib/dtrace/examples/function-calls.d | 51 ---- lib/dtrace/examples/function-calls.systemtap | 61 ----- lib/dtrace/examples/garbage-collection.d | 39 --- lib/dtrace/examples/garbage-collection.systemtap | 49 ---- lib/dtrace/examples/memory1.d | 41 --- lib/dtrace/examples/memory1.systemtap | 51 ---- lib/dtrace/examples/messages.d | 94 ------- lib/dtrace/examples/messages.systemtap | 87 ------- lib/dtrace/examples/port1.d | 142 ----------- lib/dtrace/examples/port1.systemtap | 152 ----------- lib/dtrace/examples/process-scheduling.d | 35 --- lib/dtrace/examples/process-scheduling.systemtap | 45 ---- lib/dtrace/examples/spawn-exit.d | 41 --- lib/dtrace/examples/spawn-exit.systemtap | 51 ---- lib/dtrace/examples/user-probe.d | 36 --- lib/dtrace/examples/user-probe.systemtap | 46 ---- lib/dtrace/src/Makefile | 102 -------- lib/dtrace/src/dtrace.app.src | 27 -- lib/dtrace/src/dtrace.appup.src | 19 -- lib/dtrace/src/dtrace.erl | 247 ------------------ lib/dtrace/vsn.mk | 1 - lib/runtime_tools/c_src/Makefile.in | 79 +++++- lib/runtime_tools/c_src/dtrace_user.d | 53 ++++ lib/runtime_tools/c_src/dyntrace.c | 172 +++++++++++++ lib/runtime_tools/examples/dist.d | 62 +++++ lib/runtime_tools/examples/dist.systemtap | 76 ++++++ lib/runtime_tools/examples/driver1.d | 114 +++++++++ lib/runtime_tools/examples/driver1.systemtap | 125 +++++++++ lib/runtime_tools/examples/efile_drv.d | 104 ++++++++ lib/runtime_tools/examples/efile_drv.systemtap | 112 +++++++++ lib/runtime_tools/examples/function-calls.d | 51 ++++ .../examples/function-calls.systemtap | 61 +++++ lib/runtime_tools/examples/garbage-collection.d | 39 +++ .../examples/garbage-collection.systemtap | 49 ++++ lib/runtime_tools/examples/memory1.d | 41 +++ lib/runtime_tools/examples/memory1.systemtap | 51 ++++ lib/runtime_tools/examples/messages.d | 94 +++++++ lib/runtime_tools/examples/messages.systemtap | 87 +++++++ lib/runtime_tools/examples/port1.d | 142 +++++++++++ lib/runtime_tools/examples/port1.systemtap | 152 +++++++++++ lib/runtime_tools/examples/process-scheduling.d | 35 +++ .../examples/process-scheduling.systemtap | 45 ++++ lib/runtime_tools/examples/spawn-exit.d | 41 +++ lib/runtime_tools/examples/spawn-exit.systemtap | 51 ++++ lib/runtime_tools/examples/user-probe.d | 36 +++ lib/runtime_tools/examples/user-probe.systemtap | 46 ++++ lib/runtime_tools/src/Makefile | 10 +- lib/runtime_tools/src/dyntrace.erl | 279 +++++++++++++++++++++ lib/runtime_tools/src/runtime_tools.app.src | 2 +- 63 files changed, 2202 insertions(+), 2432 deletions(-) delete mode 100644 lib/dtrace/Makefile delete mode 100644 lib/dtrace/c_src/Makefile delete mode 100644 lib/dtrace/c_src/Makefile.in delete mode 100644 lib/dtrace/c_src/dtrace.c delete mode 100644 lib/dtrace/c_src/dtrace_user.d delete mode 100644 lib/dtrace/ebin/.placeholder delete mode 100644 lib/dtrace/examples/dist.d delete mode 100644 lib/dtrace/examples/dist.systemtap delete mode 100644 lib/dtrace/examples/driver1.d delete mode 100644 lib/dtrace/examples/driver1.systemtap delete mode 100644 lib/dtrace/examples/efile_drv.d delete mode 100644 lib/dtrace/examples/efile_drv.systemtap delete mode 100644 lib/dtrace/examples/function-calls.d delete mode 100644 lib/dtrace/examples/function-calls.systemtap delete mode 100644 lib/dtrace/examples/garbage-collection.d delete mode 100644 lib/dtrace/examples/garbage-collection.systemtap delete mode 100644 lib/dtrace/examples/memory1.d delete mode 100644 lib/dtrace/examples/memory1.systemtap delete mode 100644 lib/dtrace/examples/messages.d delete mode 100644 lib/dtrace/examples/messages.systemtap delete mode 100644 lib/dtrace/examples/port1.d delete mode 100644 lib/dtrace/examples/port1.systemtap delete mode 100644 lib/dtrace/examples/process-scheduling.d delete mode 100644 lib/dtrace/examples/process-scheduling.systemtap delete mode 100644 lib/dtrace/examples/spawn-exit.d delete mode 100644 lib/dtrace/examples/spawn-exit.systemtap delete mode 100644 lib/dtrace/examples/user-probe.d delete mode 100644 lib/dtrace/examples/user-probe.systemtap delete mode 100644 lib/dtrace/src/Makefile delete mode 100644 lib/dtrace/src/dtrace.app.src delete mode 100644 lib/dtrace/src/dtrace.appup.src delete mode 100644 lib/dtrace/src/dtrace.erl delete mode 100644 lib/dtrace/vsn.mk create mode 100644 lib/runtime_tools/c_src/dtrace_user.d create mode 100644 lib/runtime_tools/c_src/dyntrace.c create mode 100644 lib/runtime_tools/examples/dist.d create mode 100644 lib/runtime_tools/examples/dist.systemtap create mode 100644 lib/runtime_tools/examples/driver1.d create mode 100644 lib/runtime_tools/examples/driver1.systemtap create mode 100644 lib/runtime_tools/examples/efile_drv.d create mode 100644 lib/runtime_tools/examples/efile_drv.systemtap create mode 100644 lib/runtime_tools/examples/function-calls.d create mode 100644 lib/runtime_tools/examples/function-calls.systemtap create mode 100644 lib/runtime_tools/examples/garbage-collection.d create mode 100644 lib/runtime_tools/examples/garbage-collection.systemtap create mode 100644 lib/runtime_tools/examples/memory1.d create mode 100644 lib/runtime_tools/examples/memory1.systemtap create mode 100644 lib/runtime_tools/examples/messages.d create mode 100644 lib/runtime_tools/examples/messages.systemtap create mode 100644 lib/runtime_tools/examples/port1.d create mode 100644 lib/runtime_tools/examples/port1.systemtap create mode 100644 lib/runtime_tools/examples/process-scheduling.d create mode 100644 lib/runtime_tools/examples/process-scheduling.systemtap create mode 100644 lib/runtime_tools/examples/spawn-exit.d create mode 100644 lib/runtime_tools/examples/spawn-exit.systemtap create mode 100644 lib/runtime_tools/examples/user-probe.d create mode 100644 lib/runtime_tools/examples/user-probe.systemtap create mode 100644 lib/runtime_tools/src/dyntrace.erl diff --git a/erts/configure.in b/erts/configure.in index 15ca2209b7..b94fe86dc7 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -4509,7 +4509,6 @@ dnl ../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in dnl ../lib/ssl/c_src/$host/Makefile:../lib/ssl/c_src/Makefile.in ../lib/crypto/c_src/$host/Makefile:../lib/crypto/c_src/Makefile.in - ../lib/dtrace/c_src/$host/Makefile:../lib/dtrace/c_src/Makefile.in ../lib/orber/c_src/$host/Makefile:../lib/orber/c_src/Makefile.in ../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in ../lib/tools/c_src/$host/Makefile:../lib/tools/c_src/Makefile.in diff --git a/lib/Makefile b/lib/Makefile index 96ce2d1315..aa4e074830 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -31,7 +31,7 @@ ifdef BUILD_ALL cosTransactions cosEvent cosTime cosNotification \ cosProperty cosFileTransfer cosEventDomain et megaco webtool \ xmerl edoc eunit ssh inviso typer erl_docgen \ - percept dialyzer dtrace hipe + percept dialyzer hipe EXTRA_FILE := $(wildcard EXTRA-APPLICATIONS) EXTRA_APPLICATIONS := $(if $(EXTRA_FILE),$(shell cat $(EXTRA_FILE))) endif diff --git a/lib/dtrace/Makefile b/lib/dtrace/Makefile deleted file mode 100644 index 29d463aab1..0000000000 --- a/lib/dtrace/Makefile +++ /dev/null @@ -1,36 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2002-2009. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# -# Macros -# - -SUB_DIRECTORIES = src c_src - -include vsn.mk -VSN = $(DTRACE_VSN) - -SPECIAL_TARGETS = - -# -# Default Subdir Targets -# -include $(ERL_TOP)/make/otp_subdir.mk diff --git a/lib/dtrace/c_src/Makefile b/lib/dtrace/c_src/Makefile deleted file mode 100644 index a65491d45d..0000000000 --- a/lib/dtrace/c_src/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# -# Invoke with GNU make -# -include $(ERL_TOP)/make/run_make.mk diff --git a/lib/dtrace/c_src/Makefile.in b/lib/dtrace/c_src/Makefile.in deleted file mode 100644 index 4d5f59a63d..0000000000 --- a/lib/dtrace/c_src/Makefile.in +++ /dev/null @@ -1,151 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Scott Lystig Fritchie 2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk -include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk - -# ---------------------------------------------------- -# Items from top-level configure -# ---------------------------------------------------- -DTRACE_ENABLED=@DTRACE_ENABLED@ -DTRACE_ENABLED_2STEP=@DTRACE_ENABLED_2STEP@ - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../vsn.mk -VSN=$(DTRACE_VSN) - -# ---------------------------------------------------- -# The following variables differ between systems. -# Set by configure. -# ---------------------------------------------------- -CC = $(DED_CC) -LD = $(DED_LD) -SHELL = /bin/sh -LIBS = $(DED_LIBS) -LDFLAGS += $(DED_LDFLAGS) -CFLAGS = $(DED_CFLAGS) - -DTRACE_LIBNAME = dtrace - - -INCLUDES = $(DED_INCLUDES) - -ifeq ($(TYPE),debug) -TYPEMARKER = .debug -TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DDEBUG -else -ifeq ($(TYPE),valgrind) -TYPEMARKER = .valgrind -TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DVALGRIND -else -TYPEMARKER = -TYPE_FLAGS = $(CFLAGS) -endif -endif - -ALL_CFLAGS = $(TYPE_FLAGS) $(INCLUDES) -I$(OBJDIR) \ - -I$(ERL_TOP)/erts/emulator/$(TARGET) - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/dtrace-$(VSN) - -# ---------------------------------------------------- -# Misc Macros -# ---------------------------------------------------- -before_DTrace_OBJS = $(OBJDIR)/dtrace$(TYPEMARKER).o -## NIF_MAKEFILE = $(PRIVDIR)/Makefile - -# Higher-level makefiles says that we can only compile on UNIX flavors -NIF_LIB = $(LIBDIR)/dtrace$(TYPEMARKER).@DED_EXT@ - -ifeq ($(HOST_OS),) -HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess) -endif - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug opt valgrind: $(OBJDIR) $(LIBDIR) $(NIF_LIB) - -ifdef DTRACE_ENABLED -DTRACE_USER_HEADER=$(OBJDIR)/dtrace_user.h -$(OBJDIR)/dtrace_user.h: ./dtrace_user.d - dtrace -h -C $(INCLUDES) \ - -s ./dtrace_user.d \ - -o ./dtrace_user.tmp - sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./dtrace_user.tmp > $@ - rm ./dtrace_user.tmp -else -DTRACE_USER_HEADER= -endif - -DTRACE_OBJS = -ifdef DTRACE_ENABLED_2STEP -DTRACE_OBJS += $(OBJDIR)/dtrace_user.o -$(OBJDIR)/dtrace_user.o: $(before_DTrace_OBJS) $(OBJDIR)/dtrace_user.h - dtrace -G -C \ - -s ./dtrace_user.d \ - -o $@ $(before_DTrace_OBJS) -endif - -OBJS = $(before_DTrace_OBJS) $(DTRACE_OBJS) - -$(OBJDIR): - -@mkdir -p $(OBJDIR) - -$(LIBDIR): - -@mkdir -p $(LIBDIR) - -$(OBJDIR)/%$(TYPEMARKER).o: %.c $(DTRACE_USER_HEADER) - $(INSTALL_DIR) $(OBJDIR) - $(CC) -c -o $@ $(ALL_CFLAGS) $< - -$(NIF_LIB): $(OBJS) - $(INSTALL_DIR) $(LIBDIR) - $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) - -clean: - rm -f $(LIBDIR)/dtrace.@DED_EXT@ - rm -f $(LIBDIR)/dtrace.debug.@DED_EXT@ - rm -f $(LIBDIR)/dtrace.valgrind.@DED_EXT@ - rm -f $(OBJDIR)/dtrace.o - rm -f $(OBJDIR)/dtrace.debug.o - rm -f $(OBJDIR)/dtrace.valgrind.o - rm -f core *~ - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/priv/obj - $(INSTALL_DIR) $(RELSYSDIR)/priv/lib - # $(INSTALL_DATA) $(NIF_MAKEFILE) $(RELSYSDIR)/priv/obj - $(INSTALL_PROGRAM) $(OBJS) $(RELSYSDIR)/priv/obj - $(INSTALL_PROGRAM) $(NIF_LIB) $(RELSYSDIR)/priv/lib - -release_docs_spec: diff --git a/lib/dtrace/c_src/dtrace.c b/lib/dtrace/c_src/dtrace.c deleted file mode 100644 index 90bb39a4b8..0000000000 --- a/lib/dtrace/c_src/dtrace.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -/* - * Purpose: Dynamically loadable NIF library for DTrace - */ - - -#include "erl_nif.h" -#include "config.h" -#include "sys.h" -#include "dtrace-wrapper.h" -#ifdef HAVE_DTRACE -#include "dtrace_user.h" -#endif - -void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf); -void get_string_maybe(ErlNifEnv *env, const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz); - -#ifdef VALGRIND - # include -#endif - -#ifdef __GNUC__ - # define INLINE __inline__ -#else - # define INLINE -#endif - -#define MESSAGE_BUFSIZ 1024 - -/* NIF interface declarations */ -static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); - -/* The NIFs: */ -static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); -static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); - -static ErlNifFunc nif_funcs[] = { - {"available", 0, available}, - {"user_trace_s1", 1, user_trace_s1}, - {"user_trace_i4s4", 9, user_trace_i4s4} -}; - -ERL_NIF_INIT(dtrace, nif_funcs, load, NULL, NULL, NULL) - -static ERL_NIF_TERM atom_true; -static ERL_NIF_TERM atom_false; -static ERL_NIF_TERM atom_error; -static ERL_NIF_TERM atom_not_available; -static ERL_NIF_TERM atom_badarg; -static ERL_NIF_TERM atom_ok; - -static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) -{ - atom_true = enif_make_atom(env,"true"); - atom_false = enif_make_atom(env,"false"); - atom_error = enif_make_atom(env,"error"); - atom_not_available = enif_make_atom(env,"not_available"); - atom_badarg = enif_make_atom(env,"badarg"); - atom_ok = enif_make_atom(env,"ok"); - - return 0; -} - -static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ -#ifdef HAVE_DTRACE - return atom_true; -#else - return atom_false; -#endif -} - -static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ -#ifdef HAVE_DTRACE - ErlNifBinary message_bin; - DTRACE_CHARBUF(messagebuf, MESSAGE_BUFSIZ + 1); - - if (DTRACE_ENABLED(user_trace_s1)) { - if (!enif_inspect_iolist_as_binary(env, argv[0], &message_bin) || - message_bin.size > MESSAGE_BUFSIZ) { - return atom_badarg; - } - memcpy(messagebuf, (char *) message_bin.data, message_bin.size); - messagebuf[message_bin.size] = '\0'; - DTRACE1(user_trace_s1, messagebuf); - return atom_true; - } else { - return atom_false; - } -#else - return atom_error; -#endif -} - -void -get_string_maybe(ErlNifEnv *env, - const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz) -{ - ErlNifBinary str_bin; - - if (!enif_inspect_iolist_as_binary(env, term, &str_bin) || - str_bin.size > bufsiz) { - *ptr = NULL; - } else { - memcpy(buf, (char *) str_bin.data, str_bin.size); - buf[str_bin.size] = '\0'; - *ptr = buf; - } -} - -static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) -{ -#ifdef HAVE_DTRACE - DTRACE_CHARBUF(procbuf, 32 + 1); - DTRACE_CHARBUF(user_tagbuf, MESSAGE_BUFSIZ + 1); - char *utbuf = NULL; - ErlNifSInt64 i1, i2, i3, i4; - DTRACE_CHARBUF(messagebuf1, MESSAGE_BUFSIZ + 1); - DTRACE_CHARBUF(messagebuf2, MESSAGE_BUFSIZ + 1); - DTRACE_CHARBUF(messagebuf3, MESSAGE_BUFSIZ + 1); - DTRACE_CHARBUF(messagebuf4, MESSAGE_BUFSIZ + 1); - char *mbuf1 = NULL, *mbuf2 = NULL, *mbuf3 = NULL, *mbuf4 = NULL; - - if (DTRACE_ENABLED(user_trace_i4s4)) { - dtrace_nifenv_str(env, procbuf); - get_string_maybe(env, argv[0], &utbuf, user_tagbuf, MESSAGE_BUFSIZ); - if (! enif_get_int64(env, argv[1], &i1)) - i1 = 0; - if (! enif_get_int64(env, argv[2], &i2)) - i2 = 0; - if (! enif_get_int64(env, argv[3], &i3)) - i3 = 0; - if (! enif_get_int64(env, argv[4], &i4)) - i4 = 0; - get_string_maybe(env, argv[5], &mbuf1, messagebuf1, MESSAGE_BUFSIZ); - get_string_maybe(env, argv[6], &mbuf2, messagebuf2, MESSAGE_BUFSIZ); - get_string_maybe(env, argv[7], &mbuf3, messagebuf3, MESSAGE_BUFSIZ); - get_string_maybe(env, argv[8], &mbuf4, messagebuf4, MESSAGE_BUFSIZ); - DTRACE10(user_trace_i4s4, procbuf, utbuf, - i1, i2, i3, i4, mbuf1, mbuf2, mbuf3, mbuf4); - return atom_true; - } else { - return atom_false; - } -#else - return atom_error; -#endif -} diff --git a/lib/dtrace/c_src/dtrace_user.d b/lib/dtrace/c_src/dtrace_user.d deleted file mode 100644 index 45d3ef3b66..0000000000 --- a/lib/dtrace/c_src/dtrace_user.d +++ /dev/null @@ -1,53 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. - * All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -provider erlang { - /** - * Send a single string to a probe. - * - * @param NUL-terminated string - */ - probe user_trace__s1(char* message); - - /** - * Multi-purpose probe: up to 4 NUL-terminated strings and 4 - * 64-bit integer arguments. - * - * @param proc, the PID (string form) of the sending process - * @param user_tag, the user tag of the sender - * @param i1, integer - * @param i2, integer - * @param i3, integer - * @param i4, integer - * @param s1, string/iolist. D's arg6 is NULL if not given by Erlang - * @param s2, string/iolist. D's arg7 is NULL if not given by Erlang - * @param s3, string/iolist. D's arg8 is NULL if not given by Erlang - * @param s4, string/iolist. D's arg9 is NULL if not given by Erlang - */ - probe user_trace__i4s4(char *proc, char *user_tag, - int i1, int i2, int i3, int i4, - char *s1, char *s2, char *s3, char *s4); -}; - -#pragma D attributes Evolving/Evolving/Common provider erlang provider -#pragma D attributes Private/Private/Common provider erlang module -#pragma D attributes Private/Private/Common provider erlang function -#pragma D attributes Evolving/Evolving/Common provider erlang name -#pragma D attributes Evolving/Evolving/Common provider erlang args diff --git a/lib/dtrace/ebin/.placeholder b/lib/dtrace/ebin/.placeholder deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/lib/dtrace/examples/dist.d b/lib/dtrace/examples/dist.d deleted file mode 100644 index 550e10d363..0000000000 --- a/lib/dtrace/examples/dist.d +++ /dev/null @@ -1,62 +0,0 @@ -/* example usage: dtrace -q -s /path/to/dist.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -erlang*:::dist-monitor -{ - printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", - pid, - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3), - copyinstr(arg4)); -} - -erlang*:::dist-port_busy -{ - printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); - /* - * For variable use advice, see: - * http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types/ - * - * Howevever, it's quite possible for the blocked events to span - * threads, so we'll use globals. - */ - blocked_procs[copyinstr(arg3)] = timestamp; -} - -erlang*:::dist-output -{ - printf("dist output: node %s, port %s, remote_node %s bytes %d\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); -} - -erlang*:::dist-outputv -{ - printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); -} - -erlang*:::process-scheduled -/blocked_procs[copyinstr(arg0)]/ -{ - pidstr = copyinstr(arg0); - printf("blocked pid %s scheduled now, waited %d microseconds\n", - pidstr, (timestamp - blocked_procs[pidstr]) / 1000); - blocked_procs[pidstr] = 0; -} diff --git a/lib/dtrace/examples/dist.systemtap b/lib/dtrace/examples/dist.systemtap deleted file mode 100644 index af27b2cab6..0000000000 --- a/lib/dtrace/examples/dist.systemtap +++ /dev/null @@ -1,76 +0,0 @@ -/* example usage: stap /path/to/dist.systemtap -x */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe process("beam").mark("dist-monitor") -{ - printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", - pid(), - user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4), - user_string($arg5)); -} - -probe process("beam").mark("dist-port_busy") -{ - printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", - user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); - blocked_procs[user_string($arg4)] = timestamp; -} - -probe process("beam").mark("dist-port_busy") -{ - printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", - user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); - blocked_procs[user_string($arg4)] = timestamp; -} - -probe process("beam").mark("dist-output") -{ - printf("dist output: node %s, port %s, remote_node %s bytes %d\n", - user_string($arg1), user_string($arg2), user_string($arg3), $arg4); -} - -probe process("beam").mark("dist-outputv") -{ - printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", - user_string($arg1), user_string($arg2), user_string($arg3), $arg4); -} - -probe process("beam").mark("process-scheduled") -{ - pidstr = user_string($arg1); - if (pidstr in blocked_procs) { - printf("blocked pid %s scheduled now, waited %d microseconds\n", - pidstr, (timestamp - blocked_procs[pidstr]) / 1000); - delete blocked_procs[pidstr]; - } -} - -global blocked_procs; diff --git a/lib/dtrace/examples/driver1.d b/lib/dtrace/examples/driver1.d deleted file mode 100644 index 9f53ffeb2a..0000000000 --- a/lib/dtrace/examples/driver1.d +++ /dev/null @@ -1,114 +0,0 @@ -/* example usage: dtrace -q -s /path/to/driver1.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -erlang*:::driver-init -{ - printf("driver init name %s major %d minor %d flags %d\n", - copyinstr(arg0), arg1, arg2, arg3); -} - -erlang*:::driver-start -{ - printf("driver start pid %s driver name %s port %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-stop -{ - printf("driver stop pid %s driver name %s port %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-finish -{ - printf("driver finish driver name %s port %s\n", - copyinstr(arg0), copyinstr(arg1)); -} - -erlang*:::driver-flush -{ - printf("driver flush pid %s port %s port name %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-output -{ - printf("driver output pid %s port %s port name %s bytes %d\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); -} - -erlang*:::driver-outputv -{ - printf("driver outputv pid %s port %s port name %s bytes %d\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); -} - -erlang*:::driver-control -{ - printf("driver control pid %s port %s port name %s command %d bytes %d\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, arg4); -} - -erlang*:::driver-call -{ - printf("driver call pid %s port %s port name %s command %d bytes %d\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, arg4); -} - -erlang*:::driver-event -{ - printf("driver event pid %s port %s port name %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-ready_input -{ - printf("driver ready_input pid %s port %s port name %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-ready_output -{ - printf("driver ready_output pid %s port %s port name %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-timeout -{ - printf("driver timeout pid %s port %s port name %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-ready_async -{ - printf("driver ready_async pid %s port %s port name %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-process_exit -{ - printf("driver process_exit pid %s port %s port name %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::driver-stop_select -{ - printf("driver stop_select driver name %s\n", copyinstr(arg0)); -} diff --git a/lib/dtrace/examples/driver1.systemtap b/lib/dtrace/examples/driver1.systemtap deleted file mode 100644 index 8b99e465b7..0000000000 --- a/lib/dtrace/examples/driver1.systemtap +++ /dev/null @@ -1,125 +0,0 @@ -/* example usage: stap /path/to/driver1.systemtap -x */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe process("beam").mark("driver-init") -{ - printf("driver init name %s major %d minor %d flags %d\n", - user_string($arg1), $arg2, $arg3, $arg4); -} - -probe process("beam").mark("driver-start") -{ - printf("driver start pid %s driver name %s port %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-stop") -{ - printf("driver stop pid %s driver name %s port %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-finish") -{ - printf("driver finish driver name %s\n", - user_string($arg1)); -} - -probe process("beam").mark("driver-flush") -{ - printf("driver flush pid %s port %s port name %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-output") -{ - printf("driver output pid %s port %s port name %s bytes %d\n", - user_string($arg1), user_string($arg2), user_string($arg3), $arg4); -} - -probe process("beam").mark("driver-outputv") -{ - printf("driver outputv pid %s port %s port name %s bytes %d\n", - user_string($arg1), user_string($arg2), user_string($arg3), $arg4); -} - -probe process("beam").mark("driver-control") -{ - printf("driver control pid %s port %s port name %s command %d bytes %d\n", - user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); -} - -probe process("beam").mark("driver-call") -{ - printf("driver call pid %s port %s port name %s command %d bytes %d\n", - user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); -} - -probe process("beam").mark("driver-event") -{ - printf("driver event pid %s port %s port name %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-ready_input") -{ - printf("driver ready_input pid %s port %s port name %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-ready_output") -{ - printf("driver ready_output pid %s port %s port name %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-timeout") -{ - printf("driver timeout pid %s port %s port name %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-ready_async") -{ - printf("driver ready_async pid %s port %s port name %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-process_exit") -{ - printf("driver process_exit pid %s port %s port name %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("driver-stop_select") -{ - printf("driver stop_select driver name %s\n", user_string($arg1)); -} diff --git a/lib/dtrace/examples/efile_drv.d b/lib/dtrace/examples/efile_drv.d deleted file mode 100644 index 085995ce58..0000000000 --- a/lib/dtrace/examples/efile_drv.d +++ /dev/null @@ -1,104 +0,0 @@ -/* example usage: dtrace -q -s /path/to/efile_drv.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -BEGIN -{ - op_map[1] = "OPEN"; - op_map[2] = "READ"; - op_map[3] = "LSEEK"; - op_map[4] = "WRITE"; - op_map[5] = "FSTAT"; - op_map[6] = "PWD"; - op_map[7] = "READDIR"; - op_map[8] = "CHDIR"; - op_map[9] = "FSYNC"; - op_map[10] = "MKDIR"; - op_map[11] = "DELETE"; - op_map[12] = "RENAME"; - op_map[13] = "RMDIR"; - op_map[14] = "TRUNCATE"; - op_map[15] = "READ_FILE"; - op_map[16] = "WRITE_INFO"; - op_map[19] = "LSTAT"; - op_map[20] = "READLINK"; - op_map[21] = "LINK"; - op_map[22] = "SYMLINK"; - op_map[23] = "CLOSE"; - op_map[24] = "PWRITEV"; - op_map[25] = "PREADV"; - op_map[26] = "SETOPT"; - op_map[27] = "IPREAD"; - op_map[28] = "ALTNAME"; - op_map[29] = "READ_LINE"; - op_map[30] = "FDATASYNC"; - op_map[31] = "FADVISE"; -} - -erlang*:::aio_pool-add -{ - printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1); -} - -erlang*:::aio_pool-get -{ - printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1); -} - -erlang*:::efile_drv-entry -{ - printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n", - arg0, arg1, - arg2 == NULL ? "" : "user tag ", - arg2 == NULL ? "" : copyinstr(arg2), - op_map[arg3], arg3, - arg4 == NULL ? "" : copyinstr(arg4), - arg5 == NULL ? "" : copyinstr(arg5), arg6, arg7, - /* NOTE: port name in args[10] is experimental */ - (args[10] == NULL) ? - "?" : copyinstr((user_addr_t) args[10])); -} - -erlang*:::efile_drv-int* -{ - printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n", - arg0, arg1, op_map[arg2], arg2, probename); -} - -/* efile_drv-return error case */ -erlang*:::efile_drv-return -/arg4 == 0/ -{ - printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n", - arg0, arg1, - arg2 == NULL ? "" : "user tag ", - arg2 == NULL ? "" : copyinstr(arg2), - op_map[arg3], arg3, - arg5); -} - -/* efile_drv-return success case */ -erlang*:::efile_drv-return -/arg4 != 0/ -{ - printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n", - arg0, arg1, - arg2 == NULL ? "" : copyinstr(arg2), - op_map[arg3], arg3); -} diff --git a/lib/dtrace/examples/efile_drv.systemtap b/lib/dtrace/examples/efile_drv.systemtap deleted file mode 100644 index 5a47b3e22b..0000000000 --- a/lib/dtrace/examples/efile_drv.systemtap +++ /dev/null @@ -1,112 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe begin -{ - op_map[1] = "OPEN"; - op_map[2] = "READ"; - op_map[3] = "LSEEK"; - op_map[4] = "WRITE"; - op_map[5] = "FSTAT"; - op_map[6] = "PWD"; - op_map[7] = "READDIR"; - op_map[8] = "CHDIR"; - op_map[9] = "FSYNC"; - op_map[10] = "MKDIR"; - op_map[11] = "DELETE"; - op_map[12] = "RENAME"; - op_map[13] = "RMDIR"; - op_map[14] = "TRUNCATE"; - op_map[15] = "READ_FILE"; - op_map[16] = "WRITE_INFO"; - op_map[19] = "LSTAT"; - op_map[20] = "READLINK"; - op_map[21] = "LINK"; - op_map[22] = "SYMLINK"; - op_map[23] = "CLOSE"; - op_map[24] = "PWRITEV"; - op_map[25] = "PREADV"; - op_map[26] = "SETOPT"; - op_map[27] = "IPREAD"; - op_map[28] = "ALTNAME"; - op_map[29] = "READ_LINE"; - op_map[30] = "FDATASYNC"; - op_map[31] = "FADVISE"; -} - -probe process("beam").mark("aio_pool-add") -{ - printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2); -} - -probe process("beam").mark("aio_pool-get") -{ - printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2); -} - -probe process("beam").mark("efile_drv-entry") -{ - printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n", - $arg1, $arg2, - $arg3 == NULL ? "" : "user tag ", - $arg3 == NULL ? "" : user_string($arg3), - op_map[$arg4], $arg4, - $arg5 == NULL ? "" : user_string($arg5), - $arg6 == NULL ? "" : user_string($arg6), $arg7, $arg8, - /* NOTE: port name in $arg[11] is experimental */ - user_string($arg11)) -} - -probe process("beam").mark("efile_drv-int*") -{ - printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n", - $arg1, $arg2, op_map[$arg3], $arg3, probefunc()); -} - -probe process("beam").mark("efile_drv-return") -{ - if ($arg5 == 0) { - /* efile_drv-return error case */ - printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n", - $arg1, $arg2, - $arg3 == NULL ? "" : "user tag ", - $arg3 == NULL ? "" : user_string($arg3), - op_map[$arg4], $arg4, - $arg6); - } else { - /* efile_drv-return success case */ - printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n", - $arg1, $arg2, - $arg3 == NULL ? "" : user_string($arg3), - op_map[$arg4], $arg4); - } -} - -global op_map; diff --git a/lib/dtrace/examples/function-calls.d b/lib/dtrace/examples/function-calls.d deleted file mode 100644 index 238c5211ac..0000000000 --- a/lib/dtrace/examples/function-calls.d +++ /dev/null @@ -1,51 +0,0 @@ -/* example usage: dtrace -q -s /path/to/function-calls.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -erlang*:::function-entry -{ - printf("pid %s enter %s depth %d\n", - copyinstr(arg0), copyinstr(arg1), arg2); -} - -erlang*:::function-return -{ - printf("pid %s return %s depth %d\n", - copyinstr(arg0), copyinstr(arg1), arg2); -} - -erlang*:::bif-entry -{ - printf("pid %s BIF entry mfa %s\n", copyinstr(arg0), copyinstr(arg1)); -} - -erlang*:::bif-return -{ - printf("pid %s BIF return mfa %s\n", copyinstr(arg0), copyinstr(arg1)); -} - -erlang*:::nif-entry -{ - printf("pid %s NIF entry mfa %s\n", copyinstr(arg0), copyinstr(arg1)); -} - -erlang*:::nif-return -{ - printf("pid %s NIF return mfa %s\n", copyinstr(arg0), copyinstr(arg1)); -} diff --git a/lib/dtrace/examples/function-calls.systemtap b/lib/dtrace/examples/function-calls.systemtap deleted file mode 100644 index 8fc4375135..0000000000 --- a/lib/dtrace/examples/function-calls.systemtap +++ /dev/null @@ -1,61 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe process("beam").mark("function-entry") -{ - printf("pid %s enter %s depth %d\n", - user_string($arg1), user_string($arg2), $arg3); -} - -probe process("beam").mark("function-return") -{ - printf("pid %s return %s depth %d\n", - user_string($arg1), user_string($arg2), $arg3); -} - -probe process("beam").mark("bif-entry") -{ - printf("pid %s BIF entry mfa %s\n", user_string($arg1), user_string($arg2)); -} - -probe process("beam").mark("bif-return") -{ - printf("pid %s BIF return mfa %s\n", user_string($arg1), user_string($arg2)); -} - -probe process("beam").mark("nif-entry") -{ - printf("pid %s NIF entry mfa %s\n", user_string($arg1), user_string($arg2)); -} - -probe process("beam").mark("nif-return") -{ - printf("pid %s NIF return mfa %s\n", user_string($arg1), user_string($arg2)); -} diff --git a/lib/dtrace/examples/garbage-collection.d b/lib/dtrace/examples/garbage-collection.d deleted file mode 100644 index f234e7d4db..0000000000 --- a/lib/dtrace/examples/garbage-collection.d +++ /dev/null @@ -1,39 +0,0 @@ -/* example usage: dtrace -q -s /path/to/garbage-collection.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -erlang*:::gc_major-start -{ - printf("GC major start pid %s need %d words\n", copyinstr(arg0), arg1); -} - -erlang*:::gc_minor-start -{ - printf("GC minor start pid %s need %d words\n", copyinstr(arg0), arg1); -} - -erlang*:::gc_major-end -{ - printf("GC major end pid %s reclaimed %d words\n", copyinstr(arg0), arg1); -} - -erlang*:::gc_minor-start -{ - printf("GC minor end pid %s reclaimed %d words\n", copyinstr(arg0), arg1); -} diff --git a/lib/dtrace/examples/garbage-collection.systemtap b/lib/dtrace/examples/garbage-collection.systemtap deleted file mode 100644 index 64d69c6fbd..0000000000 --- a/lib/dtrace/examples/garbage-collection.systemtap +++ /dev/null @@ -1,49 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe process("beam").mark("gc_major-start") -{ - printf("GC major start pid %s need %d words\n", user_string($arg1), $arg2); -} - -probe process("beam").mark("gc_minor-start") -{ - printf("GC minor start pid %s need %d words\n", user_string($arg1), $arg2); -} - -probe process("beam").mark("gc_major-end") -{ - printf("GC major end pid %s reclaimed %d words\n", user_string($arg1), $arg2); -} - -probe process("beam").mark("gc_minor-start") -{ - printf("GC minor end pid %s reclaimed %d words\n", user_string($arg1), $arg2); -} diff --git a/lib/dtrace/examples/memory1.d b/lib/dtrace/examples/memory1.d deleted file mode 100644 index c2e16e0779..0000000000 --- a/lib/dtrace/examples/memory1.d +++ /dev/null @@ -1,41 +0,0 @@ -/* example usage: dtrace -q -s /path/to/memory1.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -erlang*:::copy-struct -{ - printf("copy_struct %d bytes\n", arg0); -} - -erlang*:::copy-object -{ - printf("copy_object pid %s %d bytes\n", copyinstr(arg0), arg1); -} - -erlang*:::process-heap_grow -{ - printf("proc heap grow pid %s %d -> %d bytes\n", copyinstr(arg0), - arg1, arg2); -} - -erlang*:::process-heap_shrink -{ - printf("proc heap shrink pid %s %d -> %d bytes\n", copyinstr(arg0), - arg1, arg2); -} diff --git a/lib/dtrace/examples/memory1.systemtap b/lib/dtrace/examples/memory1.systemtap deleted file mode 100644 index 9723f2d02d..0000000000 --- a/lib/dtrace/examples/memory1.systemtap +++ /dev/null @@ -1,51 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe process("beam").mark("copy-struct") -{ - printf("copy_struct %d bytes\n", $arg1); -} - -probe process("beam").mark("copy-object") -{ - printf("copy_object pid %s %d bytes\n", user_string($arg1), $arg2); -} - -probe process("beam").mark("process-heap_grow") -{ - printf("proc heap grow pid %s %d -> %d bytes\n", user_string($arg1), - $arg2, $arg3); -} - -probe process("beam").mark("process-heap_shrink") -{ - printf("proc heap shrink pid %s %d -> %d bytes\n", user_string($arg1), - $arg2, $arg3); -} diff --git a/lib/dtrace/examples/messages.d b/lib/dtrace/examples/messages.d deleted file mode 100644 index 6361f3a220..0000000000 --- a/lib/dtrace/examples/messages.d +++ /dev/null @@ -1,94 +0,0 @@ -/* example usage: dtrace -q -s /path/to/messages.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -BEGIN -{ - printf("\n"); - printf("NOTE: message-queue message size 4294967295 means an external\n"); - printf(" message that the code isn't smart enough to determine\n"); - printf(" the actual size.\n"); - printf("\n"); -} - -erlang*:::message-send -/arg3 == 0 && arg4 == 0 && arg5 == 0/ -{ - printf("send: %s -> %s: %d words\n", - copyinstr(arg0), copyinstr(arg1), arg2); -} - -erlang*:::message-send -/arg3 != 0 || arg4 != 0 || arg5 != 0/ -{ - printf("send: %s label %d token {%d,%d} -> %s: %d words\n", - copyinstr(arg0), - arg3, arg4, arg5, - copyinstr(arg1), arg2); -} - -/* - * TODO: - * Weird, on my OS X box, beam says arg6 = 0 but this script says 4294967296. - */ - -erlang*:::message-send-remote -/arg4 == 0 && arg5 == 0 && (arg6 == 0 || arg6 >= 4294967296)/ -{ - printf("send : %s -> %s %s: %d words\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); -} - -erlang*:::message-send-remote -/arg4 != 0 || arg5 != 0 || arg6 < 4294967296/ -{ - printf("send : %s label %d token {%d,%d} -> %s %s: %d words\n", - copyinstr(arg0), - arg4, arg5, arg6, - copyinstr(arg1), copyinstr(arg2), arg3); -} - -erlang*:::message-queued -/arg3 == 0 && arg4 == 0 && arg5 == 0/ -{ - printf("queued: %s: %d words, queue len %d\n", copyinstr(arg0), arg1, arg2); -} - -erlang*:::message-queued -/arg3 != 0 || arg4 != 0 || arg5 != 0/ -{ - printf("queued: %s label %d token {%d,%d}: %d words, queue len %d\n", - copyinstr(arg0), arg3, arg4, arg5, - arg1, arg2); -} - -erlang*:::message-receive -/arg3 == 0 && arg4 == 0 && arg5 == 0/ -{ - printf("receive: %s: %d words, queue len %d\n", - copyinstr(arg0), arg1, arg2); -} - -erlang*:::message-receive -/arg3 != 0 || arg4 != 0 || arg5 != 0/ -{ - printf("receive: %s label %d token {%d,%d}: %d words, queue len %d\n", - copyinstr(arg0), arg3, arg4, arg5, - arg1, arg2); -} diff --git a/lib/dtrace/examples/messages.systemtap b/lib/dtrace/examples/messages.systemtap deleted file mode 100644 index ff8f4076b1..0000000000 --- a/lib/dtrace/examples/messages.systemtap +++ /dev/null @@ -1,87 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe begin -{ - printf("\n"); - printf("NOTE: message-queue message size 4294967295 means an external\n"); - printf(" message that the code isn't smart enough to determine\n"); - printf(" the actual size.\n"); - printf("\n"); -} - -probe process("beam").mark("message-send") -{ - if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { - printf("send: %s -> %s: %d words\n", - user_string($arg1), user_string($arg2), $arg3); - } else { - printf("send: %s label %d token {%d,%d} -> %s: %d words\n", - user_string($arg1), - $arg4, $arg5, $arg6, - user_string($arg2), $arg3); - } -} - -probe process("beam").mark("message-send-remote") -{ - if ($arg5 == 0 && $arg6 == 0 && $arg7 == 0) { - printf("send : %s -> %s %s: %d words\n", - user_string($arg1), user_string($arg2), user_string($arg3), $arg4); - } else { - printf("send : %s label %d token {%d,%d} -> %s %s: %d words\n", - user_string($arg1), - $arg5, $arg6, $arg7, - user_string($arg2), user_string($arg3), $arg4); - } -} - -probe process("beam").mark("message-queued") -{ - if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { - printf("queued: %s: %d words, queue len %d\n", user_string($arg1), $arg2, $arg3); - } else { - printf("queued: %s label %d token {%d,%d}: %d words, queue len %d\n", - user_string($arg1), $arg4, $arg5, $arg6, - $arg2, $arg3); - } -} - -probe process("beam").mark("message-receive") -{ - if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { - printf("receive: %s: %d words, queue len %d\n", - user_string($arg1), $arg2, $arg3); - } else { - printf("receive: %s label %d token {%d,%d}: %d words, queue len %d\n", - user_string($arg1), $arg4, $arg5, $arg6, - $arg2, $arg3); - } -} diff --git a/lib/dtrace/examples/port1.d b/lib/dtrace/examples/port1.d deleted file mode 100644 index 204abbd3b8..0000000000 --- a/lib/dtrace/examples/port1.d +++ /dev/null @@ -1,142 +0,0 @@ -/* example usage: dtrace -q -s /path/to/port1.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -BEGIN -{ - driver_map["tcp_inet", 1] = "OPEN"; - driver_map["tcp_inet", 2] = "CLOSE"; - driver_map["tcp_inet", 3] = "CONNECT"; - driver_map["tcp_inet", 4] = "PEER"; - driver_map["tcp_inet", 5] = "NAME"; - driver_map["tcp_inet", 6] = "BIND"; - driver_map["tcp_inet", 7] = "SETOPTS"; - driver_map["tcp_inet", 8] = "GETOPTS"; - driver_map["tcp_inet", 11] = "GETSTAT"; - driver_map["tcp_inet", 12] = "GETHOSTNAME"; - driver_map["tcp_inet", 13] = "FDOPEN"; - driver_map["tcp_inet", 14] = "GETFD"; - driver_map["tcp_inet", 15] = "GETTYPE"; - driver_map["tcp_inet", 16] = "GETSTATUS"; - driver_map["tcp_inet", 17] = "GETSERVBYNAME"; - driver_map["tcp_inet", 18] = "GETSERVBYPORT"; - driver_map["tcp_inet", 19] = "SETNAME"; - driver_map["tcp_inet", 20] = "SETPEER"; - driver_map["tcp_inet", 21] = "GETIFLIST"; - driver_map["tcp_inet", 22] = "IFGET"; - driver_map["tcp_inet", 23] = "IFSET"; - driver_map["tcp_inet", 24] = "SUBSCRIBE"; - driver_map["tcp_inet", 25] = "GETIFADDRS"; - driver_map["tcp_inet", 40] = "ACCEPT"; - driver_map["tcp_inet", 41] = "LISTEN"; - driver_map["tcp_inet", 42] = "RECV"; - driver_map["tcp_inet", 43] = "UNRECV"; - driver_map["tcp_inet", 44] = "SHUTDOWN"; - driver_map["tcp_inet", 60] = "RECV"; - driver_map["tcp_inet", 61] = "LISTEN"; - driver_map["tcp_inet", 62] = "BINDX"; - /* No looping constructs, so repeat for udp_inet */ - driver_map["udp_inet", 1] = "OPEN"; - driver_map["udp_inet", 2] = "CLOSE"; - driver_map["udp_inet", 3] = "CONNECT"; - driver_map["udp_inet", 4] = "PEER"; - driver_map["udp_inet", 5] = "NAME"; - driver_map["udp_inet", 6] = "BIND"; - driver_map["udp_inet", 7] = "SETOPTS"; - driver_map["udp_inet", 8] = "GETOPTS"; - driver_map["udp_inet", 11] = "GETSTAT"; - driver_map["udp_inet", 12] = "GETHOSTNAME"; - driver_map["udp_inet", 13] = "FDOPEN"; - driver_map["udp_inet", 14] = "GETFD"; - driver_map["udp_inet", 15] = "GETTYPE"; - driver_map["udp_inet", 16] = "GETSTATUS"; - driver_map["udp_inet", 17] = "GETSERVBYNAME"; - driver_map["udp_inet", 18] = "GETSERVBYPORT"; - driver_map["udp_inet", 19] = "SETNAME"; - driver_map["udp_inet", 20] = "SETPEER"; - driver_map["udp_inet", 21] = "GETIFLIST"; - driver_map["udp_inet", 22] = "IFGET"; - driver_map["udp_inet", 23] = "IFSET"; - driver_map["udp_inet", 24] = "SUBSCRIBE"; - driver_map["udp_inet", 25] = "GETIFADDRS"; - driver_map["udp_inet", 40] = "ACCEPT"; - driver_map["udp_inet", 41] = "LISTEN"; - driver_map["udp_inet", 42] = "RECV"; - driver_map["udp_inet", 43] = "UNRECV"; - driver_map["udp_inet", 44] = "SHUTDOWN"; - driver_map["udp_inet", 60] = "RECV"; - driver_map["udp_inet", 61] = "LISTEN"; - driver_map["udp_inet", 62] = "BINDX"; -} - -erlang*:::port-open -{ - printf("port open pid %s port name %s port %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::port-command -{ - printf("port command pid %s port %s port name %s command type %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); -} - -erlang*:::port-control -{ - /* http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types/ */ - this->cmd = driver_map[copyinstr(arg2), arg3]; - this->cmd_str = (this->cmd == 0) ? "unknown" : this->cmd; - printf("port control pid %s port %s port name %s command %d %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, - this->cmd_str); -} - -/* port-exit is fired as a result of port_close() or exit signal */ - -erlang*:::port-exit -{ - printf("port exit pid %s port %s port name %s reason %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); -} - -erlang*:::port-connect -{ - printf("port connect pid %s port %s port name %s new pid %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); -} - -erlang*:::port-busy -{ - printf("port busy %s\n", copyinstr(arg0)); -} - -erlang*:::port-not_busy -{ - printf("port not busy %s\n", copyinstr(arg0)); -} - -erlang*:::aio_pool-add -{ - printf("async I/O pool add thread %d queue len %d\n", arg0, arg1); -} - -erlang*:::aio_pool-get -{ - printf("async I/O pool get thread %d queue len %d\n", arg0, arg1); -} diff --git a/lib/dtrace/examples/port1.systemtap b/lib/dtrace/examples/port1.systemtap deleted file mode 100644 index a63d9b670c..0000000000 --- a/lib/dtrace/examples/port1.systemtap +++ /dev/null @@ -1,152 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe begin -{ - driver_map["tcp_inet", 1] = "OPEN"; - driver_map["tcp_inet", 2] = "CLOSE"; - driver_map["tcp_inet", 3] = "CONNECT"; - driver_map["tcp_inet", 4] = "PEER"; - driver_map["tcp_inet", 5] = "NAME"; - driver_map["tcp_inet", 6] = "BIND"; - driver_map["tcp_inet", 7] = "SETOPTS"; - driver_map["tcp_inet", 8] = "GETOPTS"; - driver_map["tcp_inet", 11] = "GETSTAT"; - driver_map["tcp_inet", 12] = "GETHOSTNAME"; - driver_map["tcp_inet", 13] = "FDOPEN"; - driver_map["tcp_inet", 14] = "GETFD"; - driver_map["tcp_inet", 15] = "GETTYPE"; - driver_map["tcp_inet", 16] = "GETSTATUS"; - driver_map["tcp_inet", 17] = "GETSERVBYNAME"; - driver_map["tcp_inet", 18] = "GETSERVBYPORT"; - driver_map["tcp_inet", 19] = "SETNAME"; - driver_map["tcp_inet", 20] = "SETPEER"; - driver_map["tcp_inet", 21] = "GETIFLIST"; - driver_map["tcp_inet", 22] = "IFGET"; - driver_map["tcp_inet", 23] = "IFSET"; - driver_map["tcp_inet", 24] = "SUBSCRIBE"; - driver_map["tcp_inet", 25] = "GETIFADDRS"; - driver_map["tcp_inet", 40] = "ACCEPT"; - driver_map["tcp_inet", 41] = "LISTEN"; - driver_map["tcp_inet", 42] = "RECV"; - driver_map["tcp_inet", 43] = "UNRECV"; - driver_map["tcp_inet", 44] = "SHUTDOWN"; - driver_map["tcp_inet", 60] = "RECV"; - driver_map["tcp_inet", 61] = "LISTEN"; - driver_map["tcp_inet", 62] = "BINDX"; - /* No looping constructs, so repeat for udp_inet */ - driver_map["udp_inet", 1] = "OPEN"; - driver_map["udp_inet", 2] = "CLOSE"; - driver_map["udp_inet", 3] = "CONNECT"; - driver_map["udp_inet", 4] = "PEER"; - driver_map["udp_inet", 5] = "NAME"; - driver_map["udp_inet", 6] = "BIND"; - driver_map["udp_inet", 7] = "SETOPTS"; - driver_map["udp_inet", 8] = "GETOPTS"; - driver_map["udp_inet", 11] = "GETSTAT"; - driver_map["udp_inet", 12] = "GETHOSTNAME"; - driver_map["udp_inet", 13] = "FDOPEN"; - driver_map["udp_inet", 14] = "GETFD"; - driver_map["udp_inet", 15] = "GETTYPE"; - driver_map["udp_inet", 16] = "GETSTATUS"; - driver_map["udp_inet", 17] = "GETSERVBYNAME"; - driver_map["udp_inet", 18] = "GETSERVBYPORT"; - driver_map["udp_inet", 19] = "SETNAME"; - driver_map["udp_inet", 20] = "SETPEER"; - driver_map["udp_inet", 21] = "GETIFLIST"; - driver_map["udp_inet", 22] = "IFGET"; - driver_map["udp_inet", 23] = "IFSET"; - driver_map["udp_inet", 24] = "SUBSCRIBE"; - driver_map["udp_inet", 25] = "GETIFADDRS"; - driver_map["udp_inet", 40] = "ACCEPT"; - driver_map["udp_inet", 41] = "LISTEN"; - driver_map["udp_inet", 42] = "RECV"; - driver_map["udp_inet", 43] = "UNRECV"; - driver_map["udp_inet", 44] = "SHUTDOWN"; - driver_map["udp_inet", 60] = "RECV"; - driver_map["udp_inet", 61] = "LISTEN"; - driver_map["udp_inet", 62] = "BINDX"; -} - -probe process("beam").mark("port-open") -{ - printf("port open pid %s port name %s port %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("port-command") -{ - printf("port command pid %s port %s port name %s command type %s\n", - user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); -} - -probe process("beam").mark("port-control") -{ - cmd = driver_map[user_string($arg3), $arg4]; - cmd_str = (cmd == "") ? "unknown" : cmd; - printf("port control pid %s port %s port name %s command %d %s\n", - user_string($arg1), user_string($arg2), user_string($arg3), $arg4, cmd_str); -} - -/* port-exit is fired as a result of port_close() or exit signal */ - -probe process("beam").mark("port-exit") -{ - printf("port exit pid %s port %s port name %s reason %s\n", - user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); -} - -probe process("beam").mark("port-connect") -{ - printf("port connect pid %s port %s port name %s new pid %s\n", - user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); -} - -probe process("beam").mark("port-busy") -{ - printf("port busy %s\n", user_string($arg1)); -} - -probe process("beam").mark("port-not_busy") -{ - printf("port not busy %s\n", user_string($arg1)); -} - -probe process("beam").mark("aio_pool-add") -{ - printf("async I/O pool add thread %d queue len %d\n", $arg1, $arg2); -} - -probe process("beam").mark("aio_pool-get") -{ - printf("async I/O pool get thread %d queue len %d\n", $arg1, $arg2); -} - -global driver_map; \ No newline at end of file diff --git a/lib/dtrace/examples/process-scheduling.d b/lib/dtrace/examples/process-scheduling.d deleted file mode 100644 index 79e9cc598c..0000000000 --- a/lib/dtrace/examples/process-scheduling.d +++ /dev/null @@ -1,35 +0,0 @@ -/* example usage: dtrace -q -s /path/to/process-scheduling.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -erlang*:::process-scheduled -{ - printf(" Schedule pid %s mfa %s\n", copyinstr(arg0), copyinstr(arg1)); -} - -erlang*:::process-unscheduled -{ - printf("Unschedule pid %s\n", copyinstr(arg0)); -} - -erlang*:::process-hibernate -{ - printf(" Hibernate pid %s resume mfa %s\n", - copyinstr(arg0), copyinstr(arg1)); -} diff --git a/lib/dtrace/examples/process-scheduling.systemtap b/lib/dtrace/examples/process-scheduling.systemtap deleted file mode 100644 index c8cee60a07..0000000000 --- a/lib/dtrace/examples/process-scheduling.systemtap +++ /dev/null @@ -1,45 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe process("beam").mark("process-scheduled") -{ - printf(" Schedule pid %s mfa %s\n", user_string($arg1), user_string($arg2)); -} - -probe process("beam").mark("process-unscheduled") -{ - printf("Unschedule pid %s\n", user_string($arg1)); -} - -probe process("beam").mark("process-hibernate") -{ - printf(" Hibernate pid %s resume mfa %s\n", - user_string($arg1), user_string($arg2)); -} diff --git a/lib/dtrace/examples/spawn-exit.d b/lib/dtrace/examples/spawn-exit.d deleted file mode 100644 index 7310f3343d..0000000000 --- a/lib/dtrace/examples/spawn-exit.d +++ /dev/null @@ -1,41 +0,0 @@ -/* example usage: dtrace -q -s /path/to/spawn-exit.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -erlang*:::process-spawn -{ - printf("pid %s mfa %s\n", copyinstr(arg0), copyinstr(arg1)); -} - -erlang*:::process-exit -{ - printf("pid %s reason %s\n", copyinstr(arg0), copyinstr(arg1)); -} - -erlang*:::process-exit_signal -{ - printf("sender %s -> pid %s reason %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); -} - -erlang*:::process-exit_signal-remote -{ - printf("sender %s -> node %s pid %s reason %s\n", - copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); -} diff --git a/lib/dtrace/examples/spawn-exit.systemtap b/lib/dtrace/examples/spawn-exit.systemtap deleted file mode 100644 index 5e3be9fc1b..0000000000 --- a/lib/dtrace/examples/spawn-exit.systemtap +++ /dev/null @@ -1,51 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe process("beam").mark("process-spawn") -{ - printf("pid %s mfa %s\n", user_string($arg1), user_string($arg2)); -} - -probe process("beam").mark("process-exit") -{ - printf("pid %s reason %s\n", user_string($arg1), user_string($arg2)); -} - -probe process("beam").mark("process-exit_signal") -{ - printf("sender %s -> pid %s reason %s\n", - user_string($arg1), user_string($arg2), user_string($arg3)); -} - -probe process("beam").mark("process-exit_signal-remote") -{ - printf("sender %s -> node %s pid %s reason %s\n", - user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); -} diff --git a/lib/dtrace/examples/user-probe.d b/lib/dtrace/examples/user-probe.d deleted file mode 100644 index 13baff6a32..0000000000 --- a/lib/dtrace/examples/user-probe.d +++ /dev/null @@ -1,36 +0,0 @@ -/* example usage: dtrace -q -s /path/to/user-probe.d */ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ - -erlang*:::user_trace-s1 -{ - printf("%s\n", copyinstr(arg0)); -} - -erlang*:::user_trace-i4s4 -{ - printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", - copyinstr(arg0), - arg1 == NULL ? "" : copyinstr(arg1), - arg2, arg3, arg4, arg5, - arg6 == NULL ? "" : copyinstr(arg6), - arg7 == NULL ? "" : copyinstr(arg7), - arg8 == NULL ? "" : copyinstr(arg8), - arg9 == NULL ? "" : copyinstr(arg9)); -} diff --git a/lib/dtrace/examples/user-probe.systemtap b/lib/dtrace/examples/user-probe.systemtap deleted file mode 100644 index 84a45709e8..0000000000 --- a/lib/dtrace/examples/user-probe.systemtap +++ /dev/null @@ -1,46 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. - * - * The contents of this file are subject to the Erlang Public License, - * Version 1.1, (the "License"); you may not use this file except in - * compliance with the License. You should have received a copy of the - * Erlang Public License along with this software. If not, it can be - * retrieved online at http://www.erlang.org/. - * - * Software distributed under the License is distributed on an "AS IS" - * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - * the License for the specific language governing rights and limitations - * under the License. - * - * %CopyrightEnd% - */ -/* - * Note: This file assumes that you're using the non-SMP-enabled Erlang - * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". - * Note that other variations of the virtual machine also have - * different names, e.g. the debug build of the SMP-enabled VM - * is "beam.debug.smp". - * - * To use a different virtual machine, replace each instance of - * "beam" with "beam.smp" or the VM name appropriate to your - * environment. - */ - -probe process("dyntrace.so").mark("user_trace-s1") -{ - printf("%s\n", user_string($arg1)); -} - -probe process("dyntrace.so").mark("user_trace-i4s4") -{ - printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", - user_string($arg1), - $arg2 == NULL ? "" : user_string($arg2), - $arg3, $arg4, $arg5, $arg6, - $arg7 == NULL ? "" : user_string($arg7), - $arg8 == NULL ? "" : user_string($arg8), - $arg9 == NULL ? "" : user_string($arg9), - $arg9 == NULL ? "" : user_string($arg9)); -} diff --git a/lib/dtrace/src/Makefile b/lib/dtrace/src/Makefile deleted file mode 100644 index d613402a63..0000000000 --- a/lib/dtrace/src/Makefile +++ /dev/null @@ -1,102 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2002-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include ../vsn.mk -VSN=$(DTRACE_VSN) - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/lib/dtrace-$(VSN) - -# ---------------------------------------------------- -# Common Macros -# ---------------------------------------------------- - -MODULES= \ - dtrace - -HRL_FILES= \ - -INTERNAL_HRL_FILES= \ - -ERL_FILES= $(MODULES:%=%.erl) -EXAMPLE_FILES= \ - ../examples/* - -TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) - -EXECUTABLES= \ - -APP_FILE= dtrace.app - -APP_SRC= $(APP_FILE).src -APP_TARGET= $(EBIN)/$(APP_FILE) - -APPUP_FILE= dtrace.appup - -APPUP_SRC= $(APPUP_FILE).src -APPUP_TARGET= $(EBIN)/$(APPUP_FILE) - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -ERL_COMPILE_FLAGS += \ - -I../include \ - -I ../../et/include \ - -I ../../../libraries/et/include - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -debug opt: $(TARGET_FILES) - -clean: - rm -f $(TARGET_FILES) - rm -f errs core *~ - -$(APP_TARGET): $(APP_SRC) ../vsn.mk - sed -e 's;%VSN%;$(VSN);' $< > $@ - -$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk - sed -e 's;%VSN%;$(VSN);' $< > $@ - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/src - $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src - # $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src - $(INSTALL_DIR) $(RELSYSDIR)/examples - $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples - $(INSTALL_DIR) $(RELSYSDIR)/ebin - $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin - -release_docs_spec: diff --git a/lib/dtrace/src/dtrace.app.src b/lib/dtrace/src/dtrace.app.src deleted file mode 100644 index 764e863559..0000000000 --- a/lib/dtrace/src/dtrace.app.src +++ /dev/null @@ -1,27 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -{application, dtrace, - [{description, "DTRACE version 1"}, - {vsn, "%VSN%"}, - {modules, [ - dtrace - ]}, - {registered, []}, - {applications, [kernel, stdlib]}, - {env, []}]}. diff --git a/lib/dtrace/src/dtrace.appup.src b/lib/dtrace/src/dtrace.appup.src deleted file mode 100644 index f730a2f8df..0000000000 --- a/lib/dtrace/src/dtrace.appup.src +++ /dev/null @@ -1,19 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -{"%VSN%",[],[]}. diff --git a/lib/dtrace/src/dtrace.erl b/lib/dtrace/src/dtrace.erl deleted file mode 100644 index 71a1a3480e..0000000000 --- a/lib/dtrace/src/dtrace.erl +++ /dev/null @@ -1,247 +0,0 @@ --module(dtrace). - -%%% @doc The DTrace interface module -%%% -%%% This DTrace interface module, with the corresponding NIFs, should -%%% work on any operating system platform where user-space DTrace -%%% probes are supported. -%%% -%%% Use the `dtrace:init()' function to load the NIF shared library and -%%% to initialize library's private state. -%%% -%%% It is recommended that you use the `dtrace:p()' function to add -%%% DTrace probes to your Erlang code. This function can accept up to -%%% four integer arguments and four string arguments; the integer -%%% argument(s) must come before any string argument. For example: -%%% ``` -%%% 1> dtrace:put_tag("GGOOOAAALL!!!!!"). -%%% true -%%% 2> dtrace:init(). -%%% ok -%%% -%%% % % % Enable the DTrace probe using the 'dtrace' command. -%%% -%%% 3> dtrace:p(7, 8, 9, "one", "four"). -%%% true -%%% ''' -%%% -%%% Output from the example D script `user-probe.d' looks like: -%%% ``` -%%% <0.34.0> GGOOOAAALL!!!!! 7 8 9 0 'one' 'four' '' '' -%%% ''' -%%% -%%% If the expected type of variable is not present, e.g. integer when -%%% integer() is expected, or an I/O list when iolist() is expected, -%%% then the driver will ignore the user's input and use a default -%%% value of 0 or NULL, respectively. - --export([init/0, available/0, - user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 - p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). --export([put_utag/1, get_utag/0, get_utag_data/0, spread_utag/1, restore_utag/1]). - --export([scaff/0]). % Development only --export([user_trace_i4s4/9]). % Know what you're doing! - --type probe_arg() :: integer() | iolist(). --type int_p_arg() :: integer() | iolist() | undef. -%% The *_maybe() types use atom() instead of a stricter 'undef' -%% because user_trace_i4s4/9 is exposed to the outside world, and -%% because the driver will allow any atom to be used as a "not -%% present" indication, we'll allow any atom in the types. --type integer_maybe() :: integer() | atom(). --type iolist_maybe() :: iolist() | atom(). - --spec init() -> ok | {error, {term(), term()}}. - -init() -> - PrivDir = code:priv_dir(dtrace), - Lib = filename:join([PrivDir, "lib", "dtrace"]), - erlang:load_nif(Lib, 0). - -%%% -%%% NIF placeholders -%%% - --spec available() -> true | false. - -available() -> - erlang:nif_error(nif_not_loaded). - --spec user_trace_s1(iolist()) -> true | false | error | badarg. - -user_trace_s1(_Message) -> - erlang:nif_error(nif_not_loaded). - --spec user_trace_i4s4(iolist(), - integer_maybe(), integer_maybe(), - integer_maybe(), integer_maybe(), - iolist_maybe(), iolist_maybe(), - iolist_maybe(), iolist_maybe()) -> - true | false | error | badarg. - -user_trace_i4s4(_, _, _, _, _, _, _, _, _) -> - erlang:nif_error(nif_not_loaded). - -%%% -%%% Erlang support functions -%%% - --spec p() -> true | false | error | badarg. - -p() -> - user_trace_int(undef, undef, undef, undef, undef, undef, undef, undef). - --spec p(probe_arg()) -> true | false | error | badarg. - -p(I1) when is_integer(I1) -> - user_trace_int(I1, undef, undef, undef, undef, undef, undef, undef); -p(S1) -> - user_trace_int(undef, undef, undef, undef, S1, undef, undef, undef). - --spec p(probe_arg(), probe_arg()) -> true | false | error | badarg. - -p(I1, I2) when is_integer(I1), is_integer(I2) -> - user_trace_int(I1, I2, undef, undef, undef, undef, undef, undef); -p(I1, S1) when is_integer(I1) -> - user_trace_int(I1, undef, undef, undef, S1, undef, undef, undef); -p(S1, S2) -> - user_trace_int(undef, undef, undef, undef, S1, S2, undef, undef). - --spec p(probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg. - -p(I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) -> - user_trace_int(I1, I2, I3, undef, undef, undef, undef, undef); -p(I1, I2, S1) when is_integer(I1), is_integer(I2) -> - user_trace_int(I1, I2, undef, undef, S1, undef, undef, undef); -p(I1, S1, S2) when is_integer(I1) -> - user_trace_int(I1, undef, undef, undef, S1, S2, undef, undef); -p(S1, S2, S3) -> - user_trace_int(undef, undef, undef, undef, S1, S2, S3, undef). - --spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> - true | false | error | badarg. - -p(I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> - user_trace_int(I1, I2, I3, I4, undef, undef, undef, undef); -p(I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) -> - user_trace_int(I1, I2, I3, undef, S1, undef, undef, undef); -p(I1, I2, S1, S2) when is_integer(I1), is_integer(I2) -> - user_trace_int(I1, I2, undef, undef, S1, S2, undef, undef); -p(I1, S1, S2, S3) when is_integer(I1) -> - user_trace_int(I1, undef, undef, undef, S1, S2, S3, undef); -p(S1, S2, S3, S4) -> - user_trace_int(undef, undef, undef, undef, S1, S2, S3, S4). - --spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), - probe_arg()) -> - true | false | error | badarg. - -p(I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> - user_trace_int(I1, I2, I3, I4, S1, undef, undef, undef); -p(I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) -> - user_trace_int(I1, I2, I3, undef, S1, S2, undef, undef); -p(I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) -> - user_trace_int(I1, I2, undef, undef, S1, S2, S3, undef); -p(I1, S1, S2, S3, S4) when is_integer(I1) -> - user_trace_int(I1, undef, undef, undef, S1, S2, S3, S4). - --spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), - probe_arg(), probe_arg()) -> - true | false | error | badarg. - -p(I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> - user_trace_int(I1, I2, I3, I4, S1, S2, undef, undef); -p(I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) -> - user_trace_int(I1, I2, I3, undef, S1, S2, S3, undef); -p(I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) -> - user_trace_int(I1, I2, undef, undef, S1, S2, S3, S4). - --spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), - probe_arg(), probe_arg(), probe_arg()) -> - true | false | error | badarg. - -p(I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> - user_trace_int(I1, I2, I3, I4, S1, S2, S3, undef); -p(I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) -> - user_trace_int(I1, I2, I3, undef, S1, S2, S3, S4). - --spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), - probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> - true | false | error | badarg. - -p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> - user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4). - --spec user_trace_int(int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(), - int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) -> - true | false | error | badarg. - -user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> - UTag = get_utag(), - try - user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4) - catch - error:nif_not_loaded -> - false - end. - --spec put_utag(undefined | iodata()) -> binary() | undefined. -put_utag(Data) -> - erlang:put_utag(unicode:characters_to_binary(Data)). - --spec get_utag() -> binary() | undefined. -get_utag() -> - erlang:get_utag(). - --spec get_utag_data() -> binary() | undefined. -%% Gets utag if set, otherwise the spread utag data from last incoming message -get_utag_data() -> - erlang:get_utag_data(). - --spec spread_utag(boolean()) -> true | {non_neg_integer(), binary() | []}. -%% Makes the utag behave as a sequential trace token, will spread with messages to be picked up by someone using -%% get_utag_data or get_drv_utag_data. -spread_utag(B) -> - erlang:spread_utag(B). - --spec restore_utag(true | {non_neg_integer(), binary() | []}) -> true. -restore_utag(T) -> - erlang:restore_utag(T). - - -%% Scaffolding to write tedious code: quick brute force and not 100% correct. - -scaff_int_args(N) -> - L = lists:sublist(["I1", "I2", "I3", "I4"], N), - [string:join(L, ", ")]. - -scaff_int_guards(N) -> - L = lists:sublist(["is_integer(I1)", "is_integer(I2)", "is_integer(I3)", - "is_integer(I4)"], N), - lists:flatten(string:join(L, ", ")). - -scaff_char_args(N) -> - L = lists:sublist(["S1", "S2", "S3", "S4"], N), - [string:join(L, ", ")]. - -scaff_fill(N) -> - [string:join(lists:duplicate(N, "undef"), ", ")]. - -scaff() -> - L = [begin - IntArgs = scaff_int_args(N_int), - IntGuards = scaff_int_guards(N_int), - IntFill = scaff_fill(4 - N_int), - CharArgs = scaff_char_args(N_char), - CharFill = scaff_fill(4 - N_char), - InArgs = string:join(IntArgs ++ CharArgs, ", "), - OutArgs = string:join(IntArgs ++ IntFill ++ CharArgs ++ CharFill, - ", "), - {N_int + N_char, - lists:flatten([io_lib:format("p(~s) when ~s ->\n", - [InArgs, IntGuards]), - io_lib:format(" user_trace_int(~s);\n", [OutArgs]) - ])} - end || N_int <- [0,1,2,3,4], N_char <- [0,1,2,3,4]], - [io:format("%%~p\n~s", [N, Str]) || {N, Str} <- lists:sort(L)]. diff --git a/lib/dtrace/vsn.mk b/lib/dtrace/vsn.mk deleted file mode 100644 index 73bf983c00..0000000000 --- a/lib/dtrace/vsn.mk +++ /dev/null @@ -1 +0,0 @@ -DTRACE_VSN = 0.8 diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in index 3d9a7ed69d..120f9b913f 100644 --- a/lib/runtime_tools/c_src/Makefile.in +++ b/lib/runtime_tools/c_src/Makefile.in @@ -20,6 +20,11 @@ include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk +# ---------------------------------------------------- +# Items from top-level configure +# ---------------------------------------------------- +DTRACE_ENABLED=@DTRACE_ENABLED@ +DTRACE_ENABLED_2STEP=@DTRACE_ENABLED_2STEP@ # ---------------------------------------------------- # Application version # ---------------------------------------------------- @@ -38,6 +43,8 @@ SHELL = /bin/sh LIBS = $(DED_LIBS) LDFLAGS += $(DED_LDFLAGS) +DTRACE_LIBNAME = dyntrace + SYSINCLUDE = $(DED_SYS_INCLUDE) ifeq ($(findstring vxworks,$(TARGET)),vxworks) SYSINCLUDE += -I$(ERL_TOP)/erts/etc/vxworks @@ -45,15 +52,20 @@ endif TRACE_DRV_INCLUDES = $(SYSINCLUDE) -ALL_CFLAGS = $(CFLAGS) @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) - +ALL_CFLAGS = $(CFLAGS) @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \ + -I$(OBJDIR) -I$(ERL_TOP)/erts/emulator/$(TARGET) ifeq ($(TYPE),debug) TYPEMARKER = .debug -TYPE_FLAGS = -g -DDEBUG @DEBUG_FLAGS@ +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DDEBUG @DEBUG_FLAGS@ +else +ifeq ($(TYPE),valgrind) +TYPEMARKER = .valgrind +TYPE_FLAGS = $(subst -O3,,$(subst -O2,,$(CFLAGS))) -DVALGRIND else TYPEMARKER = -TYPE_FLAGS = -O2 +TYPE_FLAGS = $(CFLAGS) +endif endif ROOTDIR = $(ERL_TOP)/lib @@ -69,6 +81,16 @@ RELSYSDIR = $(RELEASE_PATH)/lib/runtime_tools-$(VSN) # ---------------------------------------------------- # Misc Macros # ---------------------------------------------------- +before_DTrace_OBJS = $(OBJDIR)/dyntrace$(TYPEMARKER).o +## NIF_MAKEFILE = $(PRIVDIR)/Makefile + +# Higher-level makefiles says that we can only compile on UNIX flavors +NIF_LIB = $(LIBDIR)/dyntrace$(TYPEMARKER).@DED_EXT@ + +ifeq ($(HOST_OS),) +HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess) +endif + TRACE_IP_DRV_OBJS = \ $(OBJDIR)/trace_ip_drv.o @@ -91,7 +113,44 @@ endif _create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR)) -debug opt: $(SOLIBS) +debug opt valgrind: $(SOLIBS) $(OBJDIR) $(LIBDIR) $(NIF_LIB) + +ifdef DTRACE_ENABLED +DTRACE_USER_HEADER=$(OBJDIR)/dtrace_user.h +$(OBJDIR)/dtrace_user.h: ./dtrace_user.d + dtrace -h -C $(INCLUDES) \ + -s ./dtrace_user.d \ + -o ./dtrace_user.tmp + sed -e '/^#define[ ]*ERLANG_[A-Z0-9_]*(.*)/y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' ./dtrace_user.tmp > $@ + rm ./dtrace_user.tmp +else +DTRACE_USER_HEADER= +endif + +DTRACE_OBJS = +ifdef DTRACE_ENABLED_2STEP +DTRACE_OBJS += $(OBJDIR)/dtrace_user.o +$(OBJDIR)/dtrace_user.o: $(before_DTrace_OBJS) $(OBJDIR)/dtrace_user.h + dtrace -G -C \ + -s ./dtrace_user.d \ + -o $@ $(before_DTrace_OBJS) +endif + +DYNTRACE_OBJS = $(before_DTrace_OBJS) $(DTRACE_OBJS) + +$(OBJDIR): + -@mkdir -p $(OBJDIR) + +$(LIBDIR): + -@mkdir -p $(LIBDIR) + +$(OBJDIR)/dyntrace$(TYPEMARKER).o: dyntrace.c $(DTRACE_USER_HEADER) + $(INSTALL_DIR) $(OBJDIR) + $(CC) -c -o $@ $(ALL_CFLAGS) $< + +$(NIF_LIB): $(DYNTRACE_OBJS) + $(INSTALL_DIR) $(LIBDIR) + $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(OBJDIR)/%.o: %.c $(CC) -c -o $@ $(ALL_CFLAGS) $< @@ -118,6 +177,12 @@ $(LIBDIR)/trace_file_drv.eld: $(TRACE_FILE_DRV_OBJS) clean: rm -f $(SOLIBS) $(TRACE_IP_DRV_OBJS) $(TRACE_FILE_DRV_OBJS) + rm -f $(LIBDIR)/dyntrace.@DED_EXT@ + rm -f $(LIBDIR)/dyntrace.debug.@DED_EXT@ + rm -f $(LIBDIR)/dyntrace.valgrind.@DED_EXT@ + rm -f $(OBJDIR)/dyntrace.o + rm -f $(OBJDIR)/dyntrace.debug.o + rm -f $(OBJDIR)/dyntrace.valgrind.o rm -f core *~ docs: @@ -128,8 +193,10 @@ docs: include $(ERL_TOP)/make/otp_release_targets.mk release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/priv/obj $(INSTALL_DIR) $(RELSYSDIR)/priv/lib - $(INSTALL_PROGRAM) $(SOLIBS) $(RELSYSDIR)/priv/lib + $(INSTALL_PROGRAM) $(DYNTRACE_OBJS) $(RELSYSDIR)/priv/obj + $(INSTALL_PROGRAM) $(NIF_LIB) $(SOLIBS) $(RELSYSDIR)/priv/lib release_docs_spec: diff --git a/lib/runtime_tools/c_src/dtrace_user.d b/lib/runtime_tools/c_src/dtrace_user.d new file mode 100644 index 0000000000..45d3ef3b66 --- /dev/null +++ b/lib/runtime_tools/c_src/dtrace_user.d @@ -0,0 +1,53 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. + * All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +provider erlang { + /** + * Send a single string to a probe. + * + * @param NUL-terminated string + */ + probe user_trace__s1(char* message); + + /** + * Multi-purpose probe: up to 4 NUL-terminated strings and 4 + * 64-bit integer arguments. + * + * @param proc, the PID (string form) of the sending process + * @param user_tag, the user tag of the sender + * @param i1, integer + * @param i2, integer + * @param i3, integer + * @param i4, integer + * @param s1, string/iolist. D's arg6 is NULL if not given by Erlang + * @param s2, string/iolist. D's arg7 is NULL if not given by Erlang + * @param s3, string/iolist. D's arg8 is NULL if not given by Erlang + * @param s4, string/iolist. D's arg9 is NULL if not given by Erlang + */ + probe user_trace__i4s4(char *proc, char *user_tag, + int i1, int i2, int i3, int i4, + char *s1, char *s2, char *s3, char *s4); +}; + +#pragma D attributes Evolving/Evolving/Common provider erlang provider +#pragma D attributes Private/Private/Common provider erlang module +#pragma D attributes Private/Private/Common provider erlang function +#pragma D attributes Evolving/Evolving/Common provider erlang name +#pragma D attributes Evolving/Evolving/Common provider erlang args diff --git a/lib/runtime_tools/c_src/dyntrace.c b/lib/runtime_tools/c_src/dyntrace.c new file mode 100644 index 0000000000..d94014559d --- /dev/null +++ b/lib/runtime_tools/c_src/dyntrace.c @@ -0,0 +1,172 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +/* + * Purpose: Dynamically loadable NIF library for DTrace + */ + + + +#include "erl_nif.h" +#include "config.h" +#include "sys.h" +#include "dtrace-wrapper.h" +#if defined(USE_DYNAMIC_TRACE) && (defined(USE_DTRACE) || defined(USE_SYSTEMTAP)) +#define HAVE_USE_DTRACE 1 +#endif +#ifdef HAVE_USE_DTRACE +#include "dtrace_user.h" +#endif + +void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf); +void get_string_maybe(ErlNifEnv *env, const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz); + +#ifdef VALGRIND + # include +#endif + +#ifdef __GNUC__ + # define INLINE __inline__ +#else + # define INLINE +#endif + +#define MESSAGE_BUFSIZ 1024 + +/* NIF interface declarations */ +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); + +/* The NIFs: */ +static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); + +static ErlNifFunc nif_funcs[] = { + {"available", 0, available}, + {"user_trace_s1", 1, user_trace_s1}, + {"user_trace_i4s4", 9, user_trace_i4s4} +}; + +ERL_NIF_INIT(dyntrace, nif_funcs, load, NULL, NULL, NULL) + +static ERL_NIF_TERM atom_true; +static ERL_NIF_TERM atom_false; +static ERL_NIF_TERM atom_error; +static ERL_NIF_TERM atom_not_available; +static ERL_NIF_TERM atom_badarg; +static ERL_NIF_TERM atom_ok; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + atom_true = enif_make_atom(env,"true"); + atom_false = enif_make_atom(env,"false"); + atom_error = enif_make_atom(env,"error"); + atom_not_available = enif_make_atom(env,"not_available"); + atom_badarg = enif_make_atom(env,"badarg"); + atom_ok = enif_make_atom(env,"ok"); + + return 0; +} + +static ERL_NIF_TERM available(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_USE_DTRACE + return atom_true; +#else + return atom_false; +#endif +} + +static ERL_NIF_TERM user_trace_s1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_USE_DTRACE + ErlNifBinary message_bin; + DTRACE_CHARBUF(messagebuf, MESSAGE_BUFSIZ + 1); + + if (DTRACE_ENABLED(user_trace_s1)) { + if (!enif_inspect_iolist_as_binary(env, argv[0], &message_bin) || + message_bin.size > MESSAGE_BUFSIZ) { + return atom_badarg; + } + memcpy(messagebuf, (char *) message_bin.data, message_bin.size); + messagebuf[message_bin.size] = '\0'; + DTRACE1(user_trace_s1, messagebuf); + return atom_true; + } else { + return atom_false; + } +#else + return atom_error; +#endif +} + +void +get_string_maybe(ErlNifEnv *env, + const ERL_NIF_TERM term, char **ptr, char *buf, int bufsiz) +{ + ErlNifBinary str_bin; + + if (!enif_inspect_iolist_as_binary(env, term, &str_bin) || + str_bin.size > bufsiz) { + *ptr = NULL; + } else { + memcpy(buf, (char *) str_bin.data, str_bin.size); + buf[str_bin.size] = '\0'; + *ptr = buf; + } +} + +static ERL_NIF_TERM user_trace_i4s4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_USE_DTRACE + DTRACE_CHARBUF(procbuf, 32 + 1); + DTRACE_CHARBUF(user_tagbuf, MESSAGE_BUFSIZ + 1); + char *utbuf = NULL; + ErlNifSInt64 i1, i2, i3, i4; + DTRACE_CHARBUF(messagebuf1, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf2, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf3, MESSAGE_BUFSIZ + 1); + DTRACE_CHARBUF(messagebuf4, MESSAGE_BUFSIZ + 1); + char *mbuf1 = NULL, *mbuf2 = NULL, *mbuf3 = NULL, *mbuf4 = NULL; + + if (DTRACE_ENABLED(user_trace_i4s4)) { + dtrace_nifenv_str(env, procbuf); + get_string_maybe(env, argv[0], &utbuf, user_tagbuf, MESSAGE_BUFSIZ); + if (! enif_get_int64(env, argv[1], &i1)) + i1 = 0; + if (! enif_get_int64(env, argv[2], &i2)) + i2 = 0; + if (! enif_get_int64(env, argv[3], &i3)) + i3 = 0; + if (! enif_get_int64(env, argv[4], &i4)) + i4 = 0; + get_string_maybe(env, argv[5], &mbuf1, messagebuf1, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[6], &mbuf2, messagebuf2, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[7], &mbuf3, messagebuf3, MESSAGE_BUFSIZ); + get_string_maybe(env, argv[8], &mbuf4, messagebuf4, MESSAGE_BUFSIZ); + DTRACE10(user_trace_i4s4, procbuf, utbuf, + i1, i2, i3, i4, mbuf1, mbuf2, mbuf3, mbuf4); + return atom_true; + } else { + return atom_false; + } +#else + return atom_error; +#endif +} diff --git a/lib/runtime_tools/examples/dist.d b/lib/runtime_tools/examples/dist.d new file mode 100644 index 0000000000..550e10d363 --- /dev/null +++ b/lib/runtime_tools/examples/dist.d @@ -0,0 +1,62 @@ +/* example usage: dtrace -q -s /path/to/dist.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::dist-monitor +{ + printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", + pid, + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3), + copyinstr(arg4)); +} + +erlang*:::dist-port_busy +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); + /* + * For variable use advice, see: + * http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types/ + * + * Howevever, it's quite possible for the blocked events to span + * threads, so we'll use globals. + */ + blocked_procs[copyinstr(arg3)] = timestamp; +} + +erlang*:::dist-output +{ + printf("dist output: node %s, port %s, remote_node %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::dist-outputv +{ + printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::process-scheduled +/blocked_procs[copyinstr(arg0)]/ +{ + pidstr = copyinstr(arg0); + printf("blocked pid %s scheduled now, waited %d microseconds\n", + pidstr, (timestamp - blocked_procs[pidstr]) / 1000); + blocked_procs[pidstr] = 0; +} diff --git a/lib/runtime_tools/examples/dist.systemtap b/lib/runtime_tools/examples/dist.systemtap new file mode 100644 index 0000000000..af27b2cab6 --- /dev/null +++ b/lib/runtime_tools/examples/dist.systemtap @@ -0,0 +1,76 @@ +/* example usage: stap /path/to/dist.systemtap -x */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("dist-monitor") +{ + printf("monitor: pid %d, who %s, what %s, node %s, type %s, reason %s\n", + pid(), + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4), + user_string($arg5)); +} + +probe process("beam").mark("dist-port_busy") +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); + blocked_procs[user_string($arg4)] = timestamp; +} + +probe process("beam").mark("dist-port_busy") +{ + printf("dist port_busy: node %s, port %s, remote_node %s, blocked pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); + blocked_procs[user_string($arg4)] = timestamp; +} + +probe process("beam").mark("dist-output") +{ + printf("dist output: node %s, port %s, remote_node %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("dist-outputv") +{ + printf("port outputv: node %s, port %s, remote_node %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("process-scheduled") +{ + pidstr = user_string($arg1); + if (pidstr in blocked_procs) { + printf("blocked pid %s scheduled now, waited %d microseconds\n", + pidstr, (timestamp - blocked_procs[pidstr]) / 1000); + delete blocked_procs[pidstr]; + } +} + +global blocked_procs; diff --git a/lib/runtime_tools/examples/driver1.d b/lib/runtime_tools/examples/driver1.d new file mode 100644 index 0000000000..9f53ffeb2a --- /dev/null +++ b/lib/runtime_tools/examples/driver1.d @@ -0,0 +1,114 @@ +/* example usage: dtrace -q -s /path/to/driver1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::driver-init +{ + printf("driver init name %s major %d minor %d flags %d\n", + copyinstr(arg0), arg1, arg2, arg3); +} + +erlang*:::driver-start +{ + printf("driver start pid %s driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-stop +{ + printf("driver stop pid %s driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-finish +{ + printf("driver finish driver name %s port %s\n", + copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::driver-flush +{ + printf("driver flush pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-output +{ + printf("driver output pid %s port %s port name %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::driver-outputv +{ + printf("driver outputv pid %s port %s port name %s bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::driver-control +{ + printf("driver control pid %s port %s port name %s command %d bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, arg4); +} + +erlang*:::driver-call +{ + printf("driver call pid %s port %s port name %s command %d bytes %d\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, arg4); +} + +erlang*:::driver-event +{ + printf("driver event pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_input +{ + printf("driver ready_input pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_output +{ + printf("driver ready_output pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-timeout +{ + printf("driver timeout pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-ready_async +{ + printf("driver ready_async pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-process_exit +{ + printf("driver process_exit pid %s port %s port name %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::driver-stop_select +{ + printf("driver stop_select driver name %s\n", copyinstr(arg0)); +} diff --git a/lib/runtime_tools/examples/driver1.systemtap b/lib/runtime_tools/examples/driver1.systemtap new file mode 100644 index 0000000000..8b99e465b7 --- /dev/null +++ b/lib/runtime_tools/examples/driver1.systemtap @@ -0,0 +1,125 @@ +/* example usage: stap /path/to/driver1.systemtap -x */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("driver-init") +{ + printf("driver init name %s major %d minor %d flags %d\n", + user_string($arg1), $arg2, $arg3, $arg4); +} + +probe process("beam").mark("driver-start") +{ + printf("driver start pid %s driver name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-stop") +{ + printf("driver stop pid %s driver name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-finish") +{ + printf("driver finish driver name %s\n", + user_string($arg1)); +} + +probe process("beam").mark("driver-flush") +{ + printf("driver flush pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-output") +{ + printf("driver output pid %s port %s port name %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("driver-outputv") +{ + printf("driver outputv pid %s port %s port name %s bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); +} + +probe process("beam").mark("driver-control") +{ + printf("driver control pid %s port %s port name %s command %d bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); +} + +probe process("beam").mark("driver-call") +{ + printf("driver call pid %s port %s port name %s command %d bytes %d\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, $arg5); +} + +probe process("beam").mark("driver-event") +{ + printf("driver event pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_input") +{ + printf("driver ready_input pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_output") +{ + printf("driver ready_output pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-timeout") +{ + printf("driver timeout pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-ready_async") +{ + printf("driver ready_async pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-process_exit") +{ + printf("driver process_exit pid %s port %s port name %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("driver-stop_select") +{ + printf("driver stop_select driver name %s\n", user_string($arg1)); +} diff --git a/lib/runtime_tools/examples/efile_drv.d b/lib/runtime_tools/examples/efile_drv.d new file mode 100644 index 0000000000..085995ce58 --- /dev/null +++ b/lib/runtime_tools/examples/efile_drv.d @@ -0,0 +1,104 @@ +/* example usage: dtrace -q -s /path/to/efile_drv.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +BEGIN +{ + op_map[1] = "OPEN"; + op_map[2] = "READ"; + op_map[3] = "LSEEK"; + op_map[4] = "WRITE"; + op_map[5] = "FSTAT"; + op_map[6] = "PWD"; + op_map[7] = "READDIR"; + op_map[8] = "CHDIR"; + op_map[9] = "FSYNC"; + op_map[10] = "MKDIR"; + op_map[11] = "DELETE"; + op_map[12] = "RENAME"; + op_map[13] = "RMDIR"; + op_map[14] = "TRUNCATE"; + op_map[15] = "READ_FILE"; + op_map[16] = "WRITE_INFO"; + op_map[19] = "LSTAT"; + op_map[20] = "READLINK"; + op_map[21] = "LINK"; + op_map[22] = "SYMLINK"; + op_map[23] = "CLOSE"; + op_map[24] = "PWRITEV"; + op_map[25] = "PREADV"; + op_map[26] = "SETOPT"; + op_map[27] = "IPREAD"; + op_map[28] = "ALTNAME"; + op_map[29] = "READ_LINE"; + op_map[30] = "FDATASYNC"; + op_map[31] = "FADVISE"; +} + +erlang*:::aio_pool-add +{ + printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1); +} + +erlang*:::aio_pool-get +{ + printf("async I/O pool port %s queue len %d\n", copyinstr(arg0), arg1); +} + +erlang*:::efile_drv-entry +{ + printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n", + arg0, arg1, + arg2 == NULL ? "" : "user tag ", + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3, + arg4 == NULL ? "" : copyinstr(arg4), + arg5 == NULL ? "" : copyinstr(arg5), arg6, arg7, + /* NOTE: port name in args[10] is experimental */ + (args[10] == NULL) ? + "?" : copyinstr((user_addr_t) args[10])); +} + +erlang*:::efile_drv-int* +{ + printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n", + arg0, arg1, op_map[arg2], arg2, probename); +} + +/* efile_drv-return error case */ +erlang*:::efile_drv-return +/arg4 == 0/ +{ + printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n", + arg0, arg1, + arg2 == NULL ? "" : "user tag ", + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3, + arg5); +} + +/* efile_drv-return success case */ +erlang*:::efile_drv-return +/arg4 != 0/ +{ + printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n", + arg0, arg1, + arg2 == NULL ? "" : copyinstr(arg2), + op_map[arg3], arg3); +} diff --git a/lib/runtime_tools/examples/efile_drv.systemtap b/lib/runtime_tools/examples/efile_drv.systemtap new file mode 100644 index 0000000000..5a47b3e22b --- /dev/null +++ b/lib/runtime_tools/examples/efile_drv.systemtap @@ -0,0 +1,112 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + op_map[1] = "OPEN"; + op_map[2] = "READ"; + op_map[3] = "LSEEK"; + op_map[4] = "WRITE"; + op_map[5] = "FSTAT"; + op_map[6] = "PWD"; + op_map[7] = "READDIR"; + op_map[8] = "CHDIR"; + op_map[9] = "FSYNC"; + op_map[10] = "MKDIR"; + op_map[11] = "DELETE"; + op_map[12] = "RENAME"; + op_map[13] = "RMDIR"; + op_map[14] = "TRUNCATE"; + op_map[15] = "READ_FILE"; + op_map[16] = "WRITE_INFO"; + op_map[19] = "LSTAT"; + op_map[20] = "READLINK"; + op_map[21] = "LINK"; + op_map[22] = "SYMLINK"; + op_map[23] = "CLOSE"; + op_map[24] = "PWRITEV"; + op_map[25] = "PREADV"; + op_map[26] = "SETOPT"; + op_map[27] = "IPREAD"; + op_map[28] = "ALTNAME"; + op_map[29] = "READ_LINE"; + op_map[30] = "FDATASYNC"; + op_map[31] = "FADVISE"; +} + +probe process("beam").mark("aio_pool-add") +{ + printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("aio_pool-get") +{ + printf("async I/O pool port %s queue len %d\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("efile_drv-entry") +{ + printf("efile_drv enter tag={%d,%d} %s%s | %s (%d) | args: %s %s , %d %d (port %s)\n", + $arg1, $arg2, + $arg3 == NULL ? "" : "user tag ", + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4, + $arg5 == NULL ? "" : user_string($arg5), + $arg6 == NULL ? "" : user_string($arg6), $arg7, $arg8, + /* NOTE: port name in $arg[11] is experimental */ + user_string($arg11)) +} + +probe process("beam").mark("efile_drv-int*") +{ + printf("async I/O worker tag={%d,%d} | %s (%d) | %s\n", + $arg1, $arg2, op_map[$arg3], $arg3, probefunc()); +} + +probe process("beam").mark("efile_drv-return") +{ + if ($arg5 == 0) { + /* efile_drv-return error case */ + printf("efile_drv return tag={%d,%d} %s%s | %s (%d) | errno %d\n", + $arg1, $arg2, + $arg3 == NULL ? "" : "user tag ", + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4, + $arg6); + } else { + /* efile_drv-return success case */ + printf("efile_drv return tag={%d,%d} %s | %s (%d) ok\n", + $arg1, $arg2, + $arg3 == NULL ? "" : user_string($arg3), + op_map[$arg4], $arg4); + } +} + +global op_map; diff --git a/lib/runtime_tools/examples/function-calls.d b/lib/runtime_tools/examples/function-calls.d new file mode 100644 index 0000000000..238c5211ac --- /dev/null +++ b/lib/runtime_tools/examples/function-calls.d @@ -0,0 +1,51 @@ +/* example usage: dtrace -q -s /path/to/function-calls.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::function-entry +{ + printf("pid %s enter %s depth %d\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::function-return +{ + printf("pid %s return %s depth %d\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::bif-entry +{ + printf("pid %s BIF entry mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::bif-return +{ + printf("pid %s BIF return mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::nif-entry +{ + printf("pid %s NIF entry mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::nif-return +{ + printf("pid %s NIF return mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} diff --git a/lib/runtime_tools/examples/function-calls.systemtap b/lib/runtime_tools/examples/function-calls.systemtap new file mode 100644 index 0000000000..8fc4375135 --- /dev/null +++ b/lib/runtime_tools/examples/function-calls.systemtap @@ -0,0 +1,61 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("function-entry") +{ + printf("pid %s enter %s depth %d\n", + user_string($arg1), user_string($arg2), $arg3); +} + +probe process("beam").mark("function-return") +{ + printf("pid %s return %s depth %d\n", + user_string($arg1), user_string($arg2), $arg3); +} + +probe process("beam").mark("bif-entry") +{ + printf("pid %s BIF entry mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("bif-return") +{ + printf("pid %s BIF return mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("nif-entry") +{ + printf("pid %s NIF entry mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("nif-return") +{ + printf("pid %s NIF return mfa %s\n", user_string($arg1), user_string($arg2)); +} diff --git a/lib/runtime_tools/examples/garbage-collection.d b/lib/runtime_tools/examples/garbage-collection.d new file mode 100644 index 0000000000..f234e7d4db --- /dev/null +++ b/lib/runtime_tools/examples/garbage-collection.d @@ -0,0 +1,39 @@ +/* example usage: dtrace -q -s /path/to/garbage-collection.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::gc_major-start +{ + printf("GC major start pid %s need %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_minor-start +{ + printf("GC minor start pid %s need %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_major-end +{ + printf("GC major end pid %s reclaimed %d words\n", copyinstr(arg0), arg1); +} + +erlang*:::gc_minor-start +{ + printf("GC minor end pid %s reclaimed %d words\n", copyinstr(arg0), arg1); +} diff --git a/lib/runtime_tools/examples/garbage-collection.systemtap b/lib/runtime_tools/examples/garbage-collection.systemtap new file mode 100644 index 0000000000..64d69c6fbd --- /dev/null +++ b/lib/runtime_tools/examples/garbage-collection.systemtap @@ -0,0 +1,49 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("gc_major-start") +{ + printf("GC major start pid %s need %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_minor-start") +{ + printf("GC minor start pid %s need %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_major-end") +{ + printf("GC major end pid %s reclaimed %d words\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("gc_minor-start") +{ + printf("GC minor end pid %s reclaimed %d words\n", user_string($arg1), $arg2); +} diff --git a/lib/runtime_tools/examples/memory1.d b/lib/runtime_tools/examples/memory1.d new file mode 100644 index 0000000000..c2e16e0779 --- /dev/null +++ b/lib/runtime_tools/examples/memory1.d @@ -0,0 +1,41 @@ +/* example usage: dtrace -q -s /path/to/memory1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::copy-struct +{ + printf("copy_struct %d bytes\n", arg0); +} + +erlang*:::copy-object +{ + printf("copy_object pid %s %d bytes\n", copyinstr(arg0), arg1); +} + +erlang*:::process-heap_grow +{ + printf("proc heap grow pid %s %d -> %d bytes\n", copyinstr(arg0), + arg1, arg2); +} + +erlang*:::process-heap_shrink +{ + printf("proc heap shrink pid %s %d -> %d bytes\n", copyinstr(arg0), + arg1, arg2); +} diff --git a/lib/runtime_tools/examples/memory1.systemtap b/lib/runtime_tools/examples/memory1.systemtap new file mode 100644 index 0000000000..9723f2d02d --- /dev/null +++ b/lib/runtime_tools/examples/memory1.systemtap @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("copy-struct") +{ + printf("copy_struct %d bytes\n", $arg1); +} + +probe process("beam").mark("copy-object") +{ + printf("copy_object pid %s %d bytes\n", user_string($arg1), $arg2); +} + +probe process("beam").mark("process-heap_grow") +{ + printf("proc heap grow pid %s %d -> %d bytes\n", user_string($arg1), + $arg2, $arg3); +} + +probe process("beam").mark("process-heap_shrink") +{ + printf("proc heap shrink pid %s %d -> %d bytes\n", user_string($arg1), + $arg2, $arg3); +} diff --git a/lib/runtime_tools/examples/messages.d b/lib/runtime_tools/examples/messages.d new file mode 100644 index 0000000000..6361f3a220 --- /dev/null +++ b/lib/runtime_tools/examples/messages.d @@ -0,0 +1,94 @@ +/* example usage: dtrace -q -s /path/to/messages.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +BEGIN +{ + printf("\n"); + printf("NOTE: message-queue message size 4294967295 means an external\n"); + printf(" message that the code isn't smart enough to determine\n"); + printf(" the actual size.\n"); + printf("\n"); +} + +erlang*:::message-send +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("send: %s -> %s: %d words\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::message-send +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("send: %s label %d token {%d,%d} -> %s: %d words\n", + copyinstr(arg0), + arg3, arg4, arg5, + copyinstr(arg1), arg2); +} + +/* + * TODO: + * Weird, on my OS X box, beam says arg6 = 0 but this script says 4294967296. + */ + +erlang*:::message-send-remote +/arg4 == 0 && arg5 == 0 && (arg6 == 0 || arg6 >= 4294967296)/ +{ + printf("send : %s -> %s %s: %d words\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::message-send-remote +/arg4 != 0 || arg5 != 0 || arg6 < 4294967296/ +{ + printf("send : %s label %d token {%d,%d} -> %s %s: %d words\n", + copyinstr(arg0), + arg4, arg5, arg6, + copyinstr(arg1), copyinstr(arg2), arg3); +} + +erlang*:::message-queued +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("queued: %s: %d words, queue len %d\n", copyinstr(arg0), arg1, arg2); +} + +erlang*:::message-queued +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("queued: %s label %d token {%d,%d}: %d words, queue len %d\n", + copyinstr(arg0), arg3, arg4, arg5, + arg1, arg2); +} + +erlang*:::message-receive +/arg3 == 0 && arg4 == 0 && arg5 == 0/ +{ + printf("receive: %s: %d words, queue len %d\n", + copyinstr(arg0), arg1, arg2); +} + +erlang*:::message-receive +/arg3 != 0 || arg4 != 0 || arg5 != 0/ +{ + printf("receive: %s label %d token {%d,%d}: %d words, queue len %d\n", + copyinstr(arg0), arg3, arg4, arg5, + arg1, arg2); +} diff --git a/lib/runtime_tools/examples/messages.systemtap b/lib/runtime_tools/examples/messages.systemtap new file mode 100644 index 0000000000..ff8f4076b1 --- /dev/null +++ b/lib/runtime_tools/examples/messages.systemtap @@ -0,0 +1,87 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + printf("\n"); + printf("NOTE: message-queue message size 4294967295 means an external\n"); + printf(" message that the code isn't smart enough to determine\n"); + printf(" the actual size.\n"); + printf("\n"); +} + +probe process("beam").mark("message-send") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("send: %s -> %s: %d words\n", + user_string($arg1), user_string($arg2), $arg3); + } else { + printf("send: %s label %d token {%d,%d} -> %s: %d words\n", + user_string($arg1), + $arg4, $arg5, $arg6, + user_string($arg2), $arg3); + } +} + +probe process("beam").mark("message-send-remote") +{ + if ($arg5 == 0 && $arg6 == 0 && $arg7 == 0) { + printf("send : %s -> %s %s: %d words\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4); + } else { + printf("send : %s label %d token {%d,%d} -> %s %s: %d words\n", + user_string($arg1), + $arg5, $arg6, $arg7, + user_string($arg2), user_string($arg3), $arg4); + } +} + +probe process("beam").mark("message-queued") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("queued: %s: %d words, queue len %d\n", user_string($arg1), $arg2, $arg3); + } else { + printf("queued: %s label %d token {%d,%d}: %d words, queue len %d\n", + user_string($arg1), $arg4, $arg5, $arg6, + $arg2, $arg3); + } +} + +probe process("beam").mark("message-receive") +{ + if ($arg4 == 0 && $arg5 == 0 && $arg6 == 0) { + printf("receive: %s: %d words, queue len %d\n", + user_string($arg1), $arg2, $arg3); + } else { + printf("receive: %s label %d token {%d,%d}: %d words, queue len %d\n", + user_string($arg1), $arg4, $arg5, $arg6, + $arg2, $arg3); + } +} diff --git a/lib/runtime_tools/examples/port1.d b/lib/runtime_tools/examples/port1.d new file mode 100644 index 0000000000..204abbd3b8 --- /dev/null +++ b/lib/runtime_tools/examples/port1.d @@ -0,0 +1,142 @@ +/* example usage: dtrace -q -s /path/to/port1.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +BEGIN +{ + driver_map["tcp_inet", 1] = "OPEN"; + driver_map["tcp_inet", 2] = "CLOSE"; + driver_map["tcp_inet", 3] = "CONNECT"; + driver_map["tcp_inet", 4] = "PEER"; + driver_map["tcp_inet", 5] = "NAME"; + driver_map["tcp_inet", 6] = "BIND"; + driver_map["tcp_inet", 7] = "SETOPTS"; + driver_map["tcp_inet", 8] = "GETOPTS"; + driver_map["tcp_inet", 11] = "GETSTAT"; + driver_map["tcp_inet", 12] = "GETHOSTNAME"; + driver_map["tcp_inet", 13] = "FDOPEN"; + driver_map["tcp_inet", 14] = "GETFD"; + driver_map["tcp_inet", 15] = "GETTYPE"; + driver_map["tcp_inet", 16] = "GETSTATUS"; + driver_map["tcp_inet", 17] = "GETSERVBYNAME"; + driver_map["tcp_inet", 18] = "GETSERVBYPORT"; + driver_map["tcp_inet", 19] = "SETNAME"; + driver_map["tcp_inet", 20] = "SETPEER"; + driver_map["tcp_inet", 21] = "GETIFLIST"; + driver_map["tcp_inet", 22] = "IFGET"; + driver_map["tcp_inet", 23] = "IFSET"; + driver_map["tcp_inet", 24] = "SUBSCRIBE"; + driver_map["tcp_inet", 25] = "GETIFADDRS"; + driver_map["tcp_inet", 40] = "ACCEPT"; + driver_map["tcp_inet", 41] = "LISTEN"; + driver_map["tcp_inet", 42] = "RECV"; + driver_map["tcp_inet", 43] = "UNRECV"; + driver_map["tcp_inet", 44] = "SHUTDOWN"; + driver_map["tcp_inet", 60] = "RECV"; + driver_map["tcp_inet", 61] = "LISTEN"; + driver_map["tcp_inet", 62] = "BINDX"; + /* No looping constructs, so repeat for udp_inet */ + driver_map["udp_inet", 1] = "OPEN"; + driver_map["udp_inet", 2] = "CLOSE"; + driver_map["udp_inet", 3] = "CONNECT"; + driver_map["udp_inet", 4] = "PEER"; + driver_map["udp_inet", 5] = "NAME"; + driver_map["udp_inet", 6] = "BIND"; + driver_map["udp_inet", 7] = "SETOPTS"; + driver_map["udp_inet", 8] = "GETOPTS"; + driver_map["udp_inet", 11] = "GETSTAT"; + driver_map["udp_inet", 12] = "GETHOSTNAME"; + driver_map["udp_inet", 13] = "FDOPEN"; + driver_map["udp_inet", 14] = "GETFD"; + driver_map["udp_inet", 15] = "GETTYPE"; + driver_map["udp_inet", 16] = "GETSTATUS"; + driver_map["udp_inet", 17] = "GETSERVBYNAME"; + driver_map["udp_inet", 18] = "GETSERVBYPORT"; + driver_map["udp_inet", 19] = "SETNAME"; + driver_map["udp_inet", 20] = "SETPEER"; + driver_map["udp_inet", 21] = "GETIFLIST"; + driver_map["udp_inet", 22] = "IFGET"; + driver_map["udp_inet", 23] = "IFSET"; + driver_map["udp_inet", 24] = "SUBSCRIBE"; + driver_map["udp_inet", 25] = "GETIFADDRS"; + driver_map["udp_inet", 40] = "ACCEPT"; + driver_map["udp_inet", 41] = "LISTEN"; + driver_map["udp_inet", 42] = "RECV"; + driver_map["udp_inet", 43] = "UNRECV"; + driver_map["udp_inet", 44] = "SHUTDOWN"; + driver_map["udp_inet", 60] = "RECV"; + driver_map["udp_inet", 61] = "LISTEN"; + driver_map["udp_inet", 62] = "BINDX"; +} + +erlang*:::port-open +{ + printf("port open pid %s port name %s port %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::port-command +{ + printf("port command pid %s port %s port name %s command type %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-control +{ + /* http://dtrace.org/blogs/brendan/2011/11/25/dtrace-variable-types/ */ + this->cmd = driver_map[copyinstr(arg2), arg3]; + this->cmd_str = (this->cmd == 0) ? "unknown" : this->cmd; + printf("port control pid %s port %s port name %s command %d %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3, + this->cmd_str); +} + +/* port-exit is fired as a result of port_close() or exit signal */ + +erlang*:::port-exit +{ + printf("port exit pid %s port %s port name %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-connect +{ + printf("port connect pid %s port %s port name %s new pid %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} + +erlang*:::port-busy +{ + printf("port busy %s\n", copyinstr(arg0)); +} + +erlang*:::port-not_busy +{ + printf("port not busy %s\n", copyinstr(arg0)); +} + +erlang*:::aio_pool-add +{ + printf("async I/O pool add thread %d queue len %d\n", arg0, arg1); +} + +erlang*:::aio_pool-get +{ + printf("async I/O pool get thread %d queue len %d\n", arg0, arg1); +} diff --git a/lib/runtime_tools/examples/port1.systemtap b/lib/runtime_tools/examples/port1.systemtap new file mode 100644 index 0000000000..a63d9b670c --- /dev/null +++ b/lib/runtime_tools/examples/port1.systemtap @@ -0,0 +1,152 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe begin +{ + driver_map["tcp_inet", 1] = "OPEN"; + driver_map["tcp_inet", 2] = "CLOSE"; + driver_map["tcp_inet", 3] = "CONNECT"; + driver_map["tcp_inet", 4] = "PEER"; + driver_map["tcp_inet", 5] = "NAME"; + driver_map["tcp_inet", 6] = "BIND"; + driver_map["tcp_inet", 7] = "SETOPTS"; + driver_map["tcp_inet", 8] = "GETOPTS"; + driver_map["tcp_inet", 11] = "GETSTAT"; + driver_map["tcp_inet", 12] = "GETHOSTNAME"; + driver_map["tcp_inet", 13] = "FDOPEN"; + driver_map["tcp_inet", 14] = "GETFD"; + driver_map["tcp_inet", 15] = "GETTYPE"; + driver_map["tcp_inet", 16] = "GETSTATUS"; + driver_map["tcp_inet", 17] = "GETSERVBYNAME"; + driver_map["tcp_inet", 18] = "GETSERVBYPORT"; + driver_map["tcp_inet", 19] = "SETNAME"; + driver_map["tcp_inet", 20] = "SETPEER"; + driver_map["tcp_inet", 21] = "GETIFLIST"; + driver_map["tcp_inet", 22] = "IFGET"; + driver_map["tcp_inet", 23] = "IFSET"; + driver_map["tcp_inet", 24] = "SUBSCRIBE"; + driver_map["tcp_inet", 25] = "GETIFADDRS"; + driver_map["tcp_inet", 40] = "ACCEPT"; + driver_map["tcp_inet", 41] = "LISTEN"; + driver_map["tcp_inet", 42] = "RECV"; + driver_map["tcp_inet", 43] = "UNRECV"; + driver_map["tcp_inet", 44] = "SHUTDOWN"; + driver_map["tcp_inet", 60] = "RECV"; + driver_map["tcp_inet", 61] = "LISTEN"; + driver_map["tcp_inet", 62] = "BINDX"; + /* No looping constructs, so repeat for udp_inet */ + driver_map["udp_inet", 1] = "OPEN"; + driver_map["udp_inet", 2] = "CLOSE"; + driver_map["udp_inet", 3] = "CONNECT"; + driver_map["udp_inet", 4] = "PEER"; + driver_map["udp_inet", 5] = "NAME"; + driver_map["udp_inet", 6] = "BIND"; + driver_map["udp_inet", 7] = "SETOPTS"; + driver_map["udp_inet", 8] = "GETOPTS"; + driver_map["udp_inet", 11] = "GETSTAT"; + driver_map["udp_inet", 12] = "GETHOSTNAME"; + driver_map["udp_inet", 13] = "FDOPEN"; + driver_map["udp_inet", 14] = "GETFD"; + driver_map["udp_inet", 15] = "GETTYPE"; + driver_map["udp_inet", 16] = "GETSTATUS"; + driver_map["udp_inet", 17] = "GETSERVBYNAME"; + driver_map["udp_inet", 18] = "GETSERVBYPORT"; + driver_map["udp_inet", 19] = "SETNAME"; + driver_map["udp_inet", 20] = "SETPEER"; + driver_map["udp_inet", 21] = "GETIFLIST"; + driver_map["udp_inet", 22] = "IFGET"; + driver_map["udp_inet", 23] = "IFSET"; + driver_map["udp_inet", 24] = "SUBSCRIBE"; + driver_map["udp_inet", 25] = "GETIFADDRS"; + driver_map["udp_inet", 40] = "ACCEPT"; + driver_map["udp_inet", 41] = "LISTEN"; + driver_map["udp_inet", 42] = "RECV"; + driver_map["udp_inet", 43] = "UNRECV"; + driver_map["udp_inet", 44] = "SHUTDOWN"; + driver_map["udp_inet", 60] = "RECV"; + driver_map["udp_inet", 61] = "LISTEN"; + driver_map["udp_inet", 62] = "BINDX"; +} + +probe process("beam").mark("port-open") +{ + printf("port open pid %s port name %s port %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("port-command") +{ + printf("port command pid %s port %s port name %s command type %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-control") +{ + cmd = driver_map[user_string($arg3), $arg4]; + cmd_str = (cmd == "") ? "unknown" : cmd; + printf("port control pid %s port %s port name %s command %d %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), $arg4, cmd_str); +} + +/* port-exit is fired as a result of port_close() or exit signal */ + +probe process("beam").mark("port-exit") +{ + printf("port exit pid %s port %s port name %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-connect") +{ + printf("port connect pid %s port %s port name %s new pid %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} + +probe process("beam").mark("port-busy") +{ + printf("port busy %s\n", user_string($arg1)); +} + +probe process("beam").mark("port-not_busy") +{ + printf("port not busy %s\n", user_string($arg1)); +} + +probe process("beam").mark("aio_pool-add") +{ + printf("async I/O pool add thread %d queue len %d\n", $arg1, $arg2); +} + +probe process("beam").mark("aio_pool-get") +{ + printf("async I/O pool get thread %d queue len %d\n", $arg1, $arg2); +} + +global driver_map; \ No newline at end of file diff --git a/lib/runtime_tools/examples/process-scheduling.d b/lib/runtime_tools/examples/process-scheduling.d new file mode 100644 index 0000000000..79e9cc598c --- /dev/null +++ b/lib/runtime_tools/examples/process-scheduling.d @@ -0,0 +1,35 @@ +/* example usage: dtrace -q -s /path/to/process-scheduling.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::process-scheduled +{ + printf(" Schedule pid %s mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-unscheduled +{ + printf("Unschedule pid %s\n", copyinstr(arg0)); +} + +erlang*:::process-hibernate +{ + printf(" Hibernate pid %s resume mfa %s\n", + copyinstr(arg0), copyinstr(arg1)); +} diff --git a/lib/runtime_tools/examples/process-scheduling.systemtap b/lib/runtime_tools/examples/process-scheduling.systemtap new file mode 100644 index 0000000000..c8cee60a07 --- /dev/null +++ b/lib/runtime_tools/examples/process-scheduling.systemtap @@ -0,0 +1,45 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("process-scheduled") +{ + printf(" Schedule pid %s mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-unscheduled") +{ + printf("Unschedule pid %s\n", user_string($arg1)); +} + +probe process("beam").mark("process-hibernate") +{ + printf(" Hibernate pid %s resume mfa %s\n", + user_string($arg1), user_string($arg2)); +} diff --git a/lib/runtime_tools/examples/spawn-exit.d b/lib/runtime_tools/examples/spawn-exit.d new file mode 100644 index 0000000000..7310f3343d --- /dev/null +++ b/lib/runtime_tools/examples/spawn-exit.d @@ -0,0 +1,41 @@ +/* example usage: dtrace -q -s /path/to/spawn-exit.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::process-spawn +{ + printf("pid %s mfa %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-exit +{ + printf("pid %s reason %s\n", copyinstr(arg0), copyinstr(arg1)); +} + +erlang*:::process-exit_signal +{ + printf("sender %s -> pid %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); +} + +erlang*:::process-exit_signal-remote +{ + printf("sender %s -> node %s pid %s reason %s\n", + copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), copyinstr(arg3)); +} diff --git a/lib/runtime_tools/examples/spawn-exit.systemtap b/lib/runtime_tools/examples/spawn-exit.systemtap new file mode 100644 index 0000000000..5e3be9fc1b --- /dev/null +++ b/lib/runtime_tools/examples/spawn-exit.systemtap @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("beam").mark("process-spawn") +{ + printf("pid %s mfa %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-exit") +{ + printf("pid %s reason %s\n", user_string($arg1), user_string($arg2)); +} + +probe process("beam").mark("process-exit_signal") +{ + printf("sender %s -> pid %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3)); +} + +probe process("beam").mark("process-exit_signal-remote") +{ + printf("sender %s -> node %s pid %s reason %s\n", + user_string($arg1), user_string($arg2), user_string($arg3), user_string($arg4)); +} diff --git a/lib/runtime_tools/examples/user-probe.d b/lib/runtime_tools/examples/user-probe.d new file mode 100644 index 0000000000..13baff6a32 --- /dev/null +++ b/lib/runtime_tools/examples/user-probe.d @@ -0,0 +1,36 @@ +/* example usage: dtrace -q -s /path/to/user-probe.d */ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ + +erlang*:::user_trace-s1 +{ + printf("%s\n", copyinstr(arg0)); +} + +erlang*:::user_trace-i4s4 +{ + printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", + copyinstr(arg0), + arg1 == NULL ? "" : copyinstr(arg1), + arg2, arg3, arg4, arg5, + arg6 == NULL ? "" : copyinstr(arg6), + arg7 == NULL ? "" : copyinstr(arg7), + arg8 == NULL ? "" : copyinstr(arg8), + arg9 == NULL ? "" : copyinstr(arg9)); +} diff --git a/lib/runtime_tools/examples/user-probe.systemtap b/lib/runtime_tools/examples/user-probe.systemtap new file mode 100644 index 0000000000..84a45709e8 --- /dev/null +++ b/lib/runtime_tools/examples/user-probe.systemtap @@ -0,0 +1,46 @@ +/* + * %CopyrightBegin% + * + * Copyright Scott Lystig Fritchie and Andreas Schultz, 2011. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +/* + * Note: This file assumes that you're using the non-SMP-enabled Erlang + * virtual machine, "beam". The SMP-enabled VM is called "beam.smp". + * Note that other variations of the virtual machine also have + * different names, e.g. the debug build of the SMP-enabled VM + * is "beam.debug.smp". + * + * To use a different virtual machine, replace each instance of + * "beam" with "beam.smp" or the VM name appropriate to your + * environment. + */ + +probe process("dyntrace.so").mark("user_trace-s1") +{ + printf("%s\n", user_string($arg1)); +} + +probe process("dyntrace.so").mark("user_trace-i4s4") +{ + printf("%s %s %d %d %d %d '%s' '%s' '%s' '%s'\n", + user_string($arg1), + $arg2 == NULL ? "" : user_string($arg2), + $arg3, $arg4, $arg5, $arg6, + $arg7 == NULL ? "" : user_string($arg7), + $arg8 == NULL ? "" : user_string($arg8), + $arg9 == NULL ? "" : user_string($arg9), + $arg9 == NULL ? "" : user_string($arg9)); +} diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile index 946409b262..6dc89bea32 100644 --- a/lib/runtime_tools/src/Makefile +++ b/lib/runtime_tools/src/Makefile @@ -45,6 +45,7 @@ MODULES= \ runtime_tools \ runtime_tools_sup \ dbg \ + dyntrace \ percept_profile \ observer_backend \ ttb_autostart @@ -64,10 +65,15 @@ APPUP_FILE= runtime_tools.appup APPUP_SRC= $(APPUP_FILE).src APPUP_TARGET= $(EBIN)/$(APPUP_FILE) +EXAMPLE_FILES= \ + ../examples/* # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -ERL_COMPILE_FLAGS += -I../include +ERL_COMPILE_FLAGS += \ + -I../include \ + -I ../../et/include \ + -I ../../../libraries/et/include # ---------------------------------------------------- # Targets @@ -97,6 +103,8 @@ release_spec: opt $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)/src $(INSTALL_DIR) $(RELSYSDIR)/include $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples $(INSTALL_DIR) $(RELSYSDIR)/ebin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin diff --git a/lib/runtime_tools/src/dyntrace.erl b/lib/runtime_tools/src/dyntrace.erl new file mode 100644 index 0000000000..20472a2be6 --- /dev/null +++ b/lib/runtime_tools/src/dyntrace.erl @@ -0,0 +1,279 @@ +-module(dyntrace). + +%%% @doc The Dynamic tracing interface module +%%% +%%% This Dynamic tracing interface module, with the corresponding NIFs, should +%%% work on any operating system platform where user-space DTrace/Systemtap +%%% (and in the future LttNG UST) probes are supported. +%%% +%%% Use the `dyntrace:init()' function to load the NIF shared library and +%%% to initialize library's private state. +%%% +%%% It is recommended that you use the `dyntrace:p()' function to add +%%% Dynamic trace probes to your Erlang code. This function can accept up to +%%% four integer arguments and four string arguments; the integer +%%% argument(s) must come before any string argument. For example: +%%% ``` +%%% 1> dyntrace:put_utag("GGOOOAAALL!!!!!"). +%%% true +%%% 2> dyntrace:init(). +%%% ok +%%% +%%% % % % If using dtrace, enable the Dynamic trace probe using the 'dtrace' +%%% % % % command. +%%% +%%% 3> dyntrace:p(7, 8, 9, "one", "four"). +%%% true +%%% ''' +%%% +%%% Output from the example D script `user-probe.d' looks like: +%%% ``` +%%% <0.34.0> GGOOOAAALL!!!!! 7 8 9 0 'one' 'four' '' '' +%%% ''' +%%% +%%% If the expected type of variable is not present, e.g. integer when +%%% integer() is expected, or an I/O list when iolist() is expected, +%%% then the driver will ignore the user's input and use a default +%%% value of 0 or NULL, respectively. + +-export([available/0, + user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 + p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). +-export([put_utag/1, get_utag/0, get_utag_data/0, spread_utag/1, restore_utag/1]). + +-export([scaff/0]). % Development only +-export([user_trace_i4s4/9]). % Know what you're doing! +-on_load(on_load/0). + +-type probe_arg() :: integer() | iolist(). +-type int_p_arg() :: integer() | iolist() | undef. + +%% The *_maybe() types use atom() instead of a stricter 'undef' +%% because user_trace_i4s4/9 is exposed to the outside world, and +%% because the driver will allow any atom to be used as a "not +%% present" indication, we'll allow any atom in the types. + +-type integer_maybe() :: integer() | atom(). +-type iolist_maybe() :: iolist() | atom(). + +on_load() -> + PrivDir = code:priv_dir(runtime_tools), + LibName = "dyntrace", + Lib = filename:join([PrivDir, "lib", LibName]), + Status = case erlang:load_nif(Lib, 0) of + ok -> ok; + {error, {load_failed, _}}=Error1 -> + ArchLibDir = + filename:join([PrivDir, "lib", + erlang:system_info(system_architecture)]), + Candidate = + filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])), + case Candidate of + [] -> Error1; + _ -> + ArchLib = filename:join([ArchLibDir, LibName]), + erlang:load_nif(ArchLib, 0) + end; + Error1 -> Error1 + end, + case Status of + ok -> ok; + {error, {E, Str}} -> + case erlang:system_info(dynamic_trace) of + none -> + ok; + _ -> + error_logger:error_msg("Unable to load dyntrace library. Failed with error:~n +\"~p, ~s\"~n" + "Dynamic tracing is enabled but the driver is not built correctly~n",[ + E,Str]), + Status + end + end. + +%%% +%%% NIF placeholders +%%% + +-spec available() -> true | false. + +available() -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_s1(iolist()) -> true | false | error | badarg. + +user_trace_s1(_Message) -> + erlang:nif_error(nif_not_loaded). + +-spec user_trace_i4s4(iolist(), + integer_maybe(), integer_maybe(), + integer_maybe(), integer_maybe(), + iolist_maybe(), iolist_maybe(), + iolist_maybe(), iolist_maybe()) -> + true | false | error | badarg. + +user_trace_i4s4(_, _, _, _, _, _, _, _, _) -> + erlang:nif_error(nif_not_loaded). + +%%% +%%% Erlang support functions +%%% + +-spec p() -> true | false | error | badarg. + +p() -> + user_trace_int(undef, undef, undef, undef, undef, undef, undef, undef). + +-spec p(probe_arg()) -> true | false | error | badarg. + +p(I1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, undef, undef, undef, undef); +p(S1) -> + user_trace_int(undef, undef, undef, undef, S1, undef, undef, undef). + +-spec p(probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, undef, undef, undef, undef); +p(I1, S1) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, undef, undef, undef); +p(S1, S2) -> + user_trace_int(undef, undef, undef, undef, S1, S2, undef, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg()) -> true | false | error | badarg. + +p(I1, I2, I3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, undef, undef, undef, undef); +p(I1, I2, S1) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, undef, undef, undef); +p(I1, S1, S2) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, undef, undef); +p(S1, S2, S3) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, undef). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, undef, undef, undef, undef); +p(I1, I2, I3, S1) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, undef, undef, undef); +p(I1, I2, S1, S2) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, undef, undef); +p(I1, S1, S2, S3) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, undef); +p(S1, S2, S3, S4) -> + user_trace_int(undef, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, undef, undef, undef); +p(I1, I2, I3, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, undef, undef); +p(I1, I2, S1, S2, S3) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, undef); +p(I1, S1, S2, S3, S4) when is_integer(I1) -> + user_trace_int(I1, undef, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, undef, undef); +p(I1, I2, I3, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, undef); +p(I1, I2, S1, S2, S3, S4) when is_integer(I1), is_integer(I2) -> + user_trace_int(I1, I2, undef, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, undef); +p(I1, I2, I3, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3) -> + user_trace_int(I1, I2, I3, undef, S1, S2, S3, S4). + +-spec p(probe_arg(), probe_arg(), probe_arg(), probe_arg(), + probe_arg(), probe_arg(), probe_arg(), probe_arg()) -> + true | false | error | badarg. + +p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_integer(I3), is_integer(I4) -> + user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4). + +-spec user_trace_int(int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg(), + int_p_arg(), int_p_arg(), int_p_arg(), int_p_arg()) -> + true | false | error | badarg. + +user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> + UTag = get_utag(), + try + user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4) + catch + error:nif_not_loaded -> + false + end. + +-spec put_utag(undefined | iodata()) -> binary() | undefined. +put_utag(Data) -> + erlang:put_utag(unicode:characters_to_binary(Data)). + +-spec get_utag() -> binary() | undefined. +get_utag() -> + erlang:get_utag(). + +-spec get_utag_data() -> binary() | undefined. +%% Gets utag if set, otherwise the spread utag data from last incoming message +get_utag_data() -> + erlang:get_utag_data(). + +-spec spread_utag(boolean()) -> true | {non_neg_integer(), binary() | []}. +%% Makes the utag behave as a sequential trace token, will spread with messages to be picked up by someone using +%% get_utag_data or get_drv_utag_data. +spread_utag(B) -> + erlang:spread_utag(B). + +-spec restore_utag(true | {non_neg_integer(), binary() | []}) -> true. +restore_utag(T) -> + erlang:restore_utag(T). + + +%% Scaffolding to write tedious code: quick brute force and not 100% correct. + +scaff_int_args(N) -> + L = lists:sublist(["I1", "I2", "I3", "I4"], N), + [string:join(L, ", ")]. + +scaff_int_guards(N) -> + L = lists:sublist(["is_integer(I1)", "is_integer(I2)", "is_integer(I3)", + "is_integer(I4)"], N), + lists:flatten(string:join(L, ", ")). + +scaff_char_args(N) -> + L = lists:sublist(["S1", "S2", "S3", "S4"], N), + [string:join(L, ", ")]. + +scaff_fill(N) -> + [string:join(lists:duplicate(N, "undef"), ", ")]. + +scaff() -> + L = [begin + IntArgs = scaff_int_args(N_int), + IntGuards = scaff_int_guards(N_int), + IntFill = scaff_fill(4 - N_int), + CharArgs = scaff_char_args(N_char), + CharFill = scaff_fill(4 - N_char), + InArgs = string:join(IntArgs ++ CharArgs, ", "), + OutArgs = string:join(IntArgs ++ IntFill ++ CharArgs ++ CharFill, + ", "), + {N_int + N_char, + lists:flatten([io_lib:format("p(~s) when ~s ->\n", + [InArgs, IntGuards]), + io_lib:format(" user_trace_int(~s);\n", [OutArgs]) + ])} + end || N_int <- [0,1,2,3,4], N_char <- [0,1,2,3,4]], + [io:format("%%~p\n~s", [N, Str]) || {N, Str} <- lists:sort(L)]. diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src index 76fd998530..a9d2d68857 100644 --- a/lib/runtime_tools/src/runtime_tools.app.src +++ b/lib/runtime_tools/src/runtime_tools.app.src @@ -23,7 +23,7 @@ inviso_rt,inviso_rt_lib,inviso_rt_meta, inviso_as_lib,inviso_autostart,inviso_autostart_server, runtime_tools,runtime_tools_sup,erts_alloc_config, - ttb_autostart]}, + ttb_autostart,dyntrace]}, {registered, [runtime_tools_sup,inviso_rt,inviso_rt_meta]}, {applications, [kernel, stdlib]}, % {env, [{inviso_autostart_mod,your_own_autostart_module}]}, -- cgit v1.2.3 From 326e098659de187099451bf20a33c3e6181b4141 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Fri, 9 Mar 2012 17:20:49 +0100 Subject: Ifdef all dynamic trace code --- erts/configure.in | 2 ++ erts/emulator/beam/beam_emu.c | 33 ++++++++++++++--------- erts/emulator/beam/copy.c | 2 ++ erts/emulator/beam/dist.c | 46 +++++++++++++++++++++++++-------- erts/emulator/beam/erl_async.c | 4 +++ erts/emulator/beam/erl_bif_port.c | 7 ++++- erts/emulator/beam/erl_gc.c | 15 ++++++++--- erts/emulator/beam/erl_message.c | 36 +++++++++++++++++--------- erts/emulator/beam/erl_nif.c | 4 +++ erts/emulator/beam/erl_port_task.c | 4 +++ erts/emulator/beam/erl_process.c | 8 ++++++ erts/emulator/beam/io.c | 39 +++++++++++++++++++++++++++- erts/emulator/sys/common/erl_check_io.c | 6 +++++ 13 files changed, 166 insertions(+), 40 deletions(-) diff --git a/erts/configure.in b/erts/configure.in index b94fe86dc7..cb1b00b8b1 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -323,7 +323,9 @@ AS_HELP_STRING([--enable-vm-probes], use_vm_probes=no fi) +AC_SUBST(USE_VM_PROBES) if test X"$use_vm_probes" = X"yes"; then + USE_VM_PROBES=yes AC_DEFINE(USE_VM_PROBES,[1], [Define to enable VM dynamic trace probes]) fi diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 8cfcbd0fb8..5c5d9fd049 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1122,6 +1122,7 @@ init_emulator(void) #endif /* USE_VM_PROBES */ +#ifdef USE_VM_PROBES void dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) { @@ -1131,7 +1132,7 @@ dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) port_channel_no(port->id), port_number(port->id)); } - +#endif /* * process_main() is called twice: * The first call performs some initialisation, including exporting @@ -1304,6 +1305,7 @@ void process_main(void) SWAPIN; ASSERT(VALID_INSTR(next)); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_scheduled)) { DTRACE_CHARBUF(process_buf, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(fun_buf, DTRACE_TERM_BUF_SIZE); @@ -1325,7 +1327,7 @@ void process_main(void) DTRACE2(process_scheduled, process_buf, fun_buf); } - +#endif Goto(next); } @@ -1591,13 +1593,16 @@ void process_main(void) OpCase(return): { +#ifdef USE_VM_PROBES BeamInstr* fptr; +#endif SET_I(c_p->cp); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(function_return) && (fptr = find_function_from_pc(c_p->cp))) { DTRACE_RETURN(c_p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); } - +#endif /* * We must clear the CP to make sure that a stale value do not * create a false module dependcy preventing code upgrading. @@ -1954,12 +1959,13 @@ void process_main(void) } #endif } +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(message_receive)) { Eterm token2 = NIL; DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); - ERTS_DECLARE_DUMMY(Sint tok_label) = 0; - ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; - ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; + Sint tok_label = 0; + Sint tok_lastcnt = 0; + Sint tok_serial = 0; dtrace_proc_str(c_p, receiver_name); token2 = SEQ_TRACE_TOKEN(c_p); @@ -1972,6 +1978,7 @@ void process_main(void) receiver_name, size_object(ERL_MESSAGE_TERM(msgp)), c_p->msg.len - 1, tok_label, tok_lastcnt, tok_serial); } +#endif UNLINK_MESSAGE(c_p, msgp); JOIN_MESSAGE(c_p); CANCEL_TIMER(c_p); @@ -3332,7 +3339,6 @@ void process_main(void) BifFunction vbf; DTRACE_NIF_ENTRY(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]); - c_p->current = I-3; /* current and vbf set to please handle_error */ SWAPOUT; c_p->fcalls = FCALLS - 1; @@ -3356,7 +3362,6 @@ void process_main(void) ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); DTRACE_NIF_RETURN(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]); - goto apply_bif_or_nif_epilogue; OpCase(apply_bif): @@ -6082,13 +6087,14 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) save_calls(p, ep); } +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(function_entry) && ep->address) { BeamInstr *fptr = find_function_from_pc(ep->address); if (fptr) { DTRACE_CALL(p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); } } - +#endif return ep->address; } @@ -6138,13 +6144,14 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) save_calls(p, ep); } +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(function_entry)) { BeamInstr *fptr = find_function_from_pc(ep->address); if (fptr) { DTRACE_CALL(p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); } } - +#endif return ep->address; } @@ -6194,6 +6201,7 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re c_p->max_arg_reg = sizeof(c_p->def_arg_reg)/sizeof(c_p->def_arg_reg[0]); } +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_hibernate)) { DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); @@ -6201,7 +6209,7 @@ erts_hibernate(Process* c_p, Eterm module, Eterm function, Eterm args, Eterm* re process_name, mfa); DTRACE2(process_hibernate, process_name, mfa); } - +#endif /* * Arrange for the process to be resumed at the given MFA with * the stack cleared. @@ -6276,6 +6284,7 @@ call_fun(Process* p, /* Current process. */ code_ptr = fe->address; actual_arity = (int) code_ptr[-1]; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(function_entry)) { BeamInstr *fptr = find_function_from_pc(code_ptr); @@ -6283,7 +6292,7 @@ call_fun(Process* p, /* Current process. */ DTRACE_CALL(p, fe->module, (Eterm)fptr[1], actual_arity); } } - +#endif if (actual_arity == arity+num_free) { if (num_free == 0) { return code_ptr; diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index 4ee60807d9..2c355fadfa 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -60,12 +60,14 @@ copy_object(Eterm obj, Process* to) Eterm* hp = HAlloc(to, size); Eterm res; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(copy_object)) { DTRACE_CHARBUF(proc_name, 64); erts_snprintf(proc_name, sizeof(proc_name), "%T", to->id); DTRACE2(copy_object, proc_name, size); } +#endif res = copy_struct(obj, size, &hp, &to->off_heap); #ifdef DEBUG if (eq(obj, res) == 0) { diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index e93176ba4e..802feaeb1c 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -745,13 +745,15 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) Eterm token = NIL; Process *sender = dsdp->proc; int res; - ERTS_DECLARE_DUMMY(Sint tok_label) = 0; - ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; - ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; - ERTS_DECLARE_DUMMY(Uint msize) = 0; +#ifdef USE_VM_PROBES + Sint tok_label = 0; + Sint tok_lastcnt = 0; + Sint tok_serial = 0; + Uint msize = 0; DTRACE_CHARBUF(node_name, 64); DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(receiver_name, 64); +#endif UseTmpHeapNoproc(5); if (SEQ_TRACE_TOKEN(sender) != NIL @@ -763,6 +765,7 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) token = SEQ_TRACE_TOKEN(sender); seq_trace_output(token, message, SEQ_TRACE_SEND, remote, sender); } +#ifdef USE_VM_PROBES *node_name = *sender_name = *receiver_name = '\0'; if (DTRACE_ENABLED(message_send) || DTRACE_ENABLED(message_send_remote)) { erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname); @@ -775,6 +778,7 @@ erts_dsig_send_msg(ErtsDSigData *dsdp, Eterm remote, Eterm message) tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); } } +#endif if (token != NIL) ctl = TUPLE4(&ctl_heap[0], @@ -798,13 +802,15 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) Eterm token = NIL; Process *sender = dsdp->proc; int res; - ERTS_DECLARE_DUMMY(Sint tok_label) = 0; - ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; - ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; - ERTS_DECLARE_DUMMY(Uint32 msize) = 0; +#ifdef USE_VM_PROBES + Sint tok_label = 0; + Sint tok_lastcnt = 0; + Sint tok_serial = 0; + Uint32 msize = 0; DTRACE_CHARBUF(node_name, 64); DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(receiver_name, 128); +#endif UseTmpHeapNoproc(6); if (SEQ_TRACE_TOKEN(sender) != NIL @@ -816,6 +822,7 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) token = SEQ_TRACE_TOKEN(sender); seq_trace_output(token, message, SEQ_TRACE_SEND, remote_name, sender); } +#ifdef USE_VM_PROBES *node_name = *sender_name = *receiver_name = '\0'; if (DTRACE_ENABLED(message_send) || DTRACE_ENABLED(message_send_remote)) { erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname); @@ -829,6 +836,7 @@ erts_dsig_send_reg_msg(ErtsDSigData *dsdp, Eterm remote_name, Eterm message) tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); } } +#endif if (token != NIL) ctl = TUPLE5(&ctl_heap[0], make_small(DOP_REG_SEND_TT), @@ -853,14 +861,16 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, Eterm ctl; DeclareTmpHeapNoproc(ctl_heap,6); int res; +#ifdef USE_VM_PROBES Process *sender = dsdp->proc; - ERTS_DECLARE_DUMMY(Sint tok_label) = 0; - ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; - ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; + Sint tok_label = 0; + Sint tok_lastcnt = 0; + Sint tok_serial = 0; DTRACE_CHARBUF(node_name, 64); DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(remote_name, 128); DTRACE_CHARBUF(reason_str, 128); +#endif UseTmpHeapNoproc(6); if (token != NIL @@ -875,6 +885,7 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, } else { ctl = TUPLE4(&ctl_heap[0], make_small(DOP_EXIT), local, remote, reason); } +#ifdef USE_VM_PROBES *node_name = *sender_name = *remote_name = '\0'; if (DTRACE_ENABLED(process_exit_signal_remote)) { erts_snprintf(node_name, sizeof(node_name), "%T", dsdp->dep->sysname); @@ -888,6 +899,7 @@ erts_dsig_send_exit_tt(ErtsDSigData *dsdp, Eterm local, Eterm remote, tok_serial = signed_val(SEQ_TRACE_T_SERIAL(token)); } } +#endif DTRACE7(process_exit_signal_remote, sender_name, node_name, remote_name, reason_str, tok_label, tok_lastcnt, tok_serial); /* forced, i.e ignore busy */ @@ -1706,6 +1718,7 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy) if (!(dep->qflgs & ERTS_DE_QFLG_BUSY)) { if (suspended) resume = 1; /* was busy when we started, but isn't now */ +#ifdef USE_VM_PROBES if (resume && DTRACE_ENABLED(dist_port_not_busy)) { DTRACE_CHARBUF(port_str, 64); DTRACE_CHARBUF(remote_str, 64); @@ -1716,6 +1729,7 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy) DTRACE3(dist_port_not_busy, erts_this_node_sysname, port_str, remote_str); } +#endif } else { /* Enqueue suspended process on dist entry */ @@ -1765,6 +1779,7 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy) } if (suspended) { +#ifdef USE_VM_PROBES if (!resume && DTRACE_ENABLED(dist_port_busy)) { DTRACE_CHARBUF(port_str, 64); DTRACE_CHARBUF(remote_str, 64); @@ -1776,6 +1791,7 @@ dsig_send(ErtsDSigData *dsdp, Eterm ctl, Eterm msg, int force_busy) DTRACE4(dist_port_busy, erts_this_node_sysname, port_str, remote_str, pid_str); } +#endif if (!resume && erts_system_monitor_flags.busy_dist_port) monitor_generic(c_p, am_busy_dist_port, cid); return ERTS_DSIG_SEND_YIELD; @@ -1799,6 +1815,7 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf) "(%beu bytes) passed.\n", size); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(dist_output)) { DTRACE_CHARBUF(port_str, 64); DTRACE_CHARBUF(remote_str, 64); @@ -1809,6 +1826,7 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf) DTRACE4(dist_output, erts_this_node_sysname, port_str, remote_str, size); } +#endif prt->caller = NIL; fpe_was_unmasked = erts_block_fpe(); (*prt->drv_ptr->output)((ErlDrvData) prt->drv_data, @@ -1851,6 +1869,7 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf) ASSERT(prt->drv_ptr->outputv); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(dist_outputv)) { DTRACE_CHARBUF(port_str, 64); DTRACE_CHARBUF(remote_str, 64); @@ -1861,6 +1880,7 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf) DTRACE4(dist_outputv, erts_this_node_sysname, port_str, remote_str, size); } +#endif prt->caller = NIL; fpe_was_unmasked = erts_block_fpe(); (*prt->drv_ptr->outputv)((ErlDrvData) prt->drv_data, &eiov); @@ -2180,6 +2200,7 @@ erts_dist_command(Port *prt, int reds_limit) void erts_dist_port_not_busy(Port *prt) { +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(dist_port_not_busy)) { DTRACE_CHARBUF(port_str, 64); DTRACE_CHARBUF(remote_str, 64); @@ -2190,6 +2211,7 @@ erts_dist_port_not_busy(Port *prt) DTRACE3(dist_port_not_busy, erts_this_node_sysname, port_str, remote_str); } +#endif erts_schedule_dist_command(prt, NULL); } @@ -3127,6 +3149,7 @@ send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, Eterm type, Eterm reas ASSERT(is_immed(what)); ASSERT(is_immed(node)); ASSERT(is_immed(type)); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(dist_monitor)) { DTRACE_CHARBUF(what_str, 12); DTRACE_CHARBUF(node_str, 64); @@ -3140,6 +3163,7 @@ send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, Eterm type, Eterm reas DTRACE5(dist_monitor, erts_this_node_sysname, what_str, node_str, type_str, reason_str); } +#endif ERTS_SMP_LC_ASSERT(!c_p || (erts_proc_lc_my_proc_locks(c_p) diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index b8cb3c6cc4..f0e98b33a5 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -270,6 +270,7 @@ static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) #endif erts_thr_q_enqueue(&q->thr_q, a); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(aio_pool_add)) { DTRACE_CHARBUF(port_str, 16); @@ -278,6 +279,7 @@ static ERTS_INLINE void async_add(ErtsAsync *a, ErtsAsyncQ* q) len = -1; DTRACE2(aio_pool_add, port_str, len); } +#endif gcc_optimizer_hack++; } @@ -301,6 +303,7 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, if (saved_fin_deq) erts_thr_q_append_finalize_dequeue_data(&a->q.fin_deq, &fin_deq); #endif +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(aio_pool_get)) { DTRACE_CHARBUF(port_str, 16); @@ -309,6 +312,7 @@ static ERTS_INLINE ErtsAsync *async_get(ErtsThrQ_t *q, len = -1; DTRACE2(aio_pool_get, port_str, len); } +#endif return a; } diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index 8caa64b97d..3056319809 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -344,6 +344,7 @@ port_call(Process* c_p, Eterm arg1, Eterm arg2, Eterm arg3) __FILE__, __LINE__, endp - (bytes + size)); } erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_call)) { DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); @@ -352,6 +353,7 @@ port_call(Process* c_p, Eterm arg1, Eterm arg2, Eterm arg3) dtrace_port_str(p, port_str); DTRACE5(driver_call, process_str, port_str, p->name, op, real_size); } +#endif prc = (char *) port_resp; fpe_was_unmasked = erts_block_fpe(); ret = drv->call((ErlDrvData)p->drv_data, @@ -548,6 +550,7 @@ BIF_RETTYPE port_connect_2(BIF_ALIST_2) prt->connected = pid; /* internal pid */ erts_smp_port_unlock(prt); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(port_connect)) { DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); @@ -558,6 +561,7 @@ BIF_RETTYPE port_connect_2(BIF_ALIST_2) dtrace_proc_str(rp, newprocess_str); DTRACE4(port_connect, process_str, port_str, prt->name, newprocess_str); } +#endif BIF_RET(am_true); } @@ -923,6 +927,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump) erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); port_num = erts_open_driver(driver, p->id, name_buf, &opts, err_nump); +#ifdef USE_VM_PROBES if (port_num >= 0 && DTRACE_ENABLED(port_open)) { DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); @@ -931,7 +936,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_nump) erts_snprintf(port_str, sizeof(port_str), "%T", erts_port[port_num].id); DTRACE3(port_open, process_str, name_buf, port_str); } - +#endif erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN); if (port_num < 0) { diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 2e340a7ef1..82f2dc6091 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -350,8 +350,9 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) Uint reclaimed_now = 0; int done = 0; Uint ms1, s1, us1; +#ifdef USE_VM_PROBES DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); - +#endif if (IS_TRACED_FL(p, F_TRACE_GC)) { trace_gc(p, am_gc_start); } @@ -371,7 +372,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) if (GEN_GCS(p) >= MAX_GEN_GCS(p)) { FLAGS(p) |= F_NEED_FULLSWEEP; } - +#ifdef USE_VM_PROBES *pidbuf = '\0'; if (DTRACE_ENABLED(gc_major_start) || DTRACE_ENABLED(gc_major_end) @@ -379,7 +380,7 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) || DTRACE_ENABLED(gc_minor_end)) { dtrace_proc_str(p, pidbuf); } - +#endif /* * Test which type of GC to do. */ @@ -1132,12 +1133,14 @@ do_minor(Process *p, Uint new_sz, Eterm* objv, int nobj) sys_memcpy(n_heap + new_sz - n, p->stop, n * sizeof(Eterm)); p->stop = n_heap + new_sz - n; +#ifdef USE_VM_PROBES if (HEAP_SIZE(p) != new_sz && DTRACE_ENABLED(process_heap_grow)) { DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, pidbuf); DTRACE3(process_heap_grow, pidbuf, HEAP_SIZE(p), new_sz); } +#endif ERTS_HEAP_FREE(ERTS_ALC_T_HEAP, (void*)HEAP_START(p), @@ -1360,12 +1363,14 @@ major_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl) sys_memcpy(n_heap + new_sz - n, p->stop, n * sizeof(Eterm)); p->stop = n_heap + new_sz - n; +#ifdef USE_VM_PROBES if (HEAP_SIZE(p) != new_sz && DTRACE_ENABLED(process_heap_grow)) { DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, pidbuf); DTRACE3(process_heap_grow, pidbuf, HEAP_SIZE(p), new_sz); } +#endif ERTS_HEAP_FREE(ERTS_ALC_T_HEAP, (void *) HEAP_START(p), @@ -2044,12 +2049,14 @@ grow_new_heap(Process *p, Uint new_sz, Eterm* objv, int nobj) HEAP_START(p) = new_heap; } +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_heap_grow)) { DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, pidbuf); DTRACE3(process_heap_grow, pidbuf, HEAP_SIZE(p), new_sz); } +#endif HEAP_SIZE(p) = new_sz; } @@ -2089,12 +2096,14 @@ shrink_new_heap(Process *p, Uint new_sz, Eterm *objv, int nobj) HEAP_START(p) = new_heap; } +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_heap_shrink)) { DTRACE_CHARBUF(pidbuf, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, pidbuf); DTRACE3(process_heap_shrink, pidbuf, HEAP_SIZE(p), new_sz); } +#endif HEAP_SIZE(p) = new_sz; } diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c index 7de30d25ed..4cdf2d7d09 100644 --- a/erts/emulator/beam/erl_message.c +++ b/erts/emulator/beam/erl_message.c @@ -336,9 +336,11 @@ erts_queue_dist_message(Process *rcvr, Eterm token) { ErlMessage* mp; - ERTS_DECLARE_DUMMY(Sint tok_label) = 0; - ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; - ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; +#ifdef USE_VM_PROBES + Sint tok_label = 0; + Sint tok_lastcnt = 0; + Sint tok_serial = 0; +#endif #ifdef ERTS_SMP ErtsProcLocks need_locks; #endif @@ -380,6 +382,7 @@ erts_queue_dist_message(Process *rcvr, message_free(mp); msg = erts_msg_distext2heap(rcvr, rcvr_locks, &mbuf, &token, dist_ext); if (is_value(msg)) +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(message_queued)) { DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); @@ -393,6 +396,7 @@ erts_queue_dist_message(Process *rcvr, receiver_name, size_object(msg), rcvr->msg.len, tok_label, tok_lastcnt, tok_serial); } +#endif erts_queue_message(rcvr, rcvr_locks, mbuf, msg, token #ifdef USE_VM_PROBES , NIL @@ -415,6 +419,7 @@ erts_queue_dist_message(Process *rcvr, #endif mp->next = NULL; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(message_queued)) { DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); @@ -431,6 +436,7 @@ erts_queue_dist_message(Process *rcvr, DTRACE6(message_queued, receiver_name, -1, rcvr->msg.len + 1, tok_label, tok_lastcnt, tok_serial); } +#endif mp->data.dist_ext = dist_ext; LINK_MESSAGE(rcvr, mp); @@ -515,11 +521,12 @@ erts_queue_message(Process* receiver, LINK_MESSAGE(receiver, mp); #endif +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(message_queued)) { DTRACE_CHARBUF(receiver_name, DTRACE_TERM_BUF_SIZE); - ERTS_DECLARE_DUMMY(Sint tok_label) = 0; - ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; - ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; + Sint tok_label = 0; + Sint tok_lastcnt = 0; + Sint tok_serial = 0; dtrace_proc_str(receiver, receiver_name); if (seq_trace_token != NIL && is_tuple(seq_trace_token)) { @@ -531,7 +538,7 @@ erts_queue_message(Process* receiver, receiver_name, size_object(message), receiver->msg.len, tok_label, tok_lastcnt, tok_serial); } - +#endif notify_new_message(receiver); if (IS_TRACED_FL(receiver, F_TRACE_RECEIVE)) { @@ -884,21 +891,24 @@ erts_send_message(Process* sender, Uint msize; ErlHeapFragment* bp = NULL; Eterm token = NIL; +#ifdef USE_VM_PROBES DTRACE_CHARBUF(sender_name, 64); DTRACE_CHARBUF(receiver_name, 64); - ERTS_DECLARE_DUMMY(Sint tok_label) = 0; - ERTS_DECLARE_DUMMY(Sint tok_lastcnt) = 0; - ERTS_DECLARE_DUMMY(Sint tok_serial) = 0; - + Sint tok_label = 0; + Sint tok_lastcnt = 0; + Sint tok_serial = 0; +#endif BM_STOP_TIMER(system); BM_MESSAGE(message,sender,receiver); BM_START_TIMER(send); + #ifdef USE_VM_PROBES *sender_name = *receiver_name = '\0'; - if (DTRACE_ENABLED(message_send)) { + if (DTRACE_ENABLED(message_send)) { erts_snprintf(sender_name, sizeof(sender_name), "%T", sender->id); erts_snprintf(receiver_name, sizeof(receiver_name), "%T", receiver->id); } +#endif if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) { Eterm* hp; Eterm stoken = SEQ_TRACE_TOKEN(sender); @@ -956,6 +966,7 @@ erts_send_message(Process* sender, BM_MESSAGE_COPIED(msize); BM_SWAP_TIMER(copy,send); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(message_send)) { if (stoken != NIL && stoken != am_have_dt_utag) { tok_label = signed_val(SEQ_TRACE_T_LABEL(stoken)); @@ -965,6 +976,7 @@ erts_send_message(Process* sender, DTRACE6(message_send, sender_name, receiver_name, msize, tok_label, tok_lastcnt, tok_serial); } +#endif erts_queue_message(receiver, receiver_locks, bp, diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 156783d057..40f2fde578 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -66,7 +66,9 @@ static void add_readonly_check(ErlNifEnv*, unsigned char* ptr, unsigned sz); static int is_offheap(const ErlOffHeap* off_heap); #endif +#ifdef USE_VM_PROBES void dtrace_nifenv_str(ErlNifEnv *, char *); +#endif #define MIN_HEAP_FRAG_SZ 200 static Eterm* alloc_heap_heavy(ErlNifEnv* env, unsigned need, Eterm* hp); @@ -1784,10 +1786,12 @@ void erl_nif_init() resource_type_list.name = THE_NON_VALUE; } +#ifdef USE_VM_PROBES void dtrace_nifenv_str(ErlNifEnv *env, char *process_buf) { dtrace_pid_str(env->proc->id, process_buf); } +#endif #ifdef READONLY_CHECK /* Use checksums to assert that NIFs do not write into inspected binaries diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 25bba5cf17..a8cb4563d6 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -62,6 +62,7 @@ do { \ (P)->sched.next = NULL; \ } while (0) +#ifdef USE_VM_PROBES #define DTRACE_DRIVER(PROBE_NAME, PP) \ if (DTRACE_ENABLED(driver_ready_input)) { \ DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); \ @@ -71,6 +72,9 @@ do { \ dtrace_port_str(PP, port_str); \ DTRACE3(PROBE_NAME, process_str, port_str, PP->name); \ } +#else +#define DTRACE_DRIVER(PROBE_NAME, PP) do {} while(0) +#endif erts_smp_atomic_t erts_port_task_outstanding_io_tasks; diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index f678d4159d..ff4e9c3d88 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -6219,12 +6219,14 @@ Process *schedule(Process *p, int calls) int actual_reds; int reds; +#ifdef USE_VM_PROBES if (p != NULL && DTRACE_ENABLED(process_unscheduled)) { DTRACE_CHARBUF(process_buf, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, process_buf); DTRACE1(process_unscheduled, process_buf); } +#endif if (ERTS_USE_MODIFIED_TIMING()) { context_reds = ERTS_MODIFIED_TIMING_CONTEXT_REDS; @@ -7400,6 +7402,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->id)); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_spawn)) { DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); @@ -7407,6 +7410,7 @@ erl_create_process(Process* parent, /* Parent of process (default group leader). dtrace_fun_decode(p, mod, func, arity, process_name, mfa); DTRACE2(process_spawn, process_name, mfa); } +#endif error: @@ -7988,6 +7992,7 @@ send_exit_signal(Process *c_p, /* current process if and only ASSERT(reason != THE_NON_VALUE); +#ifdef USE_VM_PROBES if(DTRACE_ENABLED(process_exit_signal) && is_pid(from)) { DTRACE_CHARBUF(sender_str, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(receiver_str, DTRACE_TERM_BUF_SIZE); @@ -7998,6 +8003,7 @@ send_exit_signal(Process *c_p, /* current process if and only erts_snprintf(reason_buf, sizeof(reason_buf) - 1, "%T", reason); DTRACE3(process_exit_signal, sender_str, receiver_str, reason_buf); } +#endif if (ERTS_PROC_IS_TRAPPING_EXITS(rp) && (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) { @@ -8430,6 +8436,7 @@ erts_do_exit_process(Process* p, Eterm reason) p->arity = 0; /* No live registers */ p->fvalue = reason; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_exit)) { DTRACE_CHARBUF(process_buf, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(reason_buf, 256); @@ -8438,6 +8445,7 @@ erts_do_exit_process(Process* p, Eterm reason) erts_snprintf(reason_buf, sizeof(reason_buf) - 1, "%T", reason); DTRACE2(process_exit, process_buf, reason_buf); } +#endif #ifdef ERTS_SMP ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 9425576980..8a2a43bebd 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -181,6 +181,7 @@ typedef struct line_buf_context { #define LINEBUF_INITIAL 100 +#ifdef USE_VM_PROBES #define DTRACE_FORMAT_COMMON_PID_AND_PORT(PID, PORT) \ DTRACE_CHARBUF(process_str, DTRACE_TERM_BUF_SIZE); \ DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); \ @@ -193,7 +194,7 @@ typedef struct line_buf_context { \ dtrace_proc_str((PID), process_str); \ dtrace_port_str((PORT), port_str); - +#endif /* The 'number' field in a port now has two parts: the lowest bits contain the index in the port table, and the higher bits are a counter @@ -653,10 +654,12 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ trace_sched_ports_where(port, am_in, am_start); } port->caller = pid; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_start)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(pid, port) DTRACE3(driver_start, process_str, driver->name, port_str); } +#endif fpe_was_unmasked = erts_block_fpe(); drv_data = (*driver->start)((ErlDrvPort)(port_ix), name, opts); @@ -1188,10 +1191,12 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) ev.size = size; /* total size */ ev.iov = ivp; ev.binv = bvp; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_outputv)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p) DTRACE4(driver_outputv, process_str, port_str, p->name, size); } +#endif fpe_was_unmasked = erts_block_fpe(); (*drv->outputv)((ErlDrvData)p->drv_data, &ev); erts_unblock_fpe(fpe_was_unmasked); @@ -1211,17 +1216,21 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) buf = erts_alloc(ERTS_ALC_T_TMP, size+1); r = io_list_to_buf(list, buf, size); +#ifdef USE_VM_PROBES if(DTRACE_ENABLED(port_command)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p) DTRACE4(port_command, process_str, port_str, p->name, "command"); } +#endif if (r >= 0) { size -= r; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_output)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p) DTRACE4(driver_output, process_str, port_str, p->name, size); } +#endif fpe_was_unmasked = erts_block_fpe(); (*drv->output)((ErlDrvData)p->drv_data, buf, size); erts_unblock_fpe(fpe_was_unmasked); @@ -1245,10 +1254,12 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) */ buf = erts_alloc(ERTS_ALC_T_TMP, size+1); r = io_list_to_buf(list, buf, size); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_output)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(caller_id, p) DTRACE4(driver_output, process_str, port_str, p->name, size); } +#endif fpe_was_unmasked = erts_block_fpe(); (*drv->output)((ErlDrvData)p->drv_data, buf, size); erts_unblock_fpe(fpe_was_unmasked); @@ -1857,10 +1868,12 @@ static void flush_port(Port *p) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p)); if (p->drv_ptr->flush != NULL) { +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_flush)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(p->connected, p) DTRACE3(driver_flush, process_str, port_str, p->name); } +#endif if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) { trace_sched_ports_where(p, am_in, am_flush); } @@ -1916,10 +1929,12 @@ terminate_port(Port *prt) drv = prt->drv_ptr; if ((drv != NULL) && (drv->stop != NULL)) { int fpe_was_unmasked = erts_block_fpe(); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_stop)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(prt->connected, prt) DTRACE3(driver_stop, process_str, drv->name, port_str); } +#endif (*drv->stop)((ErlDrvData)prt->drv_data); erts_unblock_fpe(fpe_was_unmasked); #ifdef ERTS_SMP @@ -2081,6 +2096,7 @@ erts_do_exit_port(Port *p, Eterm from, Eterm reason) rreason = (reason == am_kill) ? am_killed : reason; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(port_exit)) { DTRACE_CHARBUF(from_str, DTRACE_TERM_BUF_SIZE); DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); @@ -2091,6 +2107,7 @@ erts_do_exit_port(Port *p, Eterm from, Eterm reason) erts_snprintf(rreason_str, sizeof(rreason_str), "%T", rreason); DTRACE4(port_exit, from_str, port_str, p->name, rreason_str); } +#endif if ((p->status & (ERTS_PORT_SFLGS_DEAD | ERTS_PORT_SFLG_EXITING @@ -2193,10 +2210,12 @@ void erts_port_command(Process *proc, erts_port_status_bor_set(port, ERTS_PORT_SFLG_SEND_CLOSED); erts_do_exit_port(port, pid, am_normal); +#ifdef USE_VM_PROBES if(DTRACE_ENABLED(port_command)) { DTRACE_FORMAT_COMMON_PROC_AND_PORT(proc, port) DTRACE4(port_command, process_str, port_str, port->name, "close"); } +#endif goto done; } else if (is_tuple_arity(tp[2], 2)) { tp = tuple_val(tp[2]); @@ -2204,10 +2223,12 @@ void erts_port_command(Process *proc, if (erts_write_to_port(caller_id, port, tp[2]) == 0) goto done; } else if ((tp[1] == am_connect) && is_internal_pid(tp[2])) { +#ifdef USE_VM_PROBES if(DTRACE_ENABLED(port_command)) { DTRACE_FORMAT_COMMON_PROC_AND_PORT(proc, port) DTRACE4(port_command, process_str, port_str, port->name, "connect"); } +#endif port->connected = tp[2]; deliver_result(port->id, pid, am_connected); goto done; @@ -2310,12 +2331,14 @@ erts_port_control(Process* p, Port* prt, Uint command, Eterm iolist) erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN); ERTS_SMP_CHK_NO_PROC_LOCKS; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(port_control) || DTRACE_ENABLED(driver_control)) { DTRACE_FORMAT_COMMON_PROC_AND_PORT(p, prt); DTRACE4(port_control, process_str, port_str, prt->name, command); DTRACE5(driver_control, process_str, port_str, prt->name, command, to_len); } +#endif /* * Call the port's control routine. @@ -2457,7 +2480,9 @@ print_port_info(int to, void *arg, int i) void set_busy_port(ErlDrvPort port_num, int on) { +#ifdef USE_VM_PROBES DTRACE_CHARBUF(port_str, 16); +#endif ERTS_SMP_CHK_NO_PROC_LOCKS; @@ -2466,22 +2491,26 @@ set_busy_port(ErlDrvPort port_num, int on) if (on) { erts_port_status_bor_set(&erts_port[port_num], ERTS_PORT_SFLG_PORT_BUSY); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(port_busy)) { erts_snprintf(port_str, sizeof(port_str), "%T", erts_port[port_num].id); DTRACE1(port_busy, port_str); } +#endif } else { ErtsProcList* plp = erts_port[port_num].suspended; erts_port_status_band_set(&erts_port[port_num], ~ERTS_PORT_SFLG_PORT_BUSY); erts_port[port_num].suspended = NULL; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(port_not_busy)) { erts_snprintf(port_str, sizeof(port_str), "%T", erts_port[port_num].id); DTRACE1(port_not_busy, port_str); } +#endif if (erts_port[port_num].dist_entry) { /* * Processes suspended on distribution ports are @@ -2499,6 +2528,7 @@ set_busy_port(ErlDrvPort port_num, int on) */ if (plp) { +#ifdef USE_VM_PROBES /* * Hrm, for blocked dist ports, plp always seems to be NULL. * That's not so fun. @@ -2519,6 +2549,7 @@ set_busy_port(ErlDrvPort port_num, int on) DTRACE2(process_port_unblocked, pid_str, port_str); } } +#endif /* First proc should be resumed last */ if (plp->next) { erts_resume_processes(plp->next); @@ -2565,12 +2596,14 @@ void erts_raw_port_command(Port* p, byte* buf, Uint len) p->drv_ptr->name ? p->drv_ptr->name : "unknown"); p->caller = NIL; +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_output)) { DTRACE_CHARBUF(port_str, DTRACE_TERM_BUF_SIZE); dtrace_port_str(p, port_str); DTRACE4(driver_output, "-raw-", port_str, p->name, len); } +#endif fpe_was_unmasked = erts_block_fpe(); (*p->drv_ptr->output)((ErlDrvData)p->drv_data, (char*) buf, (int) len); erts_unblock_fpe(fpe_was_unmasked); @@ -2586,10 +2619,12 @@ int async_ready(Port *p, void* data) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p)); ASSERT(!(p->status & ERTS_PORT_SFLGS_DEAD)); if (p->drv_ptr->ready_async != NULL) { +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_ready_async)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(p->connected, p) DTRACE3(driver_ready_async, process_str, port_str, p->name); } +#endif (*p->drv_ptr->ready_async)((ErlDrvData)p->drv_data, data); need_free = 0; #ifdef ERTS_SMP @@ -4573,10 +4608,12 @@ void erts_fire_port_monitor(Port *prt, Eterm ref) ASSERT(callback != NULL); ref_to_driver_monitor(ref,&drv_monitor); DRV_MONITOR_UNLOCK_PDL(prt); +#ifdef USE_VM_PROBES if (DTRACE_ENABLED(driver_process_exit)) { DTRACE_FORMAT_COMMON_PID_AND_PORT(prt->connected, prt) DTRACE3(driver_process_exit, process_str, port_str, prt->name); } +#endif fpe_was_unmasked = erts_block_fpe(); (*callback)((ErlDrvData) (prt->drv_data), &drv_monitor); erts_unblock_fpe(fpe_was_unmasked); diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index cb7ef95f00..1d173a758a 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -498,7 +498,9 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, ErtsDrvEventState *state; int wake_poller; int ret; +#ifdef USE_VM_PROBES DTRACE_CHARBUF(name, 64); +#endif ERTS_SMP_LC_ASSERT(erts_drvport2port(ix) && erts_lc_is_port_locked(erts_drvport2port(ix))); @@ -528,8 +530,10 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, if (IS_FD_UNKNOWN(state)) { /* fast track to stop_select callback */ stop_select_fn = erts_drvport2port(ix)->drv_ptr->stop_select; +#ifdef USE_VM_PROBES strncpy(name, erts_drvport2port(ix)->drv_ptr->name, sizeof(name)-1); name[sizeof(name)-1] = '\0'; +#endif ret = 0; goto done_unknown; } @@ -666,8 +670,10 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, /* Safe to close fd now as it is not in pollset or there was no need to eject fd (kernel poll) */ stop_select_fn = drv_ptr->stop_select; +#ifdef USE_VM_PROBES strncpy(name, erts_drvport2port(ix)->drv_ptr->name, sizeof(name)-1); name[sizeof(name)-1] = '\0'; +#endif } else { /* Not safe to close fd, postpone stop_select callback. */ -- cgit v1.2.3 From c7f21d552b8034baecf8e7d078da5c9243826d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 9 Mar 2012 15:53:29 +0100 Subject: beam_makeops: Add a simple preprocessor --- erts/emulator/utils/beam_makeops | 54 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/erts/emulator/utils/beam_makeops b/erts/emulator/utils/beam_makeops index 58c36c3bdc..ea57000c82 100755 --- a/erts/emulator/utils/beam_makeops +++ b/erts/emulator/utils/beam_makeops @@ -28,6 +28,7 @@ my $verbose = 0; my $hot = 1; my $num_file_opcodes = 0; my $wordsize = 32; +my %defs; # Defines (from command line). # This is shift counts and mask for the packer. my $WHOLE_WORD = ''; @@ -95,6 +96,12 @@ my %unnumbered; my %is_transformed; +# +# Pre-processor. +# +my @if_val; +my @if_line; + # # Code transformations. # @@ -223,6 +230,7 @@ while (@ARGV && $ARGV[0] =~ /^-(.*)/) { ($outdir = shift), next if /^outdir/; ($wordsize = shift), next if /^wordsize/; ($verbose = 1), next if /^v/; + ($defs{$1} = $2), next if /^D(\w+)=(\w+)/; die "$0: Bad option: -$_\n"; } @@ -239,7 +247,43 @@ while (<>) { } next if /^\s*$/; next if /^\#/; - + + # + # Handle %if. + # + if (/^\%if (\w+)/) { + my $name = $1; + my $val = $defs{$name}; + defined $val or error("'$name' is undefined"); + push @if_val, $val; + push @if_line, $.; + next; + } elsif (/^\%unless (\w+)/) { + my $name = $1; + my $val = $defs{$name}; + defined $val or error("'$name' is undefined"); + push @if_val, !$val; + push @if_line, $.; + next; + } elsif (/^\%else$/) { + unless (@if_line) { + error("%else without a preceding %if/%unless"); + } + $if_line[$#if_line] = $.; + $if_val[$#if_val] = !$if_val[$#if_val]; + next; + } elsif (/^\%endif$/) { + unless (@if_line) { + error("%endif without a preceding %if/%unless/%else"); + } + pop @if_val; + pop @if_line; + next; + } + if (@if_val and not $if_val[$#if_val]) { + next; + } + # # Handle assignments. # @@ -349,7 +393,13 @@ while (<>) { $unnumbered{$name,$arity} = 1; } } continue { - close(ARGV) if eof(ARGV); + if (eof(ARGV)) { + close(ARGV); + if (@if_line) { + error("Unterminated %if/%unless/%else at " . + "line $if_line[$#if_line]\n"); + } + } } $num_file_opcodes = @gen_opname; -- cgit v1.2.3 From c79e1106853bcfdabe7325a7073ce911ef75afaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Fri, 9 Mar 2012 14:47:23 +0100 Subject: If VM probes are not enabled, short-circuit calls to probe BIFs --- erts/emulator/Makefile.in | 2 ++ erts/emulator/beam/ops.tab | 89 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index d8fad98de2..2efbe2d57e 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -25,6 +25,7 @@ ENABLE_ALLOC_TYPE_VARS = @ENABLE_ALLOC_TYPE_VARS@ HIPE_ENABLED=@HIPE_ENABLED@ DTRACE_ENABLED=@DTRACE_ENABLED@ DTRACE_ENABLED_2STEP=@DTRACE_ENABLED_2STEP@ +USE_VM_PROBES=@USE_VM_PROBES@ LIBS = @LIBS@ Z_LIB=@Z_LIB@ NO_INLINE_FUNCTIONS=false @@ -508,6 +509,7 @@ $(TTF_DIR)/OPCODES-GENERATED: $(OPCODE_TABLES) utils/beam_makeops LANG=C $(PERL) utils/beam_makeops \ -wordsize @EXTERNAL_WORD_SIZE@ \ -outdir $(TTF_DIR) \ + -DUSE_VM_PROBES=$(if $(USE_VM_PROBES),1,0) \ -emulator $(OPCODE_TABLES) && echo $? >$(TTF_DIR)/OPCODES-GENERATED GENERATE += $(TTF_DIR)/OPCODES-GENERATED diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index fc53a88a3a..edc935e1ff 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -882,6 +882,95 @@ call_ext u==3 u$func:erlang:hibernate/3 => i_hibernate call_ext_last u==3 u$func:erlang:hibernate/3 D => i_hibernate call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate +# +# If VM probes are not enabled, we want to short-circult calls to +# the utag BIFs to make them as cheap as possible. +# + +%unless USE_VM_PROBES + +call_ext Arity u$func:erlang:get_utag/0 => \ + move a=am_undefined r +call_ext_last Arity u$func:erlang:get_utag/0 D => \ + move a=am_undefined r | deallocate D | return +call_ext_only Arity u$func:erlang:get_utag/0 => \ + move a=am_undefined r | return + +move Any r | call_ext Arity u$func:erlang:put_utag/1 => \ + move a=am_undefined r +move Any r | call_ext_last Arity u$func:erlang:put_utag/1 D => \ + move a=am_undefined r | deallocate D | return +move Any r | call_ext_only Arity u$func:erlang:put_utag/1 => \ + move a=am_undefined r | return +call_ext Arity u$func:erlang:put_utag/1 => \ + move a=am_undefined r +call_ext_last Arity u$func:erlang:put_utag/1 D => \ + move a=am_undefined r | deallocate D | return +call_ext_only Arity u$func:erlang:put_utag/1 => \ + move a=am_undefined r | return + +call_ext Arity u$func:erlang:get_utag_data/0 => \ + move a=am_undefined r +call_ext_last Arity u$func:erlang:get_utag_data/0 D => \ + move a=am_undefined r | deallocate D | return +call_ext_only Arity u$func:erlang:get_utag_data/0 => \ + move a=am_undefined r | return + +move Any r | call_ext Arity u$func:erlang:spread_utag/1 => \ + move a=am_true r +move Any r | call_ext_last Arity u$func:erlang:spread_utag/1 D => \ + move a=am_true r | deallocate D | return +move Any r | call_ext_only Arity u$func:erlang:spread_utag/1 => \ + move a=am_true r | return +call_ext Arity u$func:erlang:spread_utag/1 => \ + move a=am_true r +call_ext_last Arity u$func:erlang:spread_utag/1 D => \ + move a=am_true r | deallocate D | return +call_ext_only Arity u$func:erlang:spread_utag/1 => \ + move a=am_true r | return + +move Any r | call_ext Arity u$func:erlang:restore_utag/1 => \ + move a=am_true r +move Any r | call_ext_last Arity u$func:erlang:restore_utag/1 D => \ + move a=am_true r | deallocate D | return +move Any r | call_ext_only Arity u$func:erlang:restore_utag/1 => \ + move a=am_true r | return +call_ext Arity u$func:erlang:restore_utag/1 => \ + move a=am_true r +call_ext_last Arity u$func:erlang:restore_utag/1 D => \ + move a=am_true r | deallocate D | return +call_ext_only Arity u$func:erlang:restore_utag/1 => \ + move a=am_true r | return + +move Any r | call_ext Arity u$func:erlang:prepend_vm_utag_data/1 => \ + move Any r +move Any r | call_ext_last Arity u$func:erlang:prepend_vm_utag_data/1 D => \ + move Any r | deallocate D | return +move Any r | call_ext_only Arity u$func:erlang:prepend_vm_utag_data/1 => \ + move Any r | return +call_ext Arity u$func:erlang:prepend_vm_utag_data/1 => +call_ext_last Arity u$func:erlang:prepend_vm_utag_data/1 D => \ + deallocate D | return +call_ext_only Arity u$func:erlang:prepend_vm_utag_data/1 => \ + return + +move Any r | call_ext Arity u$func:erlang:append_vm_utag_data/1 => \ + move Any r +move Any r | call_ext_last Arity u$func:erlang:append_vm_utag_data/1 D => \ + move Any r | deallocate D | return +move Any r | call_ext_only Arity u$func:erlang:append_vm_utag_data/1 => \ + move Any r | return +call_ext Arity u$func:erlang:append_vm_utag_data/1 => +call_ext_last Arity u$func:erlang:append_vm_utag_data/1 D => \ + deallocate D | return +call_ext_only Arity u$func:erlang:append_vm_utag_data/1 => \ + return + +# Can happen after one of the transformations above. +move Discarded r | move Something r => move Something r + +%endif + # # The general case for BIFs that have no special instructions. # A BIF used in the tail must be followed by a return instruction. -- cgit v1.2.3 From 560cea59eeee117f0170772d4edee820b6fc96d9 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Wed, 21 Mar 2012 14:54:00 +0100 Subject: Rename dyntrace BIFs to more suiting names --- erts/emulator/beam/bif.c | 14 +++---- erts/emulator/beam/bif.tab | 14 +++---- erts/emulator/beam/ops.tab | 74 ++++++++++++++++++------------------- erts/preloaded/ebin/prim_file.beam | Bin 38764 -> 40672 bytes erts/preloaded/src/prim_file.erl | 22 +++++------ lib/hipe/cerl/erl_bif_types.erl | 70 +++++++++++++++++------------------ lib/kernel/src/file.erl | 4 +- lib/kernel/src/file_io_server.erl | 6 +-- lib/runtime_tools/src/dyntrace.erl | 42 ++++++++++----------- 9 files changed, 123 insertions(+), 123 deletions(-) diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 2adc713959..39d4582435 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -4647,7 +4647,7 @@ BIF_RETTYPE get_module_info_2(BIF_ALIST_2) BIF_RET(ret); } -BIF_RETTYPE put_utag_1(BIF_ALIST_1) +BIF_RETTYPE dt_put_tag_1(BIF_ALIST_1) { #ifdef USE_VM_PROBES Eterm otag; @@ -4675,7 +4675,7 @@ BIF_RETTYPE put_utag_1(BIF_ALIST_1) #endif } -BIF_RETTYPE get_utag_0(BIF_ALIST_0) +BIF_RETTYPE dt_get_tag_0(BIF_ALIST_0) { #ifdef USE_VM_PROBES BIF_RET((DT_UTAG(BIF_P) == NIL || !(DT_UTAG_FLAGS(BIF_P) & DT_UTAG_PERMANENT)) ? am_undefined : DT_UTAG(BIF_P)); @@ -4683,7 +4683,7 @@ BIF_RETTYPE get_utag_0(BIF_ALIST_0) BIF_RET(am_undefined); #endif } -BIF_RETTYPE get_utag_data_0(BIF_ALIST_0) +BIF_RETTYPE dt_get_tag_data_0(BIF_ALIST_0) { #ifdef USE_VM_PROBES BIF_RET((DT_UTAG(BIF_P) == NIL) ? am_undefined : DT_UTAG(BIF_P)); @@ -4691,7 +4691,7 @@ BIF_RETTYPE get_utag_data_0(BIF_ALIST_0) BIF_RET(am_undefined); #endif } -BIF_RETTYPE prepend_vm_utag_data_1(BIF_ALIST_1) +BIF_RETTYPE dt_prepend_vm_tag_data_1(BIF_ALIST_1) { #ifdef USE_VM_PROBES Eterm b; @@ -4718,7 +4718,7 @@ BIF_RETTYPE prepend_vm_utag_data_1(BIF_ALIST_1) BIF_RET(BIF_ARG_1); #endif } -BIF_RETTYPE append_vm_utag_data_1(BIF_ALIST_1) +BIF_RETTYPE dt_append_vm_tag_data_1(BIF_ALIST_1) { #ifdef USE_VM_PROBES Eterm b; @@ -4745,7 +4745,7 @@ BIF_RETTYPE append_vm_utag_data_1(BIF_ALIST_1) BIF_RET(BIF_ARG_1); #endif } -BIF_RETTYPE spread_utag_1(BIF_ALIST_1) +BIF_RETTYPE dt_spread_tag_1(BIF_ALIST_1) { #ifdef USE_VM_PROBES Eterm ret; @@ -4779,7 +4779,7 @@ BIF_RETTYPE spread_utag_1(BIF_ALIST_1) BIF_RET(am_true); #endif } -BIF_RETTYPE restore_utag_1(BIF_ALIST_1) +BIF_RETTYPE dt_restore_tag_1(BIF_ALIST_1) { #ifdef USE_VM_PROBES Eterm *tpl; diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 7940544156..8a85e102d1 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -820,16 +820,16 @@ bif erlang:posixtime_to_universaltime/1 # # The dtrace BIF's are always present, but give dummy results if dynamic trace is not enabled in the build -bif erlang:put_utag/1 -bif erlang:get_utag/0 -bif erlang:get_utag_data/0 -bif erlang:spread_utag/1 -bif erlang:restore_utag/1 +bif erlang:dt_put_tag/1 +bif erlang:dt_get_tag/0 +bif erlang:dt_get_tag_data/0 +bif erlang:dt_spread_tag/1 +bif erlang:dt_restore_tag/1 # These are dummies even with enabled dynamic trace unless vm probes are enabled. # They are also internal, for dtrace tags sent to the VM's own drivers (efile) -bif erlang:prepend_vm_utag_data/1 -bif erlang:append_vm_utag_data/1 +bif erlang:dt_prepend_vm_tag_data/1 +bif erlang:dt_append_vm_tag_data/1 # # Obsolete diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index edc935e1ff..b2fc571032 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -884,86 +884,86 @@ call_ext_only u==3 u$func:erlang:hibernate/3 => i_hibernate # # If VM probes are not enabled, we want to short-circult calls to -# the utag BIFs to make them as cheap as possible. +# the dt tag BIFs to make them as cheap as possible. # %unless USE_VM_PROBES -call_ext Arity u$func:erlang:get_utag/0 => \ +call_ext Arity u$func:erlang:dt_get_tag/0 => \ move a=am_undefined r -call_ext_last Arity u$func:erlang:get_utag/0 D => \ +call_ext_last Arity u$func:erlang:dt_get_tag/0 D => \ move a=am_undefined r | deallocate D | return -call_ext_only Arity u$func:erlang:get_utag/0 => \ +call_ext_only Arity u$func:erlang:dt_get_tag/0 => \ move a=am_undefined r | return -move Any r | call_ext Arity u$func:erlang:put_utag/1 => \ +move Any r | call_ext Arity u$func:erlang:dt_put_tag/1 => \ move a=am_undefined r -move Any r | call_ext_last Arity u$func:erlang:put_utag/1 D => \ +move Any r | call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \ move a=am_undefined r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:put_utag/1 => \ +move Any r | call_ext_only Arity u$func:erlang:dt_put_tag/1 => \ move a=am_undefined r | return -call_ext Arity u$func:erlang:put_utag/1 => \ +call_ext Arity u$func:erlang:dt_put_tag/1 => \ move a=am_undefined r -call_ext_last Arity u$func:erlang:put_utag/1 D => \ +call_ext_last Arity u$func:erlang:dt_put_tag/1 D => \ move a=am_undefined r | deallocate D | return -call_ext_only Arity u$func:erlang:put_utag/1 => \ +call_ext_only Arity u$func:erlang:dt_put_tag/1 => \ move a=am_undefined r | return -call_ext Arity u$func:erlang:get_utag_data/0 => \ +call_ext Arity u$func:erlang:dt_get_tag_data/0 => \ move a=am_undefined r -call_ext_last Arity u$func:erlang:get_utag_data/0 D => \ +call_ext_last Arity u$func:erlang:dt_get_tag_data/0 D => \ move a=am_undefined r | deallocate D | return -call_ext_only Arity u$func:erlang:get_utag_data/0 => \ +call_ext_only Arity u$func:erlang:dt_get_tag_data/0 => \ move a=am_undefined r | return -move Any r | call_ext Arity u$func:erlang:spread_utag/1 => \ +move Any r | call_ext Arity u$func:erlang:dt_spread_tag/1 => \ move a=am_true r -move Any r | call_ext_last Arity u$func:erlang:spread_utag/1 D => \ +move Any r | call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \ move a=am_true r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:spread_utag/1 => \ +move Any r | call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \ move a=am_true r | return -call_ext Arity u$func:erlang:spread_utag/1 => \ +call_ext Arity u$func:erlang:dt_spread_tag/1 => \ move a=am_true r -call_ext_last Arity u$func:erlang:spread_utag/1 D => \ +call_ext_last Arity u$func:erlang:dt_spread_tag/1 D => \ move a=am_true r | deallocate D | return -call_ext_only Arity u$func:erlang:spread_utag/1 => \ +call_ext_only Arity u$func:erlang:dt_spread_tag/1 => \ move a=am_true r | return -move Any r | call_ext Arity u$func:erlang:restore_utag/1 => \ +move Any r | call_ext Arity u$func:erlang:dt_restore_tag/1 => \ move a=am_true r -move Any r | call_ext_last Arity u$func:erlang:restore_utag/1 D => \ +move Any r | call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \ move a=am_true r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:restore_utag/1 => \ +move Any r | call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \ move a=am_true r | return -call_ext Arity u$func:erlang:restore_utag/1 => \ +call_ext Arity u$func:erlang:dt_restore_tag/1 => \ move a=am_true r -call_ext_last Arity u$func:erlang:restore_utag/1 D => \ +call_ext_last Arity u$func:erlang:dt_restore_tag/1 D => \ move a=am_true r | deallocate D | return -call_ext_only Arity u$func:erlang:restore_utag/1 => \ +call_ext_only Arity u$func:erlang:dt_restore_tag/1 => \ move a=am_true r | return -move Any r | call_ext Arity u$func:erlang:prepend_vm_utag_data/1 => \ +move Any r | call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ move Any r -move Any r | call_ext_last Arity u$func:erlang:prepend_vm_utag_data/1 D => \ +move Any r | call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \ move Any r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:prepend_vm_utag_data/1 => \ +move Any r | call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ move Any r | return -call_ext Arity u$func:erlang:prepend_vm_utag_data/1 => -call_ext_last Arity u$func:erlang:prepend_vm_utag_data/1 D => \ +call_ext Arity u$func:erlang:dt_prepend_vm_tag_data/1 => +call_ext_last Arity u$func:erlang:dt_prepend_vm_tag_data/1 D => \ deallocate D | return -call_ext_only Arity u$func:erlang:prepend_vm_utag_data/1 => \ +call_ext_only Arity u$func:erlang:dt_prepend_vm_tag_data/1 => \ return -move Any r | call_ext Arity u$func:erlang:append_vm_utag_data/1 => \ +move Any r | call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => \ move Any r -move Any r | call_ext_last Arity u$func:erlang:append_vm_utag_data/1 D => \ +move Any r | call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \ move Any r | deallocate D | return -move Any r | call_ext_only Arity u$func:erlang:append_vm_utag_data/1 => \ +move Any r | call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \ move Any r | return -call_ext Arity u$func:erlang:append_vm_utag_data/1 => -call_ext_last Arity u$func:erlang:append_vm_utag_data/1 D => \ +call_ext Arity u$func:erlang:dt_append_vm_tag_data/1 => +call_ext_last Arity u$func:erlang:dt_append_vm_tag_data/1 D => \ deallocate D | return -call_ext_only Arity u$func:erlang:append_vm_utag_data/1 => \ +call_ext_only Arity u$func:erlang:dt_append_vm_tag_data/1 => \ return # Can happen after one of the transformations above. diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index ea6d2cb8c6..a62a461146 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index f7861514ae..8d6ec96f33 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -268,7 +268,7 @@ advise(#file_descriptor{module = ?MODULE, data = {Port, _}}, %% Returns {error, Reason} | ok. write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> - case drv_command_nt(Port, [?FILE_WRITE,erlang:prepend_vm_utag_data(Bytes)],false,undefined) of + case drv_command_nt(Port, [?FILE_WRITE,erlang:dt_prepend_vm_tag_data(Bytes)],false,undefined) of {ok, _Size} -> ok; Error -> @@ -283,7 +283,7 @@ pwrite(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) pwrite_int(_, [], 0, [], []) -> ok; pwrite_int(Port, [], N, Spec, Data) -> - Header = list_to_binary([?FILE_PWRITEV, erlang:prepend_vm_utag_data(<>) | reverse(Spec)]), + Header = list_to_binary([?FILE_PWRITEV, erlang:dt_prepend_vm_tag_data(<>) | reverse(Spec)]), case drv_command_nt(Port, [Header | reverse(Data)], false, undefined) of {ok, _Size} -> ok; @@ -402,7 +402,7 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) pread_int(_, [], 0, []) -> {ok, []}; pread_int(Port, [], N, Spec) -> - drv_command_nt(Port, [?FILE_PREADV, erlang:prepend_vm_utag_data(<<0:32, N:32>>) | reverse(Spec)],false, undefined); + drv_command_nt(Port, [?FILE_PREADV, erlang:dt_prepend_vm_tag_data(<<0:32, N:32>>) | reverse(Spec)],false, undefined); pread_int(Port, [{Offs, Size} | T], N, Spec) when is_integer(Offs), is_integer(Size), 0 =< Size -> if @@ -424,7 +424,7 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) -(?LARGEFILESIZE) =< Offs, Offs < ?LARGEFILESIZE, Size < ?LARGEFILESIZE -> case drv_command_nt(Port, - [?FILE_PREADV, erlang:prepend_vm_utag_data(<<0:32, 1:32, + [?FILE_PREADV, erlang:dt_prepend_vm_tag_data(<<0:32, 1:32, Offs:64/signed, Size:64>>)], false, undefined) of {ok, [eof]} -> eof; @@ -923,7 +923,7 @@ drv_open(Driver, Portopts) -> %% Closes a port in a safe way. Returns ok. drv_close(Port) -> - Save = erlang:spread_utag(false), + Save = erlang:dt_spread_tag(false), try try erlang:port_close(Port) catch error:_ -> ok end, receive %% Ugly workaround in case the caller==owner traps exits @@ -933,7 +933,7 @@ drv_close(Port) -> ok end after - erlang:restore_utag(Save) + erlang:dt_restore_tag(Save) end. @@ -958,8 +958,8 @@ drv_command(Port, Command, R) -> end. drv_command(Port, Command, Validated, R) when is_port(Port) -> - Save = erlang:spread_utag(false), - try erlang:port_command(Port, erlang:append_vm_utag_data(Command)) of + Save = erlang:dt_spread_tag(false), + try erlang:port_command(Port, erlang:dt_append_vm_tag_data(Command)) of true -> drv_get_response(Port, R) catch @@ -979,7 +979,7 @@ drv_command(Port, Command, Validated, R) when is_port(Port) -> error:Reason -> {error, Reason} after - erlang:restore_utag(Save) + erlang:dt_restore_tag(Save) end; drv_command({Driver, Portopts}, Command, Validated, R) -> case drv_open(Driver, Portopts) of @@ -991,7 +991,7 @@ drv_command({Driver, Portopts}, Command, Validated, R) -> Error end. drv_command_nt(Port, Command, Validated, R) when is_port(Port) -> - Save = erlang:spread_utag(false), + Save = erlang:dt_spread_tag(false), try erlang:port_command(Port, Command) of true -> drv_get_response(Port, R) @@ -1012,7 +1012,7 @@ drv_command_nt(Port, Command, Validated, R) when is_port(Port) -> error:Reason -> {error, Reason} after - erlang:restore_utag(Save) + erlang:dt_restore_tag(Save) end. diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index 260f216725..0c2e846010 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -614,10 +614,6 @@ type(erlang, adler32_combine, 3, Xs) -> type(erlang, append, 2, Xs) -> type(erlang, '++', 2, Xs); % alias type(erlang, append_element, 2, Xs) -> strict(arg_types(erlang, append_element, 2), Xs, fun (_) -> t_tuple() end); -type(erlang, append_vm_utag_data, 1, Xs) -> - strict(arg_types(erlang, append_vm_utag_data, 1), - Xs, - fun(_) -> t_iodata() end); type(erlang, apply, 2, Xs) -> Fun = fun ([X, _Y]) -> case t_is_fun(X) of @@ -714,6 +710,27 @@ type(erlang, display_nl, 0, _) -> t_atom('true'); type(erlang, dist_exit, 3, Xs) -> strict(arg_types(erlang, dist_exit, 3), Xs, fun (_) -> t_atom('true') end); +type(erlang, dt_append_vm_tag_data, 1, Xs) -> + strict(arg_types(erlang, dt_append_vm_tag_data, 1), + Xs, + fun(_) -> t_iodata() end); +type(erlang, dt_get_tag, 0, _) -> + t_sup(t_binary(), t_atom('undefined')); +type(erlang, dt_get_tag_data, 0, _) -> + t_sup(t_binary(), t_atom('undefined')); +type(erlang, dt_prepend_vm_tag_data, 1, Xs) -> + strict(arg_types(erlang, dt_prepend_vm_tag_data, 1), + Xs, + fun(_) -> t_iodata() end); +type(erlang, dt_put_tag, 1, Xs) -> + strict(arg_types(erlang, dt_put_tag, 1), Xs, + fun(_) -> t_sup(t_binary(), t_atom('undefined')) end); +type(erlang, dt_restore_tag, 1, Xs) -> + strict(arg_types(erlang, dt_restore_tag, 1), Xs, fun(_) -> t_atom('true') end); +type(erlang, dt_spread_tag, 1, Xs) -> + strict(arg_types(erlang, dt_spread_tag, 1), Xs, + fun(_) -> t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), + t_atom('true')) end); type(erlang, element, 2, Xs) -> strict(arg_types(erlang, element, 2), Xs, fun ([X1, X2]) -> @@ -804,10 +821,6 @@ type(erlang, get_module_info, 2, Xs) -> type(erlang, get_stacktrace, 0, _) -> t_list(t_tuple([t_atom(), t_atom(), t_sup([t_arity(), t_list()]), t_list()])); -type(erlang, get_utag, 0, _) -> - t_sup(t_binary(), t_atom('undefined')); -type(erlang, get_utag_data, 0, _) -> - t_sup(t_binary(), t_atom('undefined')); type(erlang, group_leader, 0, _) -> t_pid(); type(erlang, group_leader, 2, Xs) -> strict(arg_types(erlang, group_leader, 2), Xs, @@ -1194,10 +1207,6 @@ type(erlang, port_set_data, 2, Xs) -> strict(arg_types(erlang, port_set_data, 2), Xs, fun (_) -> t_atom('true') end); type(erlang, pre_loaded, 0, _) -> t_list(t_atom()); -type(erlang, prepend_vm_utag_data, 1, Xs) -> - strict(arg_types(erlang, prepend_vm_utag_data, 1), - Xs, - fun(_) -> t_iodata() end); type(erlang, process_display, 2, _) -> t_atom('true'); type(erlang, process_flag, 2, Xs) -> T_process_flag_returns = t_sup([t_boolean(), t_atom(), t_non_neg_integer()]), @@ -1315,9 +1324,6 @@ type(erlang, purge_module, 1, Xs) -> fun (_) -> t_atom('true') end); type(erlang, put, 2, Xs) -> strict(arg_types(erlang, put, 2), Xs, fun (_) -> t_any() end); -type(erlang, put_utag, 1, Xs) -> - strict(arg_types(erlang, put_utag, 1), Xs, - fun(_) -> t_sup(t_binary(), t_atom('undefined')) end); type(erlang, raise, 3, _) -> t_none(); type(erlang, read_timer, 1, Xs) -> strict(arg_types(erlang, read_timer, 1), Xs, @@ -1327,8 +1333,6 @@ type(erlang, ref_to_list, 1, Xs) -> type(erlang, register, 2, Xs) -> strict(arg_types(erlang, register, 2), Xs, fun (_) -> t_atom('true') end); type(erlang, registered, 0, _) -> t_list(t_atom()); -type(erlang, restore_utag, 1, Xs) -> - strict(arg_types(erlang, restore_utag, 1), Xs, fun(_) -> t_atom('true') end); type(erlang, resume_process, 1, Xs) -> strict(arg_types(erlang, resume_process, 1), Xs, fun (_) -> t_any() end); %% TODO: overapproximation -- fix this @@ -1443,10 +1447,6 @@ type(erlang, spawn_opt, 4, Xs) -> type(erlang, split_binary, 2, Xs) -> strict(arg_types(erlang, split_binary, 2), Xs, fun (_) -> t_tuple([t_binary(), t_binary()]) end); -type(erlang, spread_utag, 1, Xs) -> - strict(arg_types(erlang, spread_utag, 1), Xs, - fun(_) -> t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), - t_atom('true')) end); type(erlang, start_timer, 3, Xs) -> strict(arg_types(erlang, start_timer, 3), Xs, fun (_) -> t_reference() end); type(erlang, statistics, 1, Xs) -> @@ -3443,8 +3443,6 @@ arg_types(erlang, append, 2) -> arg_types(erlang, '++', 2); arg_types(erlang, append_element, 2) -> [t_tuple(), t_any()]; -arg_types(erlang, append_vm_utag_data, 1) -> - [t_iodata()]; arg_types(erlang, apply, 2) -> [t_sup(t_tuple([t_module(), t_atom()]), @@ -3518,6 +3516,20 @@ arg_types(erlang, display_string, 1) -> [t_string()]; arg_types(erlang, dist_exit, 3) -> [t_pid(), t_dist_exit(), t_sup(t_pid(), t_port())]; +arg_types(erlang, dt_append_vm_tag_data, 1) -> + [t_iodata()]; +arg_types(erlang, dt_get_tag, 0) -> + []; +arg_types(erlang, dt_get_tag_data, 0) -> + []; +arg_types(erlang, dt_prepend_vm_tag_data, 1) -> + [t_iodata()]; +arg_types(erlang, dt_put_tag, 1) -> + [t_sup(t_binary(), t_atom('undefined'))]; +arg_types(erlang, dt_restore_tag, 1) -> + [t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), t_atom('true'))]; +arg_types(erlang, dt_spread_tag, 1) -> + [t_boolean()]; arg_types(erlang, element, 2) -> [t_pos_fixnum(), t_tuple()]; arg_types(erlang, erase, 0) -> @@ -3570,10 +3582,6 @@ arg_types(erlang, get_module_info, 1) -> [t_atom()]; arg_types(erlang, get_module_info, 2) -> [t_atom(), t_module_info_2()]; -arg_types(erlang, get_utag, 0) -> - []; -arg_types(erlang, get_utag_data, 0) -> - []; arg_types(erlang, group_leader, 0) -> []; arg_types(erlang, group_leader, 2) -> @@ -3790,8 +3798,6 @@ arg_types(erlang, port_set_data, 2) -> [t_sup(t_port(), t_atom()), t_any()]; arg_types(erlang, pre_loaded, 0) -> []; -arg_types(erlang, prepend_vm_utag_data, 1) -> - [t_iodata()]; arg_types(erlang, process_display, 2) -> [t_pid(), t_atom('backtrace')]; arg_types(erlang, process_flag, 2) -> @@ -3818,8 +3824,6 @@ arg_types(erlang, purge_module, 1) -> [t_atom()]; arg_types(erlang, put, 2) -> [t_any(), t_any()]; -arg_types(erlang, put_utag, 1) -> - [t_sup(t_binary(), t_atom('undefined'))]; arg_types(erlang, raise, 3) -> OldStyleType = t_list(t_tuple([t_atom(), t_atom(), t_sup([t_arity(), t_list()])])), @@ -3833,8 +3837,6 @@ arg_types(erlang, register, 2) -> [t_atom(), t_sup(t_port(), t_pid())]; arg_types(erlang, registered, 0) -> []; -arg_types(erlang, restore_utag, 1) -> - [t_sup(t_tuple([t_non_neg_integer(), t_sup(t_binary(), t_nil())]), t_atom('true'))]; arg_types(erlang, resume_process, 1) -> [t_pid()]; % intended for debugging only arg_types(erlang, round, 1) -> @@ -3893,8 +3895,6 @@ arg_types(erlang, spawn_opt, 4) -> [t_node(), t_atom(), t_list(), t_list(t_spawn_options())]; arg_types(erlang, split_binary, 2) -> [t_binary(), t_non_neg_integer()]; -arg_types(erlang, spread_utag, 1) -> - [t_boolean()]; arg_types(erlang, start_timer, 3) -> [t_non_neg_integer(), t_sup(t_pid(), t_atom()), t_any()]; arg_types(erlang, statistics, 1) -> diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index b281151778..e2290f6a23 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -1416,10 +1416,10 @@ mode_list(_) -> %% Functions for communicating with the file server call(Command, Args) when is_list(Args) -> - X = erlang:spread_utag(true), + X = erlang:dt_spread_tag(true), Y = gen_server:call(?FILE_SERVER, list_to_tuple([Command | Args]), infinity), - erlang:restore_utag(X), + erlang:dt_restore_tag(X), Y. check_and_call(Command, Args) when is_list(Args) -> diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index 6369a5250c..7311ad9fee 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -57,11 +57,11 @@ start_link(Owner, FileName, ModeList) do_start(Spawn, Owner, FileName, ModeList) -> Self = self(), Ref = make_ref(), - Utag = erlang:spread_utag(true), + Utag = erlang:dt_spread_tag(true), Pid = erlang:Spawn( fun() -> - erlang:restore_utag(Utag), + erlang:dt_restore_tag(Utag), %% process_flag(trap_exit, true), case parse_options(ModeList) of {ReadMode, UnicodeMode, Opts} -> @@ -86,7 +86,7 @@ do_start(Spawn, Owner, FileName, ModeList) -> exit(Reason1) end end), - erlang:restore_utag(Utag), + erlang:dt_restore_tag(Utag), Mref = erlang:monitor(process, Pid), receive {Ref, {error, _Reason} = Error} -> diff --git a/lib/runtime_tools/src/dyntrace.erl b/lib/runtime_tools/src/dyntrace.erl index 20472a2be6..388c7679b9 100644 --- a/lib/runtime_tools/src/dyntrace.erl +++ b/lib/runtime_tools/src/dyntrace.erl @@ -14,7 +14,7 @@ %%% four integer arguments and four string arguments; the integer %%% argument(s) must come before any string argument. For example: %%% ``` -%%% 1> dyntrace:put_utag("GGOOOAAALL!!!!!"). +%%% 1> dyntrace:put_tag("GGOOOAAALL!!!!!"). %%% true %%% 2> dyntrace:init(). %%% ok @@ -39,7 +39,7 @@ -export([available/0, user_trace_s1/1, % TODO: unify with pid & tag args like user_trace_i4s4 p/0, p/1, p/2, p/3, p/4, p/5, p/6, p/7, p/8]). --export([put_utag/1, get_utag/0, get_utag_data/0, spread_utag/1, restore_utag/1]). +-export([put_tag/1, get_tag/0, get_tag_data/0, spread_tag/1, restore_tag/1]). -export([scaff/0]). % Development only -export([user_trace_i4s4/9]). % Know what you're doing! @@ -210,7 +210,7 @@ p(I1, I2, I3, I4, S1, S2, S3, S4) when is_integer(I1), is_integer(I2), is_intege true | false | error | badarg. user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> - UTag = get_utag(), + UTag = get_tag(), try user_trace_i4s4(UTag, I1, I2, I3, I4, S1, S2, S3, S4) catch @@ -218,28 +218,28 @@ user_trace_int(I1, I2, I3, I4, S1, S2, S3, S4) -> false end. --spec put_utag(undefined | iodata()) -> binary() | undefined. -put_utag(Data) -> - erlang:put_utag(unicode:characters_to_binary(Data)). +-spec put_tag(undefined | iodata()) -> binary() | undefined. +put_tag(Data) -> + erlang:dt_put_tag(unicode:characters_to_binary(Data)). --spec get_utag() -> binary() | undefined. -get_utag() -> - erlang:get_utag(). +-spec get_tag() -> binary() | undefined. +get_tag() -> + erlang:dt_get_tag(). --spec get_utag_data() -> binary() | undefined. -%% Gets utag if set, otherwise the spread utag data from last incoming message -get_utag_data() -> - erlang:get_utag_data(). +-spec get_tag_data() -> binary() | undefined. +%% Gets tag if set, otherwise the spread tag data from last incoming message +get_tag_data() -> + erlang:dt_get_tag_data(). --spec spread_utag(boolean()) -> true | {non_neg_integer(), binary() | []}. -%% Makes the utag behave as a sequential trace token, will spread with messages to be picked up by someone using -%% get_utag_data or get_drv_utag_data. -spread_utag(B) -> - erlang:spread_utag(B). +-spec spread_tag(boolean()) -> true | {non_neg_integer(), binary() | []}. +%% Makes the tag behave as a sequential trace token, will spread with +%% messages to be picked up by someone using get_tag_data +spread_tag(B) -> + erlang:dt_spread_tag(B). --spec restore_utag(true | {non_neg_integer(), binary() | []}) -> true. -restore_utag(T) -> - erlang:restore_utag(T). +-spec restore_tag(true | {non_neg_integer(), binary() | []}) -> true. +restore_tag(T) -> + erlang:dt_restore_tag(T). %% Scaffolding to write tedious code: quick brute force and not 100% correct. -- cgit v1.2.3 From 0c0d640ed423d4a386de75a2b37a1be038c2d059 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Wed, 21 Mar 2012 15:00:00 +0100 Subject: Update README's for dtrace and systemtap --- README.dtrace.md | 42 ++++++++++-------------------------------- README.systemtap.md | 2 +- 2 files changed, 11 insertions(+), 33 deletions(-) diff --git a/README.dtrace.md b/README.dtrace.md index bbff233ed9..5bc042f9fc 100644 --- a/README.dtrace.md +++ b/README.dtrace.md @@ -36,44 +36,22 @@ Supported platforms * Linux via SystemTap compatibility. Please see the file `README.systemtap.md` for more details. -Just add the `--enable-dtrace` option to your command when you run the -`configure` script. +Just add the `--with-dynamic-trace=dtrace` option to your command when you +run the `configure` script. If you are using systemtap, the configure option +is `--with-dynamic-trace=systemtap` -Contributions -------------- +Status +------ -Code contributions are welcome! This is a side project for me (SLF), -so things would go faster if other people are willing to pitch in. -Please use the GitHub pull request mechanism or send me an email -message. - -To build from scratch, use this recipe. If you're an experienced Git -user and wish to add my repository as a remote repository, be my -guest. Just resume the recipe at command #4. - -NOTE: The `dtrace-experiment+michal2` branch is used for changes that -can be applied to both R14B and R15 releases. - - % git clone git://github.com/slfritchie/otp.git - % cd otp - % git checkout -b dtrace-experiment+michal2 origin/dtrace-experiment+michal2 - % env ERL_TOP=`pwd` ./otp_build autoconf - % env ERL_TOP=`pwd` ./configure --enable-dtrace + whatever args you need - % env ERL_TOP=`pwd` make - -Then `make install` and then start an Erlang shell via -`/path/to/installed/bin/erl +A 8`. The Erlang shell's banner should -include `[dtrace]`. - -Try using this (ugly) DTrace command to watch file I/O probes in use -(tested on OS X only, sorry): - - dtrace -Z -n 'erlang*:::efile_drv-entry {printf("%d %d %s | %d | %s %s , %d %d %d", arg0, arg1, arg2 == NULL ? "" : copyinstr(arg2), arg3, arg4 == NULL ? "" : copyinstr(arg4), arg5 == NULL ? "" : copyinstr(arg5), arg6, arg7, arg8)} erlang*:::efile_drv-int* {printf("%d %d %d | %d", arg0, arg1, arg2, arg3);} erlang*:::efile_drv-return {printf("%d %d %s | %d | %d %d %d", arg0, arg1, arg2 == NULL ? "" : copyinstr(arg2), arg3, arg4, arg5, arg6 ) ; }' +As of R15B01, the dynamic trace code is included in the main OTP distribution, +although it's considered experimental. The main development of the dtrace code +still happens outside of Ericsson, but there is no need to fetch a patched +version of OTP to get the basic funtionality. Implementation summary ---------------------- -So far, most effort has been focused on the `efile_drv.erl` code, +So far, most effort has been focused on the `efile_drv.c` code, which implements most file I/O on behalf of the Erlang virtual machine. This driver also presents a big challenge: its use of an I/O worker pool (enabled by using the `erl +A 8` flag, for example) makes diff --git a/README.systemtap.md b/README.systemtap.md index 3bb3e626cd..c190bcc893 100644 --- a/README.systemtap.md +++ b/README.systemtap.md @@ -35,7 +35,7 @@ Building Erlang Configure and build Erlang with SystemTap support: - # ./configure --enable-dtrace + whatever args you need + # ./configure --with-dynamic-trace=systemtap + whatever args you need # make Testing -- cgit v1.2.3 From 19a36b917d8c7c2dc061ee5b41738fa8b315d70b Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Fri, 9 Mar 2012 15:51:51 +0100 Subject: Update slogan and add system_info for dynamic trace --- erts/emulator/beam/erl_bif_info.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 618acc5117..041eac240d 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -115,8 +115,11 @@ static char erts_system_version[] = ("Erlang " ERLANG_OTP_RELEASE #ifdef VALGRIND " [valgrind-compiled]" #endif -#ifdef USE_VM_PROBES +#ifdef USE_DTRACE " [dtrace]" +#endif +#ifdef USE_SYSTEMTAP + " [systemtap]" #endif "\n"); @@ -2723,6 +2726,24 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1) #endif BIF_RET(am_true); } + else if (ERTS_IS_ATOM_STR("dynamic_trace", BIF_ARG_1)) { +#if defined(USE_DTRACE) + DECL_AM(dtrace); + BIF_RET(AM_dtrace); +#elif defined(USE_SYSTEMTAP) + DECL_AM(systemtap); + BIF_RET(AM_systemtap); +#else + BIF_RET(am_none); +#endif + } + else if (ERTS_IS_ATOM_STR("dynamic_trace_probes", BIF_ARG_1)) { +#if defined(USE_VM_PROBES) + BIF_RET(am_true); +#else + BIF_RET(am_false); +#endif + } #ifdef ERTS_SMP else if (ERTS_IS_ATOM_STR("thread_progress", BIF_ARG_1)) { erts_thr_progress_dbg_print_state(); -- cgit v1.2.3 From 6969ae73662f7c507977a9560a858a5964c791c4 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Tue, 20 Mar 2012 18:47:03 +0100 Subject: Add documentation for dyntrace and system_info changes --- erts/doc/src/erlang.xml | 23 ++++ lib/runtime_tools/doc/src/Makefile | 2 +- lib/runtime_tools/doc/src/dyntrace.xml | 209 +++++++++++++++++++++++++++++++++ lib/runtime_tools/doc/src/ref_man.xml | 1 + 4 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 lib/runtime_tools/doc/src/dyntrace.xml diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index 0776599fae..0963904b83 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -5744,6 +5744,29 @@ ok used by the runtime system. It will be on the form "<major ver>.<minor ver>".

+ dynamic_trace + +

Returns an atom describing the dynamic trace framework + compiled into the virtual machine. It can currently be either + dtrace, systemtap or none. For a + commercial or standard build, this is always none, + the other return values indicate a custom configuration + (e.g. ./configure --with-dynamic-trace=dtrace). See + the dyntrace + manual page and the + README.dtrace/README.systemtap files in the + Erlang source code top directory for more information + about dynamic tracing.

+
+ dynamic_trace_probes + +

Returns a boolean() indicating if dynamic trace probes + (either dtrace or systemtap) are built into the + emulator. This can only be true if the virtual + machine was built for dynamic tracing + (i.e. system_info(dynamic_trace) returns + dtrace or systemtap).

+
elib_malloc

This option will be removed in a future release. diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile index dbbae81cfe..f1dd788f80 100644 --- a/lib/runtime_tools/doc/src/Makefile +++ b/lib/runtime_tools/doc/src/Makefile @@ -40,7 +40,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) # Target Specs # ---------------------------------------------------- XML_APPLICATION_FILES = ref_man.xml -XML_REF3_FILES = dbg.xml erts_alloc_config.xml +XML_REF3_FILES = dbg.xml dyntrace.xml erts_alloc_config.xml XML_REF6_FILES = runtime_tools_app.xml XML_PART_FILES = part_notes.xml part_notes_history.xml diff --git a/lib/runtime_tools/doc/src/dyntrace.xml b/lib/runtime_tools/doc/src/dyntrace.xml new file mode 100644 index 0000000000..5fc5530f25 --- /dev/null +++ b/lib/runtime_tools/doc/src/dyntrace.xml @@ -0,0 +1,209 @@ + + + + +

+ + 19962012 + Ericsson AB. All Rights Reserved. + + + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + + + dyntrace + Patrik Nyblom + + 1 + ETX/B/SFP (Kenneth Lundin) + + 12-03-20 + A + dyntrace.xml +
+ dyntrace + Interface to dynamic tracing + +

This module implements interfaces to dynamic tracing, should such be compiled into the virtual machine. For a standard and/or commercial build, no dynamic tracing is available, in which case none of the functions in this module is usable or give any effect.

+

Should dynamic tracing be enabled in the current build, either by configuring with ./configure --with-dynamic-trace=dtrace or with ./configure --with-dynamic-trace=systemtap, the module can be used for two things:

+ + Trigger the user-probe user_trace_i4s4 in the NIF library dyntrace.so by calling dyntrace:p/{1,2,3,4,5,6,7,8}. + Set a user specified tag that will be present in the trace messages of both the efile_drv and the user-probe mentioned above. + +

Both building with dynamic trace probes and using them is experimental and unsupported by Erlang/OTP. It is included as an option for the developer to trace and debug performance issues in their systems.

+

The original implementation is mostly done by Scott Lystiger Fritchie as an Open Source Contribution and it should be viewed as such even though the source for dynamic tracing as well as this module is included in the main distribution. However, the ability to use dynamic tracing of the virtual machine is a very valuable contribution which OTP has every intention to maintain as a tool for the developer.

+

How to write d programs or systemtap scripts can be learned from books and from a lot of pages on the Internet. This manual page does not include any documentation about using the dynamic trace tools of respective platform. The examples directory of the runtime_tools application however contains comprehensive examples of both d and systemtap programs that will help you get started. Another source of information is the README.dtrace(.md) and README.systemtap(.md) files in the Erlang source top directory.

+
+ + + available() -> boolean() + Check if dynamic tracing is available + +

This function uses the NIF library to determine if dynamic + tracing is available. Usually calling erlang:system_info/1 + is a better indicator of the availability of dynamic + tracing.

+

The function will throw an exception if the dyntrace NIF library could not be loaded by the on_load function of this module.

+
+
+ + p() -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message only containing the user tag and zeroes/empty strings in all other fields.

+
+
+ + p(integer() | string()) -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer or string parameter in the first integer/string field.

+
+
+ + p(integer() | string(), integer() | string()) -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters. I.e. p(1,"Hello") is ok, as is p(1,1) and p("Hello","Again"), but not p("Hello",1).

+
+
+ + p(integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in p/2.

+
+
+ + p(integer() | string(), integer() | string(), integer() | string(), integer() | string()) -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in p/2.

+
+
+ + p(integer(), integer() | string(), integer() | string(), integer() | string(), string()) -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in p/2.

+

There can be no more than four parameters of any type (integer() or string()), so the first parameter has to be an integer() and the last a string().

+
+
+ + p(integer(), integer(), integer() | string(), integer() | string(), string(), string()) -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in p/2.

+

There can be no more than four parameters of any type (integer() or string()), so the first two parameters has to be integer()'s and the last two string()'s.

+
+
+ + p(integer(), integer(), integer(), integer() | string(), string(), string(), string()) -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing the user tag and the integer() or string() parameters as the first fields of respective type. integer() parameters should be put before any string() parameters, as in p/2.

+

There can be no more than four parameters of any type (integer() or string()), so the first three parameters has to be integer()'s and the last three string()'s.

+
+
+ + p(integer(), integer(), integer(), integer(), string(), string(), string(), string()) -> true | false | error | badarg + Trigger the user trace probe. + +

Calling this function will trigger the "user" trace probe user_trace_i4s4 in the dyntrace NIF module, sending a trace message containing all the integer()'s and string()'s provided, as well as any user tag set in the current process.

+
+
+ + get_tag() -> binary() | undefined + Get the user tag set in the process. + +

This function returns the user tag set in the current + process. If no tag is set or dynamic tracing is not available, + it returns undefined

+
+
+ + get_tag() -> binary() | undefined + Get the user tag set in the process or sent to the process. + +

This function returns the user tag set in the current + process or, if no user tag is present, the last user tag sent + to the process together with a message (in the same way as + sequential trace + tokens are spread to other processes together with + messages. For an explanation of how user tags can be spread + together with messages, see spread_tag/1. If no tag is + found or dynamic tracing is not available, it returns + undefined

+
+
+ + + put_tag(Item) -> binary() | undefined + Set the user tag of the current process. + + Item = iodata() + + +

This function sets the user tag of the current process. The user tag is a binary(), but can be specified as any iodata(), which is automatically converted to a binary by this function.

+

The user tag is provided to the user probes triggered by calls top dyntrace:p/{1,2,3,4,5,6,7,8} as well as probes in the efile_driver. In the future, user tags might be added to more probes.

+

The old user tag (if any) is returned, or undefined if no user tag was present or dynamic tracing is not enabled.

+
+
+ + spread_tag(boolean()) -> TagData + Start or stop spreading dynamic trace user tags with the next message. + + TagData = opaque data that can be used as parameter to restore_tag/1 + + +

This function controls if user tags are to be spread to other processes with the next message. Spreading of user tags work like spreading of sequential trace tokens, so that a received user tag will be active in the process until the next message arrives (if that message does not also contain the user tag.

+

This functionality is used when a client process communicates with a file i/o-server to spread the user tag to the I/O-server and then down to the efile_drv driver. By using spread_tag/1 and restore_tag/1, one can enable or disable spreading of user tags to other processes and then restore the previous state of the user tag. The TagData returned from this call contains all previous information so the state (including any previously spread user tags) will be completely restored by a later call to restore_tag/1.

+

The file module already spread's tags, so there is noo need to manually call these function to get user tags spread to the efile driver through that module.

+

The most use of this function would be if one for example uses the io module to communicate with an I/O-server for a regular file, like in the following example:

+
+f() ->
+   {ok, F} = file:open("test.tst",[write]),
+   Saved = dyntrace:spread_tag(true),
+   io:format(F,"Hello world!",[]),
+   dyntrace:restore_tag(Saved),
+   file:close(F).
+
+

In this example, any user tag set in the calling process will be spread to the I/O-server when the io:format call is done.

+
+
+ + restore_tag(TagData) -> true + Restore to a previous state of user tag spreading. + + TagData = opaque data returned by spread_tag/1 + + +

Restores the previous state of user tags and their spreading as it was before a call to spread_tag/1. Note that the restoring is not limited to the same process, one can utilize this to turn off spreding in one process and restore it in a newly created, the one that actually is going to send messages:

+
+f() ->
+    TagData=dyntrace:spread_tag(false),
+    spawn(fun() ->
+             dyntrace:restore_tag(TagData),
+             do_something()
+          end),
+    do_something_else(),
+    dyntrace:restore_tag(TagData).
+
+

Correctly handling user tags and their spreading might take some effort, as Erlang programs tend to send and receive messages so that sometimes the user tag gets lost due to various things, like double receives or communication with a port (ports do not handle user tags, in the same way as they do not handle regular sequential trace tokens).

+
+
+
+ + diff --git a/lib/runtime_tools/doc/src/ref_man.xml b/lib/runtime_tools/doc/src/ref_man.xml index 579efcd969..41fa5f17c4 100644 --- a/lib/runtime_tools/doc/src/ref_man.xml +++ b/lib/runtime_tools/doc/src/ref_man.xml @@ -33,6 +33,7 @@ + -- cgit v1.2.3 From ee14f5a400b94b7ded000d7d3dc4c47c9ce1d315 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Tue, 20 Mar 2012 18:48:34 +0100 Subject: Remove code causing dialyzer warning from prim_file --- erts/preloaded/ebin/prim_file.beam | Bin 40672 -> 40608 bytes erts/preloaded/src/prim_file.erl | 15 +++++---------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam index a62a461146..6400cda2b5 100644 Binary files a/erts/preloaded/ebin/prim_file.beam and b/erts/preloaded/ebin/prim_file.beam differ diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 8d6ec96f33..0ecb720726 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -268,7 +268,7 @@ advise(#file_descriptor{module = ?MODULE, data = {Port, _}}, %% Returns {error, Reason} | ok. write(#file_descriptor{module = ?MODULE, data = {Port, _}}, Bytes) -> - case drv_command_nt(Port, [?FILE_WRITE,erlang:dt_prepend_vm_tag_data(Bytes)],false,undefined) of + case drv_command_nt(Port, [?FILE_WRITE,erlang:dt_prepend_vm_tag_data(Bytes)],undefined) of {ok, _Size} -> ok; Error -> @@ -284,7 +284,7 @@ pwrite_int(_, [], 0, [], []) -> ok; pwrite_int(Port, [], N, Spec, Data) -> Header = list_to_binary([?FILE_PWRITEV, erlang:dt_prepend_vm_tag_data(<>) | reverse(Spec)]), - case drv_command_nt(Port, [Header | reverse(Data)], false, undefined) of + case drv_command_nt(Port, [Header | reverse(Data)], undefined) of {ok, _Size} -> ok; Error -> @@ -402,7 +402,7 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, L) pread_int(_, [], 0, []) -> {ok, []}; pread_int(Port, [], N, Spec) -> - drv_command_nt(Port, [?FILE_PREADV, erlang:dt_prepend_vm_tag_data(<<0:32, N:32>>) | reverse(Spec)],false, undefined); + drv_command_nt(Port, [?FILE_PREADV, erlang:dt_prepend_vm_tag_data(<<0:32, N:32>>) | reverse(Spec)],undefined); pread_int(Port, [{Offs, Size} | T], N, Spec) when is_integer(Offs), is_integer(Size), 0 =< Size -> if @@ -425,7 +425,7 @@ pread(#file_descriptor{module = ?MODULE, data = {Port, _}}, Offs, Size) Size < ?LARGEFILESIZE -> case drv_command_nt(Port, [?FILE_PREADV, erlang:dt_prepend_vm_tag_data(<<0:32, 1:32, - Offs:64/signed, Size:64>>)], false, undefined) of + Offs:64/signed, Size:64>>)], undefined) of {ok, [eof]} -> eof; {ok, [Data]} -> @@ -990,17 +990,12 @@ drv_command({Driver, Portopts}, Command, Validated, R) -> Error -> Error end. -drv_command_nt(Port, Command, Validated, R) when is_port(Port) -> +drv_command_nt(Port, Command, R) when is_port(Port) -> Save = erlang:dt_spread_tag(false), try erlang:port_command(Port, Command) of true -> drv_get_response(Port, R) catch - %% If the Command is valid, knowing that the port is a port, - %% a badarg error must mean it is a dead port, that is: - %% a currently invalid filehandle, -> einval, not badarg. - error:badarg when Validated -> - {error, einval}; error:badarg -> try erlang:iolist_size(Command) of _ -> % Valid -- cgit v1.2.3 From 062b599f16ff74e0ae6495b09df85bfd8560afdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 20 Mar 2012 12:30:28 +0100 Subject: erl_process.c: Fix probe for process exit --- erts/emulator/beam/erl_process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index ff4e9c3d88..95d408f79d 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -8439,10 +8439,10 @@ erts_do_exit_process(Process* p, Eterm reason) #ifdef USE_VM_PROBES if (DTRACE_ENABLED(process_exit)) { DTRACE_CHARBUF(process_buf, DTRACE_TERM_BUF_SIZE); - DTRACE_CHARBUF(reason_buf, 256); + DTRACE_CHARBUF(reason_buf, DTRACE_TERM_BUF_SIZE); dtrace_proc_str(p, process_buf); - erts_snprintf(reason_buf, sizeof(reason_buf) - 1, "%T", reason); + erts_snprintf(reason_buf, DTRACE_TERM_BUF_SIZE - 1, "%T", reason); DTRACE2(process_exit, process_buf, reason_buf); } #endif -- cgit v1.2.3 From 654983b39f9aaaf2297ab1cd4b60243ea119bcdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 21 Mar 2012 10:42:19 +0100 Subject: Don't try to "clean up" generated fun names The fun names may look ugly, but if we clean them up we can't distinguish calls to the function defining the fun and to the fun itself. --- erts/emulator/beam/global.h | 24 ++---------------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 7f12004b43..b000e2c5d4 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -2007,32 +2007,12 @@ dtrace_fun_decode(Process *process, Eterm module, Eterm function, int arity, char *process_buf, char *mfa_buf) { - char funbuf[DTRACE_TERM_BUF_SIZE]; - char *funptr = funbuf; - char *p = NULL; - if (process_buf) { dtrace_proc_str(process, process_buf); } - erts_snprintf(funbuf, sizeof(funbuf), "%T", function); - /* - * I'm not quite sure how these function names are synthesized, - * but they almost always seem to be in the form of - * '-name/arity-fun-0-' so I'm chopping them up when it's -fun-0- - * (which seems to be the toplevel) - */ - if (funbuf[0] == '\'' && funbuf[1] == '-' - && strlen(funbuf) > 3 && funbuf[strlen(funbuf) - 3] == '0') { - p = strchr(funbuf, '/'); - if (p) { - *p = 0; - } - funptr += 2; - } - - erts_snprintf(mfa_buf, DTRACE_TERM_BUF_SIZE, "%T:%s/%d", - module, funptr, arity); + erts_snprintf(mfa_buf, DTRACE_TERM_BUF_SIZE, "%T:%T/%d", + module, function, arity); } #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */ -- cgit v1.2.3 From e3163d8482c01bd61a76c3c69adfd45df94b8f7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 21 Mar 2012 11:28:35 +0100 Subject: Add probes for all kind of calls --- erts/emulator/beam/beam_emu.c | 59 +++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 5c5d9fd049..6a758f6e19 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1052,6 +1052,10 @@ init_emulator(void) #endif #ifdef USE_VM_PROBES +# define USE_VM_CALL_PROBES +#endif + +#ifdef USE_VM_CALL_PROBES #define DTRACE_CALL(p, m, f, a) \ if (DTRACE_ENABLED(function_entry)) { \ @@ -1504,6 +1508,7 @@ void process_main(void) /* FALL THROUGH */ OpCase(i_call_only_f): { SET_I((BeamInstr *) Arg(0)); + DTRACE_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); Dispatch(); } @@ -1515,6 +1520,7 @@ void process_main(void) RESTORE_CP(E); E = ADD_BYTE_OFFSET(E, Arg(1)); SET_I((BeamInstr *) Arg(0)); + DTRACE_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); Dispatch(); } @@ -1526,6 +1532,7 @@ void process_main(void) OpCase(i_call_f): { SET_CP(c_p, I+2); SET_I((BeamInstr *) Arg(0)); + DTRACE_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); Dispatch(); } @@ -1542,6 +1549,12 @@ void process_main(void) * is not loaded, it points to code which will invoke the error handler * (see lb_call_error_handler below). */ +#ifdef USE_VM_CALL_PROBES + if (DTRACE_ENABLED(function_entry)) { + BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); + DTRACE_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); + } +#endif Dispatchx(); OpCase(i_move_call_ext_cre): { @@ -1551,6 +1564,12 @@ void process_main(void) /* FALL THROUGH */ OpCase(i_call_ext_e): SET_CP(c_p, I+2); +#ifdef USE_VM_CALL_PROBES + if (DTRACE_ENABLED(function_entry)) { + BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); + DTRACE_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); + } +#endif Dispatchx(); OpCase(i_move_call_ext_only_ecr): { @@ -1558,6 +1577,12 @@ void process_main(void) } /* FALL THROUGH */ OpCase(i_call_ext_only_e): +#ifdef USE_VM_CALL_PROBES + if (DTRACE_ENABLED(function_entry)) { + BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); + DTRACE_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); + } +#endif Dispatchx(); OpCase(init_y): { @@ -1593,12 +1618,12 @@ void process_main(void) OpCase(return): { -#ifdef USE_VM_PROBES +#ifdef USE_VM_CALL_PROBES BeamInstr* fptr; #endif SET_I(c_p->cp); -#ifdef USE_VM_PROBES +#ifdef USE_VM_CALL_PROBES if (DTRACE_ENABLED(function_return) && (fptr = find_function_from_pc(c_p->cp))) { DTRACE_RETURN(c_p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); } @@ -6087,12 +6112,10 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) save_calls(p, ep); } -#ifdef USE_VM_PROBES - if (DTRACE_ENABLED(function_entry) && ep->address) { - BeamInstr *fptr = find_function_from_pc(ep->address); - if (fptr) { - DTRACE_CALL(p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); - } +#ifdef USE_VM_CALL_PROBES + if (DTRACE_ENABLED(function_entry)) { + BeamInstr *fptr = (BeamInstr *) ep->address; + DTRACE_CALL(p, (Eterm)fptr[-3], (Eterm)fptr[-2], (Uint)fptr[-1]); } #endif return ep->address; @@ -6144,12 +6167,10 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) save_calls(p, ep); } -#ifdef USE_VM_PROBES +#ifdef USE_VM_CALL_PROBES if (DTRACE_ENABLED(function_entry)) { - BeamInstr *fptr = find_function_from_pc(ep->address); - if (fptr) { - DTRACE_CALL(p, (Eterm)fptr[0], (Eterm)fptr[1], (Uint)fptr[2]); - } + BeamInstr *fptr = (BeamInstr *) ep->address; + DTRACE_CALL(p, (Eterm)fptr[-3], (Eterm)fptr[-2], (Uint)fptr[-1]); } #endif return ep->address; @@ -6284,16 +6305,10 @@ call_fun(Process* p, /* Current process. */ code_ptr = fe->address; actual_arity = (int) code_ptr[-1]; -#ifdef USE_VM_PROBES - if (DTRACE_ENABLED(function_entry)) { - BeamInstr *fptr = find_function_from_pc(code_ptr); - - if (fptr) { - DTRACE_CALL(p, fe->module, (Eterm)fptr[1], actual_arity); - } - } -#endif if (actual_arity == arity+num_free) { + DTRACE_CALL(p, (Eterm)code_ptr[-3], + (Eterm)code_ptr[-2], + code_ptr[-1]); if (num_free == 0) { return code_ptr; } else { -- cgit v1.2.3 From 848f6e541f779e13f7d99bbd0c99ac37a9bd56e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 21 Mar 2012 12:00:05 +0100 Subject: Correct calculation of stack depth in call/return probes --- erts/emulator/beam/beam_emu.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 6a758f6e19..69a3d7e81a 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1061,8 +1061,7 @@ init_emulator(void) if (DTRACE_ENABLED(function_entry)) { \ DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ - int depth = (STACK_START(p) - STACK_TOP(p)) \ - / sizeof(Eterm*); \ + int depth = STACK_START(p) - STACK_TOP(p); \ dtrace_fun_decode(p, m, f, a, \ process_name, mfa); \ DTRACE3(function_entry, process_name, mfa, depth); \ @@ -1072,8 +1071,7 @@ init_emulator(void) if (DTRACE_ENABLED(function_return)) { \ DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ - int depth = (STACK_START(p) - STACK_TOP(p)) \ - / sizeof(Eterm*); \ + int depth = STACK_START(p) - STACK_TOP(p); \ dtrace_fun_decode(p, m, f, a, \ process_name, mfa); \ DTRACE3(function_return, process_name, mfa, depth); \ -- cgit v1.2.3 From 1e653c3539423e4cfdeab1d232483bcac0e8b073 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 21 Mar 2012 14:26:47 +0100 Subject: Use distinct function-entry probes for local and global calls It seems useful to be able to filter out (for example) just the global calls. --- erts/emulator/beam/beam_emu.c | 71 +++++++++++++--------- erts/emulator/beam/erlang_dtrace.d | 14 ++++- lib/runtime_tools/examples/function-calls.d | 10 ++- .../examples/function-calls.systemtap | 10 ++- 4 files changed, 69 insertions(+), 36 deletions(-) diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 69a3d7e81a..8b4f067b98 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1057,14 +1057,24 @@ init_emulator(void) #ifdef USE_VM_CALL_PROBES -#define DTRACE_CALL(p, m, f, a) \ - if (DTRACE_ENABLED(function_entry)) { \ - DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ - DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ - int depth = STACK_START(p) - STACK_TOP(p); \ - dtrace_fun_decode(p, m, f, a, \ - process_name, mfa); \ - DTRACE3(function_entry, process_name, mfa, depth); \ +#define DTRACE_LOCAL_CALL(p, m, f, a) \ + if (DTRACE_ENABLED(local_function_entry)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ + int depth = STACK_START(p) - STACK_TOP(p); \ + dtrace_fun_decode(p, m, f, a, \ + process_name, mfa); \ + DTRACE3(local_function_entry, process_name, mfa, depth); \ + } + +#define DTRACE_GLOBAL_CALL(p, m, f, a) \ + if (DTRACE_ENABLED(global_function_entry)) { \ + DTRACE_CHARBUF(process_name, DTRACE_TERM_BUF_SIZE); \ + DTRACE_CHARBUF(mfa, DTRACE_TERM_BUF_SIZE); \ + int depth = STACK_START(p) - STACK_TOP(p); \ + dtrace_fun_decode(p, m, f, a, \ + process_name, mfa); \ + DTRACE3(global_function_entry, process_name, mfa, depth); \ } #define DTRACE_RETURN(p, m, f, a) \ @@ -1115,12 +1125,13 @@ init_emulator(void) #else /* USE_VM_PROBES */ -#define DTRACE_CALL(p, m, f, a) do {} while (0) -#define DTRACE_RETURN(p, m, f, a) do {} while (0) -#define DTRACE_BIF_ENTRY(p, m, f, a) do {} while (0) -#define DTRACE_BIF_RETURN(p, m, f, a) do {} while (0) -#define DTRACE_NIF_ENTRY(p, m, f, a) do {} while (0) -#define DTRACE_NIF_RETURN(p, m, f, a) do {} while (0) +#define DTRACE_LOCAL_CALL(p, m, f, a) do {} while (0) +#define DTRACE_GLOBAL_CALL(p, m, f, a) do {} while (0) +#define DTRACE_RETURN(p, m, f, a) do {} while (0) +#define DTRACE_BIF_ENTRY(p, m, f, a) do {} while (0) +#define DTRACE_BIF_RETURN(p, m, f, a) do {} while (0) +#define DTRACE_NIF_ENTRY(p, m, f, a) do {} while (0) +#define DTRACE_NIF_RETURN(p, m, f, a) do {} while (0) #endif /* USE_VM_PROBES */ @@ -1506,7 +1517,7 @@ void process_main(void) /* FALL THROUGH */ OpCase(i_call_only_f): { SET_I((BeamInstr *) Arg(0)); - DTRACE_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); + DTRACE_LOCAL_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); Dispatch(); } @@ -1518,7 +1529,7 @@ void process_main(void) RESTORE_CP(E); E = ADD_BYTE_OFFSET(E, Arg(1)); SET_I((BeamInstr *) Arg(0)); - DTRACE_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); + DTRACE_LOCAL_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); Dispatch(); } @@ -1530,7 +1541,7 @@ void process_main(void) OpCase(i_call_f): { SET_CP(c_p, I+2); SET_I((BeamInstr *) Arg(0)); - DTRACE_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); + DTRACE_LOCAL_CALL(c_p, (Eterm)I[-3], (Eterm)I[-2], I[-1]); Dispatch(); } @@ -1548,9 +1559,9 @@ void process_main(void) * (see lb_call_error_handler below). */ #ifdef USE_VM_CALL_PROBES - if (DTRACE_ENABLED(function_entry)) { + if (DTRACE_ENABLED(global_function_entry)) { BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); - DTRACE_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); + DTRACE_GLOBAL_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); } #endif Dispatchx(); @@ -1563,9 +1574,9 @@ void process_main(void) OpCase(i_call_ext_e): SET_CP(c_p, I+2); #ifdef USE_VM_CALL_PROBES - if (DTRACE_ENABLED(function_entry)) { + if (DTRACE_ENABLED(global_function_entry)) { BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); - DTRACE_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); + DTRACE_GLOBAL_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); } #endif Dispatchx(); @@ -1576,9 +1587,9 @@ void process_main(void) /* FALL THROUGH */ OpCase(i_call_ext_only_e): #ifdef USE_VM_CALL_PROBES - if (DTRACE_ENABLED(function_entry)) { + if (DTRACE_ENABLED(global_function_entry)) { BeamInstr* fp = (BeamInstr *) (((Export *) Arg(0))->address); - DTRACE_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); + DTRACE_GLOBAL_CALL(c_p, (Eterm)fp[-3], (Eterm)fp[-2], fp[-1]); } #endif Dispatchx(); @@ -6111,9 +6122,9 @@ apply(Process* p, Eterm module, Eterm function, Eterm args, Eterm* reg) } #ifdef USE_VM_CALL_PROBES - if (DTRACE_ENABLED(function_entry)) { + if (DTRACE_ENABLED(global_function_entry)) { BeamInstr *fptr = (BeamInstr *) ep->address; - DTRACE_CALL(p, (Eterm)fptr[-3], (Eterm)fptr[-2], (Uint)fptr[-1]); + DTRACE_GLOBAL_CALL(p, (Eterm)fptr[-3], (Eterm)fptr[-2], (Uint)fptr[-1]); } #endif return ep->address; @@ -6166,9 +6177,9 @@ fixed_apply(Process* p, Eterm* reg, Uint arity) } #ifdef USE_VM_CALL_PROBES - if (DTRACE_ENABLED(function_entry)) { + if (DTRACE_ENABLED(global_function_entry)) { BeamInstr *fptr = (BeamInstr *) ep->address; - DTRACE_CALL(p, (Eterm)fptr[-3], (Eterm)fptr[-2], (Uint)fptr[-1]); + DTRACE_GLOBAL_CALL(p, (Eterm)fptr[-3], (Eterm)fptr[-2], (Uint)fptr[-1]); } #endif return ep->address; @@ -6304,7 +6315,7 @@ call_fun(Process* p, /* Current process. */ actual_arity = (int) code_ptr[-1]; if (actual_arity == arity+num_free) { - DTRACE_CALL(p, (Eterm)code_ptr[-3], + DTRACE_LOCAL_CALL(p, (Eterm)code_ptr[-3], (Eterm)code_ptr[-2], code_ptr[-1]); if (num_free == 0) { @@ -6399,7 +6410,7 @@ call_fun(Process* p, /* Current process. */ actual_arity = (int) ep->code[2]; if (arity == actual_arity) { - DTRACE_CALL(p, ep->code[0], ep->code[1], (Uint)ep->code[2]); + DTRACE_GLOBAL_CALL(p, ep->code[0], ep->code[1], (Uint)ep->code[2]); return ep->address; } else { /* @@ -6475,7 +6486,7 @@ call_fun(Process* p, /* Current process. */ reg[1] = function; reg[2] = args; } - DTRACE_CALL(p, module, function, arity); + DTRACE_GLOBAL_CALL(p, module, function, arity); return ep->address; } else { badfun: diff --git a/erts/emulator/beam/erlang_dtrace.d b/erts/emulator/beam/erlang_dtrace.d index d8508426f4..587e51cb67 100644 --- a/erts/emulator/beam/erlang_dtrace.d +++ b/erts/emulator/beam/erlang_dtrace.d @@ -149,13 +149,23 @@ provider erlang { /* PID, Module, Function, Arity */ /** - * Fired whenever a user function is being called. + * Fired whenever a user function is being called locally. * * @param p the PID (string form) of the process * @param mfa the m:f/a of the function * @param depth the stack depth */ - probe function__entry(char *p, char *mfa, int depth); + probe local__function__entry(char *p, char *mfa, int depth); + + /** + * Fired whenever a user function is called externally + * (through an export entry). + * + * @param p the PID (string form) of the process + * @param mfa the m:f/a of the function + * @param depth the stack depth + */ + probe global__function__entry(char *p, char *mfa, int depth); /** * Fired whenever a user function returns. diff --git a/lib/runtime_tools/examples/function-calls.d b/lib/runtime_tools/examples/function-calls.d index 238c5211ac..3e015dc2d2 100644 --- a/lib/runtime_tools/examples/function-calls.d +++ b/lib/runtime_tools/examples/function-calls.d @@ -18,9 +18,15 @@ * %CopyrightEnd% */ -erlang*:::function-entry +erlang*:::local-function-entry { - printf("pid %s enter %s depth %d\n", + printf("pid %s enter (local) %s depth %d\n", + copyinstr(arg0), copyinstr(arg1), arg2); +} + +erlang*:::global-function-entry +{ + printf("pid %s enter (global) %s depth %d\n", copyinstr(arg0), copyinstr(arg1), arg2); } diff --git a/lib/runtime_tools/examples/function-calls.systemtap b/lib/runtime_tools/examples/function-calls.systemtap index 8fc4375135..16c9c04918 100644 --- a/lib/runtime_tools/examples/function-calls.systemtap +++ b/lib/runtime_tools/examples/function-calls.systemtap @@ -28,9 +28,15 @@ * environment. */ -probe process("beam").mark("function-entry") +probe process("beam").mark("local-function-entry") { - printf("pid %s enter %s depth %d\n", + printf("pid %s enter (local) %s depth %d\n", + user_string($arg1), user_string($arg2), $arg3); +} + +probe process("beam").mark("global-function-entry") +{ + printf("pid %s enter (global) %s depth %d\n", user_string($arg1), user_string($arg2), $arg3); } -- cgit v1.2.3