void print_memory_info(Process *p) { if (p != NULL) { erts_printf("======================================\n"); erts_printf("|| Memory info for %-12T ||\n",p->common.id); erts_printf("======================================\n"); erts_printf("+- local heap ----%s-%s-%s-%s-+\n", dashes,dashes,dashes,dashes); erts_printf("| Young | 0x%0*lx - (0x%0*lx) - 0x%0*lx - 0x%0*lx |\n", PTR_SIZE, (unsigned long)HEAP_START(p), PTR_SIZE, (unsigned long)HIGH_WATER(p), PTR_SIZE, (unsigned long)HEAP_TOP(p), PTR_SIZE, (unsigned long)HEAP_END(p)); if (OLD_HEAP(p) != NULL) erts_printf("| Old | 0x%0*lx - 0x%0*lx - 0x%0*lx %*s |\n", PTR_SIZE, (unsigned long)OLD_HEAP(p), PTR_SIZE, (unsigned long)OLD_HTOP(p), PTR_SIZE, (unsigned long)OLD_HEND(p), PTR_SIZE, ""); } else { erts_printf("=================\n"); erts_printf("|| Memory info ||\n"); erts_printf("=================\n"); } erts_printf("+-----------------%s-%s-%s-%s-+\n",dashes,dashes,dashes,dashes); }
BIF_RETTYPE hipe_bifs_gc_info_0(BIF_ALIST_0) { #ifdef __BENCHMARK__ #ifndef BM_COUNTERS Uint minor_gc = 0; Uint major_gc = 0; #endif #ifndef BM_HEAP_SIZES Uint max_used_heap = 0; Uint max_allocated_heap = 0; #endif Eterm *hp; Uint used_heap = (BIF_P->htop - BIF_P->heap) + (OLD_HTOP(BIF_P) - OLD_HEAP(BIF_P)) + MBUF_SIZE(BIF_P); Uint alloc_heap = (BIF_P->hend - BIF_P->heap) + (OLD_HEND(BIF_P) - OLD_HEAP(BIF_P)) + MBUF_SIZE(BIF_P); hp = HAlloc(BIF_P, 7); BIF_RET(TUPLE6(hp, make_small((Uint)minor_gc), make_small((Uint)major_gc), make_small((Uint)used_heap), make_small((Uint)alloc_heap), make_small(max_used_heap), make_small(max_allocated_heap))); #else BIF_RET(am_false); #endif }
static int within2(Eterm *ptr, Process *p, Eterm *real_htop) { ErlHeapFragment* bp = MBUF(p); ErlMessage* mp = p->msg.first; Eterm *htop = real_htop ? real_htop : HEAP_TOP(p); if (OLD_HEAP(p) && (OLD_HEAP(p) <= ptr && ptr < OLD_HEND(p))) { return 1; } if (HEAP_START(p) <= ptr && ptr < htop) { return 1; } while (bp != NULL) { if (bp->mem <= ptr && ptr < bp->mem + bp->used_size) { return 1; } bp = bp->next; } while (mp) { if (mp->data.attached) { ErlHeapFragment *hfp; if (is_value(ERL_MESSAGE_TERM(mp))) hfp = mp->data.heap_frag; else if (is_not_nil(ERL_MESSAGE_TOKEN(mp))) hfp = erts_dist_ext_trailer(mp->data.dist_ext); else hfp = NULL; if (hfp && hfp->mem <= ptr && ptr < hfp->mem + hfp->used_size) return 1; } mp = mp->next; } return 0; }
/* * erts_check_heap and erts_check_memory will run through the heap * silently if everything is ok. If there are strange (untagged) data * in the heap or wild pointers, the system will be halted with an * error message. */ void erts_check_heap(Process *p) { ErlHeapFragment* bp = MBUF(p); erts_check_memory(p,HEAP_START(p),HEAP_TOP(p)); if (OLD_HEAP(p) != NULL) { erts_check_memory(p,OLD_HEAP(p),OLD_HTOP(p)); } while (bp) { erts_check_memory(p,bp->mem,bp->mem + bp->used_size); bp = bp->next; } }
static void print_garb_info(int to, void *to_arg, Process* p) { /* ERTS_SMP: A scheduler is probably concurrently doing gc... */ #ifndef ERTS_SMP erts_print(to, to_arg, "New heap start: %bpX\n", p->heap); erts_print(to, to_arg, "New heap top: %bpX\n", p->htop); erts_print(to, to_arg, "Stack top: %bpX\n", p->stop); erts_print(to, to_arg, "Stack end: %bpX\n", p->hend); erts_print(to, to_arg, "Old heap start: %bpX\n", OLD_HEAP(p)); erts_print(to, to_arg, "Old heap top: %bpX\n", OLD_HTOP(p)); erts_print(to, to_arg, "Old heap end: %bpX\n", OLD_HEND(p)); #endif }
static void print_process_memory(Process *p) { ErlHeapFragment* bp = MBUF(p); erts_printf("==============================\n"); erts_printf("|| Memory info for %T ||\n",p->common.id); erts_printf("==============================\n"); erts_printf("-- %-*s ---%s-%s-%s-%s--\n", PTR_SIZE, "PCB", dashes, dashes, dashes, dashes); if (p->msg.first != NULL) { ErtsMessage* mp; erts_printf(" Message Queue:\n"); mp = p->msg.first; while (mp != NULL) { erts_printf("| 0x%0*lx | 0x%0*lx |\n",PTR_SIZE, ERL_MESSAGE_TERM(mp),PTR_SIZE,ERL_MESSAGE_TOKEN(mp)); mp = mp->next; } } if (p->dictionary != NULL) { int n = ERTS_PD_SIZE(p->dictionary); Eterm *ptr = ERTS_PD_START(p->dictionary); erts_printf(" Dictionary: "); while (n--) erts_printf("0x%0*lx ",PTR_SIZE,(unsigned long)ptr++); erts_printf("\n"); } if (p->arity > 0) { int n = p->arity; Eterm *ptr = p->arg_reg; erts_printf(" Argument Registers: "); while (n--) erts_printf("0x%0*lx ",PTR_SIZE,(unsigned long)*ptr++); erts_printf("\n"); } erts_printf(" Trace Token: 0x%0*lx\n",PTR_SIZE,p->seq_trace_token); erts_printf(" Group Leader: 0x%0*lx\n",PTR_SIZE,p->group_leader); erts_printf(" Fvalue: 0x%0*lx\n",PTR_SIZE,p->fvalue); erts_printf(" Ftrace: 0x%0*lx\n",PTR_SIZE,p->ftrace); erts_printf("+- %-*s -+ 0x%0*lx 0x%0*lx %s-%s-+\n", PTR_SIZE, "Stack", PTR_SIZE, (unsigned long)STACK_TOP(p), PTR_SIZE, (unsigned long)STACK_START(p), dashes, dashes); print_untagged_memory(STACK_TOP(p),STACK_START(p)); erts_printf("+- %-*s -+ 0x%0*lx 0x%0*lx 0x%0*lx 0x%0*lx +\n", PTR_SIZE, "Heap", PTR_SIZE, (unsigned long)HEAP_START(p), PTR_SIZE, (unsigned long)HIGH_WATER(p), PTR_SIZE, (unsigned long)HEAP_TOP(p), PTR_SIZE, (unsigned long)HEAP_END(p)); print_untagged_memory(HEAP_START(p),HEAP_TOP(p)); if (OLD_HEAP(p)) { erts_printf("+- %-*s -+ 0x%0*lx 0x%0*lx 0x%0*lx %s-+\n", PTR_SIZE, "Old Heap", PTR_SIZE, (unsigned long)OLD_HEAP(p), PTR_SIZE, (unsigned long)OLD_HTOP(p), PTR_SIZE, (unsigned long)OLD_HEND(p), dashes); print_untagged_memory(OLD_HEAP(p),OLD_HTOP(p)); } if (bp) erts_printf("+- %-*s -+-%s-%s-%s-%s-+\n", PTR_SIZE, "heap fragments", dashes, dashes, dashes, dashes); while (bp) { print_untagged_memory(bp->mem,bp->mem + bp->used_size); bp = bp->next; } }
/* Display info about an individual Erlang process */ void print_process_info(int to, void *to_arg, Process *p) { time_t approx_started; int garbing = 0; int running = 0; struct saved_calls *scb; erts_aint32_t state; /* display the PID */ erts_print(to, to_arg, "=proc:%T\n", p->common.id); /* Display the state */ erts_print(to, to_arg, "State: "); state = erts_smp_atomic32_read_acqb(&p->state); erts_dump_process_state(to, to_arg, state); if (state & ERTS_PSFLG_GC) { garbing = 1; running = 1; } else if (state & ERTS_PSFLG_RUNNING) running = 1; /* * If the process is registered as a global process, display the * registered name */ if (p->common.u.alive.reg) erts_print(to, to_arg, "Name: %T\n", p->common.u.alive.reg->name); /* * Display the initial function name */ erts_print(to, to_arg, "Spawned as: %T:%T/%bpu\n", p->u.initial[INITIAL_MOD], p->u.initial[INITIAL_FUN], p->u.initial[INITIAL_ARI]); if (p->current != NULL) { if (running) { erts_print(to, to_arg, "Last scheduled in for: "); } else { erts_print(to, to_arg, "Current call: "); } erts_print(to, to_arg, "%T:%T/%bpu\n", p->current[0], p->current[1], p->current[2]); } erts_print(to, to_arg, "Spawned by: %T\n", p->parent); approx_started = (time_t) p->approx_started; erts_print(to, to_arg, "Started: %s", ctime(&approx_started)); ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p); erts_print(to, to_arg, "Message queue length: %d\n", p->msg.len); /* display the message queue only if there is anything in it */ if (!ERTS_IS_CRASH_DUMPING && p->msg.first != NULL && !garbing) { ErlMessage* mp; erts_print(to, to_arg, "Message queue: ["); for (mp = p->msg.first; mp; mp = mp->next) erts_print(to, to_arg, mp->next ? "%T," : "%T", ERL_MESSAGE_TERM(mp)); erts_print(to, to_arg, "]\n"); } { int frags = 0; ErlHeapFragment *m = p->mbuf; while (m != NULL) { frags++; m = m->next; } erts_print(to, to_arg, "Number of heap fragments: %d\n", frags); } erts_print(to, to_arg, "Heap fragment data: %beu\n", MBUF_SIZE(p)); scb = ERTS_PROC_GET_SAVED_CALLS_BUF(p); if (scb) { int i, j; erts_print(to, to_arg, "Last calls:"); for (i = 0; i < scb->n; i++) { erts_print(to, to_arg, " "); j = scb->cur - i - 1; if (j < 0) j += scb->len; if (scb->ct[j] == &exp_send) erts_print(to, to_arg, "send"); else if (scb->ct[j] == &exp_receive) erts_print(to, to_arg, "'receive'"); else if (scb->ct[j] == &exp_timeout) erts_print(to, to_arg, "timeout"); else erts_print(to, to_arg, "%T:%T/%bpu\n", scb->ct[j]->code[0], scb->ct[j]->code[1], scb->ct[j]->code[2]); } erts_print(to, to_arg, "\n"); } /* display the links only if there are any*/ if (ERTS_P_LINKS(p) || ERTS_P_MONITORS(p)) { PrintMonitorContext context = {1,to}; erts_print(to, to_arg,"Link list: ["); erts_doforall_links(ERTS_P_LINKS(p), &doit_print_link, &context); erts_doforall_monitors(ERTS_P_MONITORS(p), &doit_print_monitor, &context); erts_print(to, to_arg,"]\n"); } if (!ERTS_IS_CRASH_DUMPING) { /* and the dictionary */ if (p->dictionary != NULL && !garbing) { erts_print(to, to_arg, "Dictionary: "); erts_dictionary_dump(to, to_arg, p->dictionary); erts_print(to, to_arg, "\n"); } } /* print the number of reductions etc */ erts_print(to, to_arg, "Reductions: %beu\n", p->reds); erts_print(to, to_arg, "Stack+heap: %beu\n", p->heap_sz); erts_print(to, to_arg, "OldHeap: %bpu\n", (OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HEAP(p)) ); erts_print(to, to_arg, "Heap unused: %bpu\n", (p->hend - p->htop)); erts_print(to, to_arg, "OldHeap unused: %bpu\n", (OLD_HEAP(p) == NULL) ? 0 : (OLD_HEND(p) - OLD_HTOP(p)) ); erts_print(to, to_arg, "Memory: %beu\n", erts_process_memory(p)); if (garbing) { print_garb_info(to, to_arg, p); } if (ERTS_IS_CRASH_DUMPING) { erts_program_counter_info(to, to_arg, p); } else { erts_print(to, to_arg, "Stack dump:\n"); #ifdef ERTS_SMP if (!garbing) #endif erts_stack_dump(to, to_arg, p); } /* Display all states */ erts_print(to, to_arg, "Internal State: "); erts_dump_extended_process_state(to, to_arg, state); }