📄 erl_instrument.c
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "global.h"#include "big.h"#include "erl_instrument.h"#include "erl_threads.h"typedef union { long l; double d; } Align_t;typedef struct { Uint size; Align_t mem[1];} StatBlock_t;#define STAT_BLOCK_HEADER_SIZE (sizeof(StatBlock_t) - sizeof(Align_t))typedef struct MapStatBlock_t_ MapStatBlock_t;struct MapStatBlock_t_ { Uint size; ErtsAlcType_t type_no; Eterm pid; MapStatBlock_t *prev; MapStatBlock_t *next; Align_t mem[1];};#define MAP_STAT_BLOCK_HEADER_SIZE (sizeof(MapStatBlock_t) - sizeof(Align_t))typedef struct { Uint size; Uint max_size; Uint max_size_ever; Uint blocks; Uint max_blocks; Uint max_blocks_ever;} Stat_t;static erts_mtx_t instr_mutex;static erts_mtx_t instr_x_mutex;int erts_instr_memory_map;int erts_instr_stat;static ErtsAllocatorFunctions_t real_allctrs[ERTS_ALC_A_MAX+1];struct stats_ { Stat_t tot; Stat_t a[ERTS_ALC_A_MAX+1]; Stat_t *ap[ERTS_ALC_A_MAX+1]; Stat_t c[ERTS_ALC_C_MAX+1]; Stat_t n[ERTS_ALC_N_MAX+1];};static struct stats_ *stats;static MapStatBlock_t *mem_anchor;static Eterm *am_tot;static Eterm *am_n;static Eterm *am_a;static Eterm *am_c;static int atoms_initialized;static struct { Eterm total; Eterm allocators; Eterm classes; Eterm types; Eterm sizes; Eterm blocks; Eterm instr_hdr;#ifdef DEBUG Eterm end_of_atoms;#endif} am;static void ERTS_INLINE atom_init(Eterm *atom, const char *name){ *atom = am_atom_put((char *) name, strlen(name));}#define AM_INIT(AM) atom_init(&am.AM, #AM)static voidinit_atoms(void){#ifdef DEBUG Eterm *atom; for (atom = (Eterm *) &am; atom <= &am.end_of_atoms; atom++) { *atom = THE_NON_VALUE; }#endif AM_INIT(total); AM_INIT(allocators); AM_INIT(classes); AM_INIT(types); AM_INIT(sizes); AM_INIT(blocks); AM_INIT(instr_hdr);#ifdef DEBUG for (atom = (Eterm *) &am; atom < &am.end_of_atoms; atom++) { ASSERT(*atom != THE_NON_VALUE); }#endif atoms_initialized = 1;}#undef AM_INITstatic voidinit_am_tot(void){ am_tot = (Eterm *) erts_alloc(ERTS_ALC_T_INSTR_INFO, sizeof(Eterm)); atom_init(am_tot, "total");}static voidinit_am_n(void){ int i; am_n = (Eterm *) erts_alloc(ERTS_ALC_T_INSTR_INFO, (ERTS_ALC_N_MAX+1)*sizeof(Eterm)); for (i = ERTS_ALC_N_MIN; i <= ERTS_ALC_N_MAX; i++) { atom_init(&am_n[i], ERTS_ALC_N2TD(i)); }}static voidinit_am_c(void){ int i; am_c = (Eterm *) erts_alloc(ERTS_ALC_T_INSTR_INFO, (ERTS_ALC_C_MAX+1)*sizeof(Eterm)); for (i = ERTS_ALC_C_MIN; i <= ERTS_ALC_C_MAX; i++) { atom_init(&am_c[i], ERTS_ALC_C2CD(i)); }}static voidinit_am_a(void){ int i; am_a = (Eterm *) erts_alloc(ERTS_ALC_T_INSTR_INFO, (ERTS_ALC_A_MAX+1)*sizeof(Eterm)); for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { atom_init(&am_a[i], ERTS_ALC_A2AD(i)); }}static ERTS_INLINE voidstat_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;}static ERTS_INLINE voidstat_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--;}static ERTS_INLINE voidstat_upd_realloc(ErtsAlcType_t n, Uint size, Uint old_size){ if (old_size) stat_upd_free(n, old_size); stat_upd_alloc(n, size);}/* * stat instrumentation callback functions */static void *stat_alloc(ErtsAlcType_t n, void *extra, Uint size){ ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; Uint ssize; void *res; erts_mtx_lock(&instr_mutex); ssize = size + STAT_BLOCK_HEADER_SIZE; res = (*real_af->alloc)(n, real_af->extra, ssize); if (res) { stat_upd_alloc(n, size); ((StatBlock_t *) res)->size = size; res = (void *) ((StatBlock_t *) res)->mem; } erts_mtx_unlock(&instr_mutex); return res;}static void *stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size){ ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; Uint old_size; Uint ssize; void *sptr; void *res; erts_mtx_lock(&instr_mutex); if (ptr) { sptr = (void *) (((char *) ptr) - STAT_BLOCK_HEADER_SIZE); old_size = ((StatBlock_t *) sptr)->size; } else { sptr = NULL; old_size = 0; } ssize = size + STAT_BLOCK_HEADER_SIZE; res = (*real_af->realloc)(n, real_af->extra, sptr, ssize); if (res) { stat_upd_realloc(n, size, old_size); ((StatBlock_t *) res)->size = size; res = (void *) ((StatBlock_t *) res)->mem; } erts_mtx_unlock(&instr_mutex); return res;}static voidstat_free(ErtsAlcType_t n, void *extra, void *ptr){ ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; void *sptr; erts_mtx_lock(&instr_mutex); if (ptr) { sptr = (void *) (((char *) ptr) - STAT_BLOCK_HEADER_SIZE); stat_upd_free(n, ((StatBlock_t *) sptr)->size); } else { sptr = NULL; } (*real_af->free)(n, real_af->extra, sptr); erts_mtx_unlock(&instr_mutex);}/* * map stat instrumentation callback functions */static void *map_stat_alloc(ErtsAlcType_t n, void *extra, Uint size){ ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; Uint msize; void *res; erts_mtx_lock(&instr_mutex); msize = size + MAP_STAT_BLOCK_HEADER_SIZE; res = (*real_af->alloc)(n, real_af->extra, msize); if (res) { MapStatBlock_t *mb = (MapStatBlock_t *) res; stat_upd_alloc(n, size); mb->size = size; mb->type_no = n; mb->pid = erts_get_current_pid(); mb->prev = NULL; mb->next = mem_anchor; if (mem_anchor) mem_anchor->prev = mb; mem_anchor = mb; res = (void *) mb->mem; } erts_mtx_unlock(&instr_mutex); return res;}static void *map_stat_realloc(ErtsAlcType_t n, void *extra, void *ptr, Uint size){ ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; Uint old_size; Uint msize; void *mptr; void *res; erts_mtx_lock(&instr_x_mutex); erts_mtx_lock(&instr_mutex); if (ptr) { mptr = (void *) (((char *) ptr) - MAP_STAT_BLOCK_HEADER_SIZE); old_size = ((MapStatBlock_t *) mptr)->size; } else { mptr = NULL; old_size = 0; } msize = size + MAP_STAT_BLOCK_HEADER_SIZE; res = (*real_af->realloc)(n, real_af->extra, mptr, msize); if (res) { MapStatBlock_t *mb = (MapStatBlock_t *) res; mb->size = size; mb->type_no = n; mb->pid = erts_get_current_pid(); stat_upd_realloc(n, size, old_size); if (mptr != res) { if (mptr) { if (mb->prev) mb->prev->next = mb; else { ASSERT(mem_anchor == (MapStatBlock_t *) mptr); mem_anchor = mb; } if (mb->next) mb->next->prev = mb; } else { mb->prev = NULL; mb->next = mem_anchor; if (mem_anchor) mem_anchor->prev = mb; mem_anchor = mb; } } res = (void *) mb->mem; } erts_mtx_unlock(&instr_mutex); erts_mtx_unlock(&instr_x_mutex); return res;}static voidmap_stat_free(ErtsAlcType_t n, void *extra, void *ptr){ ErtsAllocatorFunctions_t *real_af = (ErtsAllocatorFunctions_t *) extra; void *mptr; erts_mtx_lock(&instr_x_mutex); erts_mtx_lock(&instr_mutex); if (ptr) { MapStatBlock_t *mb; mptr = (void *) (((char *) ptr) - MAP_STAT_BLOCK_HEADER_SIZE); mb = (MapStatBlock_t *) mptr; stat_upd_free(n, mb->size); if (mb->prev) mb->prev->next = mb->next; else mem_anchor = mb->next; if (mb->next) mb->next->prev = mb->prev; } else { mptr = NULL; } (*real_af->free)(n, real_af->extra, mptr); erts_mtx_unlock(&instr_mutex); erts_mtx_unlock(&instr_x_mutex);}static void dump_memory_map_to_stream(FILE *fp){ ErtsAlcType_t n; MapStatBlock_t *bp; int lock = !ERTS_IS_CRASH_DUMPING; if (lock) 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", (Uint) bp->type_no, (Uint) bp->mem, (Uint) bp->size, (Uint) pid_channel_no(bp->pid), (Uint) pid_number(bp->pid), (Uint) pid_serial(bp->pid)); else fprintf(fp, "{%lu, %lu, %lu, undefined}.\n", (Uint) bp->type_no, (Uint) bp->mem, (Uint) bp->size); } if (lock) erts_mtx_unlock(&instr_mutex);}int erts_instr_dump_memory_map_to_fd(int fd){ char buf[BUFSIZ]; FILE *f; if (!erts_instr_memory_map) return 0; f = fdopen(fd, "w"); if (f == NULL) return 0; /* Avoid allocating memory; we may have run out of it at this point. */ setbuf(f, buf); dump_memory_map_to_stream(f); fflush(f); return 1;}int erts_instr_dump_memory_map(const char *name){ FILE *f; if (!erts_instr_memory_map) return 0; f = fopen(name, "w"); if (f == NULL) return 0; dump_memory_map_to_stream(f); fclose(f); return 1;}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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -