📄 erl_trace.c
字号:
#define TS_SIZE(p) (((p)->trace_flags & F_TIMESTAMP) ? 5 : 0)/* * Patch a timestamp into a tuple. The tuple must be the last thing * built on the heap. * * Returns the new hp pointer.*/static Eterm*patch_ts(Eterm tuple, Eterm* hp){ Uint ms, s, us; Eterm* ptr = tuple_val(tuple); int arity = arityval(*ptr); ASSERT((ptr+arity+1) == hp); ptr[0] = make_arityval(arity+1); ptr[1] = am_trace_ts; GET_NOW(&ms, &s, &us); *hp = TUPLE3(hp+1, make_small(ms), make_small(s), make_small(us)); return hp+5;}/* Send {trace_ts, Pid, What, {Mod, Func, Arity}, Timestamp} * or {trace, Pid, What, {Mod, Func, Arity}} * * where 'What' is supposed to be 'in' or 'out'. */voidtrace_sched(Process *p, Eterm what){ Eterm tmp; Eterm mess; Eterm* hp; if (is_internal_port(p->tracer_proc)) { Eterm local_heap[4+5+5]; hp = local_heap; if (p->current == NULL) { p->current = find_function_from_pc(p->i); } if (p->current == NULL) { tmp = make_small(0); } else { tmp = TUPLE3(hp, p->current[0], p->current[1], make_small(p->current[2])); hp += 4; } mess = TUPLE4(hp, am_trace, p->id, what, tmp); hp += 5; erts_smp_mtx_lock(&smq_mtx); if (p->trace_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); } if (what != am_out) { send_to_port(p, mess, &p->tracer_proc, &p->trace_flags); } else { send_to_port(NULL, mess, &p->tracer_proc, &p->trace_flags); } erts_smp_mtx_unlock(&smq_mtx); } else { ErlHeapFragment *bp; ErlOffHeap *off_heap;#ifndef ERTS_SMP Process *tracer;#endif ASSERT(is_internal_pid(p->tracer_proc) && internal_pid_index(p->tracer_proc) < erts_max_processes);#ifdef ERTS_SMP bp = new_message_buffer(9 + TS_SIZE(p)); hp = bp->mem; off_heap = &bp->off_heap;#else tracer = process_tab[internal_pid_index(p->tracer_proc)]; if (INVALID_PID(tracer, p->tracer_proc) || (tracer->trace_flags & F_TRACER) == 0) { p->trace_flags &= ~TRACEE_FLAGS; p->tracer_proc = NIL; return; } hp = erts_alloc_message_heap(9 + TS_SIZE(p), &bp, &off_heap, tracer, 0);#endif if (p->current == NULL) { p->current = find_function_from_pc(p->i); } if (p->current == NULL) { tmp = make_small(0); } else { tmp = TUPLE3(hp, p->current[0], p->current[1], make_small(p->current[2])); hp += 4; } mess = TUPLE4(hp, am_trace,p->id/* Local pid */, what, tmp); hp += 5; erts_smp_mtx_lock(&smq_mtx); if (p->trace_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); }#ifdef ERTS_SMP enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, p->id, p->tracer_proc, mess, bp); erts_smp_mtx_unlock(&smq_mtx);#else erts_queue_message(tracer, 0, bp, mess, NIL);#endif }}/* Send {trace_ts, Pid, Send, Msg, DestPid, Timestamp} * or {trace, Pid, Send, Msg, DestPid} * * where 'Send' is 'send' or 'send_to_non_existing_process'. */voidtrace_send(Process *p, Eterm to, Eterm msg){ Eterm operation; unsigned sz_msg; unsigned sz_to; Eterm* hp; Eterm mess; if (!ARE_TRACE_FLAGS_ON(p, F_TRACE_SEND)) { return; } operation = am_send; if (is_internal_pid(to)) { if (!erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, to, 0)) goto send_to_non_existing_process; } else if(is_external_pid(to) && external_pid_dist_entry(to) == erts_this_dist_entry) { char *s; send_to_non_existing_process: s = "send_to_non_existing_process"; operation = am_atom_put(s, sys_strlen(s)); } if (is_internal_port(p->tracer_proc)) { Eterm local_heap[11]; hp = local_heap; mess = TUPLE5(hp, am_trace, p->id, operation, msg, to); hp += 6; erts_smp_mtx_lock(&smq_mtx); if (p->trace_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); } send_to_port(p, mess, &p->tracer_proc, &p->trace_flags); erts_smp_mtx_unlock(&smq_mtx); } else { Uint need; ErlHeapFragment *bp; ErlOffHeap *off_heap;#ifndef ERTS_SMP Process *tracer;#endif ASSERT(is_internal_pid(p->tracer_proc) && internal_pid_index(p->tracer_proc) < erts_max_processes);#ifndef ERTS_SMP tracer = process_tab[internal_pid_index(p->tracer_proc)]; if (INVALID_PID(tracer, p->tracer_proc) || (tracer->trace_flags & F_TRACER) == 0) { p->trace_flags &= ~TRACEE_FLAGS; p->tracer_proc = NIL; return; }#endif sz_msg = size_object(msg); sz_to = size_object(to); need = sz_msg + sz_to + 6 + TS_SIZE(p); #ifdef ERTS_SMP bp = new_message_buffer(need); hp = bp->mem; off_heap = &bp->off_heap;#else hp = erts_alloc_message_heap(need, &bp, &off_heap, tracer, 0);#endif to = copy_struct(to, sz_to, &hp, off_heap); msg = copy_struct(msg, sz_msg, &hp, off_heap); mess = TUPLE5(hp, am_trace, p->id/* Local pid */, operation, msg, to); hp += 6; erts_smp_mtx_lock(&smq_mtx); if (p->trace_flags & F_TIMESTAMP) { patch_ts(mess, hp); }#ifdef ERTS_SMP enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, p->id, p->tracer_proc, mess, bp); erts_smp_mtx_unlock(&smq_mtx);#else erts_queue_message(tracer, 0, bp, mess, NIL);#endif }}/* Send {trace_ts, Pid, receive, Msg, Timestamp} * or {trace, Pid, receive, Msg} */voidtrace_receive(Process *rp, Eterm msg){ Eterm mess; size_t sz_msg; Eterm* hp; if (is_internal_port(rp->tracer_proc)) { Eterm local_heap[10]; hp = local_heap; mess = TUPLE4(hp, am_trace, rp->id, am_receive, msg); hp += 5; erts_smp_mtx_lock(&smq_mtx); if (rp->trace_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); } send_to_port(rp, mess, &rp->tracer_proc, &rp->trace_flags); erts_smp_mtx_unlock(&smq_mtx); } else { Uint hsz; ErlHeapFragment *bp; ErlOffHeap *off_heap;#ifndef ERTS_SMP Process *tracer;#endif ASSERT(is_internal_pid(rp->tracer_proc) && internal_pid_index(rp->tracer_proc) < erts_max_processes);#ifndef ERTS_SMP tracer = process_tab[internal_pid_index(rp->tracer_proc)]; if (INVALID_PID(tracer, rp->tracer_proc) || (tracer->trace_flags & F_TRACER) == 0) { rp->trace_flags &= ~TRACEE_FLAGS; rp->tracer_proc = NIL; return; }#endif sz_msg = size_object(msg); hsz = sz_msg + 5 + TS_SIZE(rp);#ifdef ERTS_SMP bp = new_message_buffer(hsz); hp = bp->mem; off_heap = &bp->off_heap;#else hp = erts_alloc_message_heap(hsz, &bp, &off_heap, tracer, 0);#endif msg = copy_struct(msg, sz_msg, &hp, off_heap); mess = TUPLE4(hp, am_trace, rp->id/* Local pid */, am_receive, msg); hp += 5; erts_smp_mtx_lock(&smq_mtx); if (rp->trace_flags & F_TIMESTAMP) { patch_ts(mess, hp); }#ifdef ERTS_SMP enqueue_sys_msg_unlocked(SYS_MSG_TYPE_TRACE, rp->id, rp->tracer_proc, mess, bp); erts_smp_mtx_unlock(&smq_mtx);#else erts_queue_message(tracer, 0, bp, mess, NIL);#endif }}intseq_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)) return 0; SEQ_TRACE_TOKEN_SENDER(p) = p->id; /* Internal pid */ SEQ_TRACE_TOKEN_SERIAL(p) = make_small(++(p -> seq_trace_clock)); SEQ_TRACE_TOKEN_LASTCNT(p) = make_small(p -> seq_trace_lastcnt); return 1;}/* Send a sequential trace message to the sequential tracer. * p is the caller (which contains the trace token), * msg is the original message, type is trace type (SEQ_TRACE_SEND etc), * and receiver is the receiver of the message. * * The message to be received by the sequential tracer is: * * TraceMsg = * {seq_trace, Label, {Type, {Lastcnt, Serial}, Sender, Receiver, Msg} [,Timestamp] } * */void seq_trace_output_generic(Eterm token, Eterm msg, Uint type, Eterm receiver, Process *process, Eterm exitfrom){ Eterm mess; ErlHeapFragment* bp; Eterm* hp; Eterm label; Eterm lastcnt_serial; Eterm type_atom; int sz_exit; Eterm seq_tracer; seq_tracer = erts_get_system_seq_tracer(); ASSERT(is_tuple(token) || is_nil(token)); if (SEQ_TRACE_T_SENDER(token) == seq_tracer || token == NIL || (process && process->trace_flags & F_SENSITIVE)) { return; } switch (type) { case SEQ_TRACE_SEND: type_atom = am_send; break; case SEQ_TRACE_PRINT: type_atom = am_print; break; case SEQ_TRACE_RECEIVE: type_atom = am_receive; break; default: erl_exit(1, "invalid type in seq_trace_output_generic: %d:\n", type); return; /* To avoid warning */ } if ((unsigned_val(SEQ_TRACE_T_FLAGS(token)) & type) == 0) { /* No flags set, nothing to do */ return; } if (seq_tracer == am_false) { return; /* no need to send anything */ } if (is_internal_port(seq_tracer)) { Eterm local_heap[64]; hp = local_heap; label = SEQ_TRACE_T_LABEL(token); lastcnt_serial = TUPLE2(hp, SEQ_TRACE_T_LASTCNT(token), SEQ_TRACE_T_SERIAL(token)); hp += 3; if (exitfrom != NIL) { msg = TUPLE3(hp, am_EXIT, exitfrom, msg); hp += 4; } mess = TUPLE5(hp, type_atom, lastcnt_serial, SEQ_TRACE_T_SENDER(token), receiver, msg); hp += 6; erts_smp_mtx_lock(&smq_mtx); if ((unsigned_val(SEQ_TRACE_T_FLAGS(token)) & SEQ_TRACE_TIMESTAMP) == 0) { mess = TUPLE3(hp, am_seq_trace, label, mess); seq_trace_send_to_port(NULL, seq_tracer, mess, NIL); } else { Uint ms,s,us,ts; GET_NOW(&ms, &s, &us); ts = TUPLE3(hp, make_small(ms),make_small(s), make_small(us)); hp += 4; mess = TUPLE4(hp, am_seq_trace, label, mess, ts); seq_trace_send_to_port(process, seq_tracer, mess, ts); } erts_smp_mtx_unlock(&smq_mtx); } else {#ifndef ERTS_SMP Process* tracer;#endif Eterm sender_copy; Eterm receiver_copy; Eterm m2; Uint sz_label, sz_lastcnt_serial, sz_msg, sz_ts, sz_sender, sz_exitfrom, sz_receiver; ASSERT(is_internal_pid(seq_tracer) && internal_pid_index(seq_tracer) < erts_max_processes);#ifndef ERTS_SMP tracer = process_tab[internal_pid_index(seq_tracer)]; if (INVALID_PID(tracer, tracer->id)) { system_seq_tracer = am_false; return; /* no need to send anything */ }#endif if (receiver == seq_tracer) { return; /* no need to send anything */ } sz_label = size_object(SEQ_TRACE_T_LABEL(token)); sz_sender = size_object(SEQ_TRACE_T_SENDER(token)); sz_receiver = size_object(receiver); sz_lastcnt_serial = 3; /* TUPLE2 */ sz_msg = size_object(msg); sz_ts = ((unsigned_val(SEQ_TRACE_T_FLAGS(token)) & SEQ_TRACE_TIMESTAMP) ? 5 : 0); if (exitfrom != NIL) { sz_exit = 4; /* create {'EXIT',exitfrom,msg} */ sz_exitfrom = size_object(exitfrom); } else { sz_exit = 0; sz_exitfrom = 0; } bp = new_message_buffer(4 /* TUPLE3 */ + sz_ts + 6 /* TUPLE5 */ + sz_lastcnt_serial + sz_label + sz_msg + sz_exit + sz_exitfrom + sz_sender + sz_receiver); hp = bp->mem; label = copy_struct(SEQ_TRACE_T_LABEL(token), sz_label, &hp, &bp->off_heap); lastcnt_serial = TUPLE2(hp,SEQ_TRACE_T_LASTCNT(token),SEQ_TRACE_T_SERIAL(token)); hp += 3; m2 = copy_struct(msg, sz_msg, &hp, &bp->off_heap); if (sz_exit) { Eterm exitfrom_copy = copy_struct(exitfrom, sz_exitfrom, &hp, &bp->off_heap); m2 = TUPLE3(hp, am_EXIT, exitfrom_copy, m2); hp += 4; } sender_copy = copy_struct(SEQ_TRACE_T_SENDER(token), sz_sender, &hp, &bp->off_heap); receiver_copy = copy_struct(receiver, sz_receiver, &hp, &bp->off_heap); mess = TUPLE5(hp, type_atom, lastcnt_serial, sender_copy, receiver_copy, m2); hp += 6; erts_smp_mtx_lock(&smq_mtx); if (sz_ts) {/* timestamp should be included */ Uint ms,s,us,ts; GET_NOW(&ms, &s, &us); ts = TUPLE3(hp, make_small(ms),make_small(s), make_small(us)); hp += 4; mess = TUPLE4(hp, am_seq_trace, label, mess, ts); } else { mess = TUPLE3(hp, am_seq_trace, label, mess); }#ifdef ERTS_SMP enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SEQTRACE, NIL, NIL, mess, bp); erts_smp_mtx_unlock(&smq_mtx);#else erts_queue_message(tracer, 0, bp, mess, NIL); /* trace_token must be NIL here */#endif }}/* Send {trace_ts, Pid, return_to, {Mod, Func, Arity}, Timestamp} * or {trace, Pid, return_to, {Mod, Func, Arity}} */void erts_trace_return_to(Process *p, Uint *pc){ Eterm* hp; Eterm mfa; Eterm mess; Eterm local_heap[4+5+5]; Eterm *code_ptr = find_function_from_pc(pc); hp = local_heap; if (!code_ptr) { mfa = am_undefined; } else { mfa = TUPLE3(hp, code_ptr[0], code_ptr[1], make_small(code_ptr[2])); hp += 4; } mess = TUPLE4(hp, am_trace, p->id, am_return_to, mfa); hp += 5; erts_smp_mtx_lock(&smq_mtx); if (p->trace_flags & F_TIMESTAMP) { hp = patch_ts(mess, hp); } if (is_internal_port(p->tracer_proc)) { send_to_port(p, mess, &p->tracer_proc, &p->trace_flags); } else { ErlHeapFragment *bp; ErlOffHeap *off_heap;#ifndef ERTS_SMP Process *tracer;#endif unsigned size; /* * Find the tracer. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -