diff options
-rw-r--r-- | README.dtrace.md | 37 | ||||
-rw-r--r-- | erts/emulator/Makefile.in | 6 | ||||
-rw-r--r-- | erts/emulator/beam/beam_emu.c | 85 | ||||
-rw-r--r-- | erts/emulator/beam/dist.c | 16 | ||||
-rw-r--r-- | erts/emulator/beam/dtrace-wrapper.h | 9 | ||||
-rw-r--r-- | erts/emulator/beam/erl_async.c | 10 | ||||
-rw-r--r-- | erts/emulator/beam/erl_gc.c | 1 | ||||
-rw-r--r-- | erts/emulator/beam/erl_message.c | 12 | ||||
-rw-r--r-- | erts/emulator/beam/global.h | 69 | ||||
-rw-r--r-- | erts/emulator/drivers/common/efile_drv.c | 26 | ||||
-rw-r--r-- | erts/lib_src/common/erl_printf.c | 2 | ||||
-rw-r--r-- | erts/preloaded/ebin/prim_file.beam | bin | 46840 -> 46736 bytes | |||
-rw-r--r-- | erts/preloaded/src/prim_file.erl | 22 | ||||
-rw-r--r-- | lib/dtrace/c_src/Makefile | 2 | ||||
-rw-r--r-- | lib/dtrace/c_src/Makefile.in | 15 | ||||
-rw-r--r-- | lib/dtrace/c_src/dtrace.c | 16 | ||||
-rw-r--r-- | lib/dtrace/examples/dist.d | 14 | ||||
-rw-r--r-- | lib/dtrace/examples/port1.d | 8 | ||||
-rw-r--r-- | lib/dtrace/examples/process-scheduling.d | 2 | ||||
-rw-r--r-- | lib/dtrace/src/dtrace.erl | 38 | ||||
-rw-r--r-- | lib/kernel/src/file.erl | 8 | ||||
-rw-r--r-- | 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 <assert.h> #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), "<unknown/%p>", next); + erts_snprintf(fun_buf, sizeof(fun_buf), + "<unknown/%p>", 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 <ctype.h> #include <sys/types.h> @@ -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 Binary files differindex 9d6c47ffc1..6778fe353c 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam 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}; |