static ERTS_INLINE void stat_upd_free(ErtsAlcType_t n, Uint size) { ErtsAlcType_t t = ERTS_ALC_N2T(n); ErtsAlcType_t a = ERTS_ALC_T2A(t); ErtsAlcType_t c = ERTS_ALC_T2C(t); ASSERT(stats->ap[a]->size >= size); stats->ap[a]->size -= size; ASSERT(stats->c[c].size >= size); stats->c[c].size -= size; ASSERT(stats->n[n].size >= size); stats->n[n].size -= size; ASSERT(stats->tot.size >= size); stats->tot.size -= size; ASSERT(stats->ap[a]->blocks > 0); stats->ap[a]->blocks--; ASSERT(stats->c[c].blocks > 0); stats->c[c].blocks--; ASSERT(stats->n[n].blocks > 0); stats->n[n].blocks--; ASSERT(stats->tot.blocks > 0); stats->tot.blocks--; }
Eterm erts_instr_get_type_info(Process *proc) { Eterm res, *tpls; Uint hsz, *hszp, *hp, **hpp; ErtsAlcType_t n; if (!am_n) init_am_n(); if (!am_a) init_am_a(); if (!am_c) init_am_c(); tpls = (Eterm *) erts_alloc(ERTS_ALC_T_TMP, (ERTS_ALC_N_MAX-ERTS_ALC_N_MIN+1) * sizeof(Eterm)); hsz = 0; hszp = &hsz; hpp = NULL; restart_bld: #if ERTS_ALC_N_MIN != 1 #error ERTS_ALC_N_MIN is not 1 #endif for (n = ERTS_ALC_N_MIN; n <= ERTS_ALC_N_MAX; n++) { ErtsAlcType_t t = ERTS_ALC_N2T(n); ErtsAlcType_t a = ERTS_ALC_T2A(t); ErtsAlcType_t c = ERTS_ALC_T2C(t); if (!erts_allctrs_info[a].enabled) a = ERTS_ALC_A_SYSTEM; tpls[n - ERTS_ALC_N_MIN] = bld_tuple(hpp, hszp, 3, am_n[n], am_a[a], am_c[c]); } res = bld_tuplev(hpp, hszp, ERTS_ALC_N_MAX-ERTS_ALC_N_MIN+1, tpls); if (!hpp) { hp = HAlloc(proc, hsz); hszp = NULL; hpp = &hp; goto restart_bld; } erts_free(ERTS_ALC_T_TMP, tpls); return res; }
static ERTS_INLINE void stat_upd_alloc(ErtsAlcType_t n, Uint size) { ErtsAlcType_t t = ERTS_ALC_N2T(n); ErtsAlcType_t a = ERTS_ALC_T2A(t); ErtsAlcType_t c = ERTS_ALC_T2C(t); stats->ap[a]->size += size; if (stats->ap[a]->max_size < stats->ap[a]->size) stats->ap[a]->max_size = stats->ap[a]->size; stats->c[c].size += size; if (stats->c[c].max_size < stats->c[c].size) stats->c[c].max_size = stats->c[c].size; stats->n[n].size += size; if (stats->n[n].max_size < stats->n[n].size) stats->n[n].max_size = stats->n[n].size; stats->tot.size += size; if (stats->tot.max_size < stats->tot.size) stats->tot.max_size = stats->tot.size; stats->ap[a]->blocks++; if (stats->ap[a]->max_blocks < stats->ap[a]->blocks) stats->ap[a]->max_blocks = stats->ap[a]->blocks; stats->c[c].blocks++; if (stats->c[c].max_blocks < stats->c[c].blocks) stats->c[c].max_blocks = stats->c[c].blocks; stats->n[n].blocks++; if (stats->n[n].max_blocks < stats->n[n].blocks) stats->n[n].max_blocks = stats->n[n].blocks; stats->tot.blocks++; if (stats->tot.max_blocks < stats->tot.blocks) stats->tot.max_blocks = stats->tot.blocks; }
Eterm erts_instr_get_memory_map(Process *proc) { MapStatBlock_t *org_mem_anchor; Eterm hdr_tuple, md_list, res; Eterm *hp; Uint hsz; MapStatBlock_t *bp; #ifdef DEBUG Eterm *end_hp; #endif if (!erts_instr_memory_map) return am_false; if (!atoms_initialized) init_atoms(); if (!am_n) init_am_n(); if (!am_c) init_am_c(); if (!am_a) init_am_a(); erts_mtx_lock(&instr_x_mutex); erts_mtx_lock(&instr_mutex); /* Header size */ hsz = 5 + 1 + (ERTS_ALC_N_MAX+1-ERTS_ALC_N_MIN)*(1 + 4); /* Memory data list */ for (bp = mem_anchor; bp; bp = bp->next) { if (is_internal_pid(bp->pid)) { #if (_PID_NUM_SIZE - 1 > MAX_SMALL) if (internal_pid_number(bp->pid) > MAX_SMALL) hsz += BIG_UINT_HEAP_SIZE; #endif #if (_PID_SER_SIZE - 1 > MAX_SMALL) if (internal_pid_serial(bp->pid) > MAX_SMALL) hsz += BIG_UINT_HEAP_SIZE; #endif hsz += 4; } if ((UWord) bp->mem > MAX_SMALL) hsz += BIG_UINT_HEAP_SIZE; if (bp->size > MAX_SMALL) hsz += BIG_UINT_HEAP_SIZE; hsz += 5 + 2; } hsz += 3; /* Root tuple */ org_mem_anchor = mem_anchor; mem_anchor = NULL; erts_mtx_unlock(&instr_mutex); hp = HAlloc(proc, hsz); /* May end up calling map_stat_alloc() */ erts_mtx_lock(&instr_mutex); #ifdef DEBUG end_hp = hp + hsz; #endif { /* Build header */ ErtsAlcType_t n; Eterm type_map; Uint *hp2 = hp; #ifdef DEBUG Uint *hp2_end; #endif hp += (ERTS_ALC_N_MAX + 1 - ERTS_ALC_N_MIN)*4; #ifdef DEBUG hp2_end = hp; #endif type_map = make_tuple(hp); *(hp++) = make_arityval(ERTS_ALC_N_MAX + 1 - ERTS_ALC_N_MIN); for (n = ERTS_ALC_N_MIN; n <= ERTS_ALC_N_MAX; n++) { ErtsAlcType_t t = ERTS_ALC_N2T(n); ErtsAlcType_t a = ERTS_ALC_T2A(t); ErtsAlcType_t c = ERTS_ALC_T2C(t); if (!erts_allctrs_info[a].enabled) a = ERTS_ALC_A_SYSTEM; *(hp++) = TUPLE3(hp2, am_n[n], am_a[a], am_c[c]); hp2 += 4; } ASSERT(hp2 == hp2_end); hdr_tuple = TUPLE4(hp, am.instr_hdr, make_small(ERTS_INSTR_VSN), make_small(MAP_STAT_BLOCK_HEADER_SIZE), type_map); hp += 5; } /* Build memory data list */ for (md_list = NIL, bp = org_mem_anchor; bp; bp = bp->next) { Eterm tuple; Eterm type; Eterm ptr; Eterm size; Eterm pid; if (is_not_internal_pid(bp->pid)) pid = am_undefined; else { Eterm c; Eterm n; Eterm s; #if (ERST_INTERNAL_CHANNEL_NO > MAX_SMALL) #error Oversized internal channel number #endif c = make_small(ERST_INTERNAL_CHANNEL_NO); #if (_PID_NUM_SIZE - 1 > MAX_SMALL) if (internal_pid_number(bp->pid) > MAX_SMALL) { n = uint_to_big(internal_pid_number(bp->pid), hp); hp += BIG_UINT_HEAP_SIZE; } else #endif n = make_small(internal_pid_number(bp->pid)); #if (_PID_SER_SIZE - 1 > MAX_SMALL) if (internal_pid_serial(bp->pid) > MAX_SMALL) { s = uint_to_big(internal_pid_serial(bp->pid), hp); hp += BIG_UINT_HEAP_SIZE; } else #endif s = make_small(internal_pid_serial(bp->pid)); pid = TUPLE3(hp, c, n, s); hp += 4; } #if ERTS_ALC_N_MAX > MAX_SMALL #error Oversized memory type number #endif type = make_small(bp->type_no); if ((UWord) bp->mem > MAX_SMALL) { ptr = uint_to_big((UWord) bp->mem, hp); hp += BIG_UINT_HEAP_SIZE; } else ptr = make_small((UWord) bp->mem); if (bp->size > MAX_SMALL) { size = uint_to_big(bp->size, hp); hp += BIG_UINT_HEAP_SIZE; } else size = make_small(bp->size); tuple = TUPLE4(hp, type, ptr, size, pid); hp += 5; md_list = CONS(hp, tuple, md_list); hp += 2; } res = TUPLE2(hp, hdr_tuple, md_list); ASSERT(hp + 3 == end_hp); if (mem_anchor) { for (bp = mem_anchor; bp->next; bp = bp->next) ; ASSERT(org_mem_anchor); org_mem_anchor->prev = bp; bp->next = org_mem_anchor; } else { mem_anchor = org_mem_anchor; } erts_mtx_unlock(&instr_mutex); erts_mtx_unlock(&instr_x_mutex); return res; }
static void dump_memory_map_to_stream(FILE *fp) { ErtsAlcType_t n; MapStatBlock_t *bp; int lock = !ERTS_IS_CRASH_DUMPING; if (lock) { ASSERT(!erts_is_allctr_wrapper_prelocked()); erts_mtx_lock(&instr_mutex); } /* Write header */ fprintf(fp, "{instr_hdr,\n" " %lu,\n" " %lu,\n" " {", (unsigned long) ERTS_INSTR_VSN, (unsigned long) MAP_STAT_BLOCK_HEADER_SIZE); #if ERTS_ALC_N_MIN != 1 #error ERTS_ALC_N_MIN is not 1 #endif for (n = ERTS_ALC_N_MIN; n <= ERTS_ALC_N_MAX; n++) { ErtsAlcType_t t = ERTS_ALC_N2T(n); ErtsAlcType_t a = ERTS_ALC_T2A(t); ErtsAlcType_t c = ERTS_ALC_T2C(t); const char *astr; if (erts_allctrs_info[a].enabled) astr = ERTS_ALC_A2AD(a); else astr = ERTS_ALC_A2AD(ERTS_ALC_A_SYSTEM); fprintf(fp, "%s{%s,%s,%s}%s", (n == ERTS_ALC_N_MIN) ? "" : " ", ERTS_ALC_N2TD(n), astr, ERTS_ALC_C2CD(c), (n == ERTS_ALC_N_MAX) ? "" : ",\n"); } fprintf(fp, "}}.\n"); /* Write memory data */ for (bp = mem_anchor; bp; bp = bp->next) { if (is_internal_pid(bp->pid)) fprintf(fp, "{%lu, %lu, %lu, {%lu,%lu,%lu}}.\n", (UWord) bp->type_no, (UWord) bp->mem, (UWord) bp->size, (UWord) pid_channel_no(bp->pid), (UWord) pid_number(bp->pid), (UWord) pid_serial(bp->pid)); else fprintf(fp, "{%lu, %lu, %lu, undefined}.\n", (UWord) bp->type_no, (UWord) bp->mem, (UWord) bp->size); } if (lock) erts_mtx_unlock(&instr_mutex); }
static int write_trace_header(char *nodename, char *pid, char *hostname) { #ifdef DEBUG byte *startp; #endif Uint16 entry_sz; Uint32 flags, n_len, h_len, p_len, hdr_prolog_len; int i, no, str_len; const char *str; struct { Uint32 gsec; Uint32 sec; Uint32 usec; } start_time; sys_gettimeofday(&last_tv); start_time.gsec = (Uint32) (last_tv.tv_sec / 1000000000); start_time.sec = (Uint32) (last_tv.tv_sec % 1000000000); start_time.usec = (Uint32) last_tv.tv_usec; if (!MAKE_TBUF_SZ(3*UI32_SZ)) return 0; flags = 0; #ifdef ARCH_64 flags |= ERTS_MT_64_BIT_FLAG; #endif flags |= ERTS_MT_CRR_INFO; #ifdef ERTS_CAN_TRACK_MALLOC flags |= ERTS_MT_SEG_CRR_INFO; #endif /* * The following 3 ui32 words *always* have to come * first in the trace. */ PUT_UI32(tracep, ERTS_MT_START_WORD); PUT_UI32(tracep, ERTS_MT_MAJOR_VSN); PUT_UI32(tracep, ERTS_MT_MINOR_VSN); n_len = strlen(nodename); h_len = strlen(hostname); p_len = strlen(pid); hdr_prolog_len = (2*UI32_SZ + 3*UI16_SZ + 3*UI32_SZ + 3*UI8_SZ + n_len + h_len + p_len); if (!MAKE_TBUF_SZ(hdr_prolog_len)) return 0; /* * New stuff can be added at the end the of header prolog * (EOHP). The reader should skip stuff at the end, that it * doesn't understand. */ #ifdef DEBUG startp = tracep; #endif PUT_UI32(tracep, hdr_prolog_len); PUT_UI32(tracep, flags); PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID); PUT_UI16(tracep, ERTS_ALC_A_MAX); PUT_UI16(tracep, ERTS_ALC_N_MAX); PUT_UI32(tracep, start_time.gsec); PUT_UI32(tracep, start_time.sec); PUT_UI32(tracep, start_time.usec); PUT_UI8(tracep, (byte) n_len); memcpy((void *) tracep, (void *) nodename, n_len); tracep += n_len; PUT_UI8(tracep, (byte) h_len); memcpy((void *) tracep, (void *) hostname, h_len); tracep += h_len; PUT_UI8(tracep, (byte) p_len); memcpy((void *) tracep, (void *) pid, p_len); tracep += p_len; ASSERT(startp + hdr_prolog_len == tracep); /* * EOHP */ /* * All tags from here on should be followed by an Uint16 size * field containing the total size of the entry. * * New stuff can eigther be added at the end of an entry, or * as a new tagged entry. The reader should skip stuff at the * end, that it doesn't understand. */ for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { Uint16 aflags = 0; #ifndef ERTS_CAN_TRACK_MALLOC if (i != ERTS_ALC_A_SYSTEM) #endif aflags |= ERTS_MT_ALLCTR_USD_CRR_INFO; str = ERTS_ALC_A2AD(i); ASSERT(str); str_len = strlen(str); if (str_len >= (1 << 8)) { disable_trace(1, "Excessively large allocator string", 0); return 0; } entry_sz = UI8_SZ + 3*UI16_SZ + UI8_SZ; entry_sz += (erts_allctrs_info[i].alloc_util ? 2 : 1)*UI16_SZ; entry_sz += UI8_SZ + str_len; if (!MAKE_TBUF_SZ(entry_sz)) return 0; #ifdef DEBUG startp = tracep; #endif PUT_UI8(tracep, ERTS_MT_ALLOCATOR_HDR_TAG); PUT_UI16(tracep, entry_sz); PUT_UI16(tracep, aflags); PUT_UI16(tracep, (Uint16) i); PUT_UI8( tracep, (byte) str_len); memcpy((void *) tracep, (void *) str, str_len); tracep += str_len; if (erts_allctrs_info[i].alloc_util) { PUT_UI8(tracep, 2); PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID); PUT_UI16(tracep, ERTS_ALC_A_SYSTEM); } else { PUT_UI8(tracep, 1); switch (i) { case ERTS_ALC_A_SYSTEM: PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID); break; default: PUT_UI16(tracep, ERTS_MTRACE_SEGMENT_ID); break; } } ASSERT(startp + entry_sz == tracep); } for (i = ERTS_ALC_N_MIN; i <= ERTS_ALC_N_MAX; i++) { Uint16 nflags = 0; str = ERTS_ALC_N2TD(i); ASSERT(str); str_len = strlen(str); if (str_len >= (1 << 8)) { disable_trace(1, "Excessively large type string", 0); return 0; } no = ERTS_ALC_T2A(ERTS_ALC_N2T(i)); if (!erts_allctrs_info[no].enabled) no = ERTS_ALC_A_SYSTEM; ASSERT(ERTS_ALC_A_MIN <= no && no <= ERTS_ALC_A_MAX); entry_sz = UI8_SZ + 3*UI16_SZ + UI8_SZ + str_len + UI16_SZ; if (!MAKE_TBUF_SZ(entry_sz)) return 0; #ifdef DEBUG startp = tracep; #endif PUT_UI8(tracep, ERTS_MT_BLOCK_TYPE_HDR_TAG); PUT_UI16(tracep, entry_sz); PUT_UI16(tracep, nflags); PUT_UI16(tracep, (Uint16) i); PUT_UI8(tracep, (byte) str_len); memcpy((void *) tracep, (void *) str, str_len); tracep += str_len; PUT_UI16(tracep, no); ASSERT(startp + entry_sz == tracep); } entry_sz = UI8_SZ + UI16_SZ; if (!MAKE_TBUF_SZ(entry_sz)) return 0; PUT_UI8(tracep, ERTS_MT_END_OF_HDR_TAG); PUT_UI16(tracep, entry_sz); return 1; }