From f5fa3ac80d2f7fcd11ac3e702c29df5ef6c204db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= Date: Thu, 3 Mar 2016 17:13:32 +0100 Subject: runtime_tools: Add lttng 'call' tracing --- erts/emulator/beam/erl_trace.c | 4 +- lib/runtime_tools/c_src/dyntrace.c | 85 +++++++++++++++++++++++++++++++- lib/runtime_tools/c_src/dyntrace_lttng.h | 46 +++++++++++++++++ lib/runtime_tools/src/dyntrace.erl | 4 ++ 4 files changed, 136 insertions(+), 3 deletions(-) diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index fa1d03c588..0842c0c0a4 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -1000,7 +1000,7 @@ erts_trace_return(Process* p, BeamInstr* fi, Eterm retval, ErtsTracer *tracer) mfa = TUPLE3(hp, mod, name, make_small(arity)); hp += 4; send_to_tracer_nif_raw(p, NULL, *tracer, *tracee_flags, p->common.id, - NULL, TRACE_FUN_DEFAULT, am_return_from, mfa, retval, am_true); + NULL, TRACE_FUN_CALL, am_return_from, mfa, retval, am_true); } /* Send {trace_ts, Pid, exception_from, {Mod, Name, Arity}, {Class,Value}, @@ -1055,7 +1055,7 @@ erts_trace_exception(Process* p, BeamInstr mfa[3], Eterm class, Eterm value, cv = TUPLE2(hp, class, value); hp += 3; send_to_tracer_nif_raw(p, NULL, *tracer, *tracee_flags, p->common.id, - NULL, TRACE_FUN_DEFAULT, am_exception_from, mfa_tuple, cv, am_true); + NULL, TRACE_FUN_CALL, am_exception_from, mfa_tuple, cv, am_true); } /* diff --git a/lib/runtime_tools/c_src/dyntrace.c b/lib/runtime_tools/c_src/dyntrace.c index 43d61266cc..a22b546cdd 100644 --- a/lib/runtime_tools/c_src/dyntrace.c +++ b/lib/runtime_tools/c_src/dyntrace.c @@ -71,6 +71,7 @@ static ERL_NIF_TERM trace(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM trace_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM trace_ports(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM trace_running(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM trace_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM trace_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM trace_receive(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM trace_garbage_collection(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -86,6 +87,7 @@ static ErlNifFunc nif_funcs[] = { {"trace_procs", 6, trace_procs}, {"trace_ports", 6, trace_ports}, {"trace_running", 6, trace_running}, + {"trace_call", 6, trace_call}, {"trace_send", 6, trace_send}, {"trace_receive", 6, trace_receive}, {"trace_garbage_collection", 6, trace_garbage_collection} @@ -139,6 +141,12 @@ static ERL_NIF_TERM atom_send_to_non_existing_process; static ERL_NIF_TERM atom_open; static ERL_NIF_TERM atom_closed; +/* 'call' */ + +static ERL_NIF_TERM atom_call; +static ERL_NIF_TERM atom_return_from; +static ERL_NIF_TERM atom_exception_from; + static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { atom_true = enif_make_atom(env,"true"); @@ -187,6 +195,12 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_open = enif_make_atom(env,"open"); atom_closed = enif_make_atom(env,"closed"); + /* 'call' */ + + atom_call = enif_make_atom(env,"call"); + atom_return_from = enif_make_atom(env,"return_from"); + atom_exception_from = enif_make_atom(env,"exception_from"); + return 0; } @@ -322,6 +336,71 @@ static ERL_NIF_TERM trace_garbage_collection(ErlNifEnv* env, int argc, const ERL return atom_ok; } +static ERL_NIF_TERM trace_call(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ +#ifdef HAVE_USE_DTRACE +#elif HAVE_USE_LTTNG + lttng_decl_procbuf(pid); + unsigned int len; + char undef[] = "undefined"; + + lttng_pid_to_str(argv[2], pid); + + if (argv[0] == atom_call) { + const ERL_NIF_TERM* tuple; + int arity; + lttng_decl_mfabuf(mfa); + + if (enif_get_tuple(env, argv[3], &arity, &tuple)) { + if (enif_is_list(env, tuple[2])) { + enif_get_list_length(env, tuple[2], &len); + } else { + enif_get_uint(env, tuple[2], &len); + } + lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); + LTTNG3(function_call, pid, mfa, 0); + } else { + LTTNG3(function_call, pid, undef, 0); + } + } else if (argv[0] == atom_return_from) { + const ERL_NIF_TERM* tuple; + int arity; + lttng_decl_mfabuf(mfa); + + if (enif_get_tuple(env, argv[3], &arity, &tuple)) { + enif_get_uint(env, tuple[2], &len); + lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); + LTTNG3(function_return, pid, mfa, 0); + } else { + LTTNG3(function_return, pid, undef, 0); + } + } else if (argv[0] == atom_exception_from) { + const ERL_NIF_TERM* tuple; + int arity; + lttng_decl_mfabuf(mfa); + char class[LTTNG_BUFFER_SZ]; + + enif_get_tuple(env, argv[4], &arity, &tuple); + erts_snprintf(class, LTTNG_BUFFER_SZ, "%T", tuple[0]); + + if (enif_get_tuple(env, argv[3], &arity, &tuple)) { + enif_get_uint(env, tuple[2], &len); + lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); + LTTNG3(function_exception, pid, mfa, class); + } else { + LTTNG3(function_exception, pid, undef, class); + } + } else { + int i; + erts_fprintf(stderr, "trace call:\r\n"); + for (i = 0; i < argc; i++) { + erts_fprintf(stderr, " %T\r\n", argv[i]); + } + } +#endif + return atom_ok; +} + static ERL_NIF_TERM trace_send(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { @@ -441,7 +520,11 @@ static ERL_NIF_TERM trace_procs(ErlNifEnv* env, int argc, const ERL_NIF_TERM arg lttng_pid_to_str(argv[3], to); if (enif_get_tuple(env, argv[4], &arity, &tuple)) { - enif_get_list_length(env, tuple[2], &len); + if (enif_is_list(env, tuple[2])) { + enif_get_list_length(env, tuple[2], &len); + } else { + enif_get_uint(env, tuple[2], &len); + } lttng_mfa_to_str(tuple[0], tuple[1], len, mfa); LTTNG3(process_spawn, to, pid, mfa); } else { diff --git a/lib/runtime_tools/c_src/dyntrace_lttng.h b/lib/runtime_tools/c_src/dyntrace_lttng.h index 2e0b921621..265af5729f 100644 --- a/lib/runtime_tools/c_src/dyntrace_lttng.h +++ b/lib/runtime_tools/c_src/dyntrace_lttng.h @@ -193,6 +193,52 @@ TRACEPOINT_EVENT( ) ) +/* Call tracing */ + +TRACEPOINT_EVENT( + com_ericsson_dyntrace, + function_call, + TP_ARGS( + char*, pid, + char*, mfa, + unsigned int, depth + ), + TP_FIELDS( + ctf_string(pid, pid) + ctf_string(entry, mfa) + ctf_integer(unsigned int, depth, depth) + ) +) + +TRACEPOINT_EVENT( + com_ericsson_dyntrace, + function_return, + TP_ARGS( + char*, pid, + char*, mfa, + unsigned int, depth + ), + TP_FIELDS( + ctf_string(pid, pid) + ctf_string(entry, mfa) + ctf_integer(unsigned int, depth, depth) + ) +) + +TRACEPOINT_EVENT( + com_ericsson_dyntrace, + function_exception, + TP_ARGS( + char*, pid, + char*, mfa, + char*, type + ), + TP_FIELDS( + ctf_string(pid, pid) + ctf_string(entry, mfa) + ctf_string(class, type) + ) +) /* Process messages */ diff --git a/lib/runtime_tools/src/dyntrace.erl b/lib/runtime_tools/src/dyntrace.erl index 44c5e36242..f776b601cb 100644 --- a/lib/runtime_tools/src/dyntrace.erl +++ b/lib/runtime_tools/src/dyntrace.erl @@ -47,6 +47,7 @@ trace_procs/6, trace_ports/6, trace_running/6, + trace_call/6, trace_send/6, trace_receive/6, trace_garbage_collection/6 @@ -154,6 +155,9 @@ trace_ports(_TraceTag, _TracerState, _Tracee, _FirstTraceTerm, _SecondTraceTerm, trace_running(_TraceTag, _TracerState, _Tracee, _FirstTraceTerm, _SecondTraceTerm, _Opts) -> erlang:nif_error(nif_not_loaded). +trace_call(_TraceTag, _TracerState, _Tracee, _FirstTraceTerm, _SecondTraceTerm, _Opts) -> + erlang:nif_error(nif_not_loaded). + trace_send(_TraceTag, _TracerState, _Tracee, _FirstTraceTerm, _SecondTraceTerm, _Opts) -> erlang:nif_error(nif_not_loaded). -- cgit v1.2.1