diff options
author | Damien George <damien.p.george@gmail.com> | 2014-10-24 23:12:25 +0100 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2014-10-24 23:12:25 +0100 |
commit | 0b13f3e026c842facf65743450246b15a8c2e064 (patch) | |
tree | 4793550a3701f766428d3f42e76086896e10100f | |
parent | 564963a1700bfca8f053f864ad170d4a34a26270 (diff) | |
download | micropython-0b13f3e026c842facf65743450246b15a8c2e064.tar.gz micropython-0b13f3e026c842facf65743450246b15a8c2e064.zip |
py: Improve memory usage debugging; better GC AT dumping.
In unix port, mem_info(1) now prints pretty GC alloc table.
-rw-r--r-- | py/gc.c | 35 | ||||
-rw-r--r-- | py/gc.h | 2 | ||||
-rw-r--r-- | py/qstr.c | 9 | ||||
-rw-r--r-- | unix/main.c | 8 |
4 files changed, 34 insertions, 20 deletions
@@ -492,7 +492,7 @@ void gc_free(void *ptr_in) { } } -mp_uint_t gc_nbytes(void *ptr_in) { +mp_uint_t gc_nbytes(const void *ptr_in) { mp_uint_t ptr = (mp_uint_t)ptr_in; if (VERIFY_PTR(ptr)) { @@ -681,31 +681,32 @@ void gc_dump_alloc_table(void) { for (mp_uint_t bl = 0; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB; bl++) { if (bl % DUMP_BYTES_PER_LINE == 0) { // a new line of blocks - #if EXTENSIVE_HEAP_PROFILING { // check if this line contains only free blocks - bool only_free_blocks = true; - for (mp_uint_t bl2 = bl; bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && bl2 < bl + DUMP_BYTES_PER_LINE; bl2++) { - if (ATB_GET_KIND(bl2) != AT_FREE) { - - only_free_blocks = false; + mp_uint_t bl2 = bl; + while (bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && ATB_GET_KIND(bl2) == AT_FREE) { + bl2++; + } + if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) { + // there are at least 2 lines containing only free blocks, so abbreviate their printing + printf("\n (" UINT_FMT " lines all free)", (bl2 - bl) / DUMP_BYTES_PER_LINE); + bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1)); + if (bl >= gc_alloc_table_byte_len * BLOCKS_PER_ATB) { + // got to end of heap break; } } - if (only_free_blocks) { - // line contains only free blocks, so skip printing it - bl += DUMP_BYTES_PER_LINE - 1; - continue; - } } - #endif // print header for new line of blocks - printf("\n%04x: ", (uint)bl); + #if EXTENSIVE_HEAP_PROFILING + printf("\n%05x: ", (uint)(bl * BYTES_PER_BLOCK) & 0xfffff); + #else + printf("\n%05x: ", (uint)PTR_FROM_BLOCK(bl) & 0xfffff); + #endif } int c = ' '; switch (ATB_GET_KIND(bl)) { case AT_FREE: c = '.'; break; - case AT_HEAD: c = 'h'; break; /* this prints out if the object is reachable from BSS or STACK (for unix only) case AT_HEAD: { extern char __bss_start, _end; @@ -734,7 +735,7 @@ void gc_dump_alloc_table(void) { break; } */ - /* this prints the uPy object type of the head block + /* this prints the uPy object type of the head block */ case AT_HEAD: { mp_uint_t *ptr = gc_pool_start + bl * WORDS_PER_BLOCK; if (*ptr == (mp_uint_t)&mp_type_tuple) { c = 'T'; } @@ -742,10 +743,10 @@ void gc_dump_alloc_table(void) { else if (*ptr == (mp_uint_t)&mp_type_dict) { c = 'D'; } else if (*ptr == (mp_uint_t)&mp_type_float) { c = 'F'; } else if (*ptr == (mp_uint_t)&mp_type_fun_bc) { c = 'B'; } + else if (*ptr == (mp_uint_t)&mp_type_module) { c = 'M'; } else { c = 'h'; } break; } - */ case AT_TAIL: c = 't'; break; case AT_MARK: c = 'm'; break; } @@ -40,7 +40,7 @@ void gc_collect_end(void); void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser); void gc_free(void *ptr); -mp_uint_t gc_nbytes(void *ptr); +mp_uint_t gc_nbytes(const void *ptr); void *gc_realloc(void *ptr, mp_uint_t n_bytes); typedef struct _gc_info_t { @@ -30,6 +30,7 @@ #include "mpconfig.h" #include "misc.h" #include "qstr.h" +#include "gc.h" // NOTE: we are using linear arrays to store and search for qstr's (unique strings, interned strings) // ultimately we will replace this with a static hash table of some kind @@ -220,9 +221,17 @@ void qstr_pool_info(mp_uint_t *n_pool, mp_uint_t *n_qstr, mp_uint_t *n_str_data_ *n_pool += 1; *n_qstr += pool->len; for (const byte **q = pool->qstrs, **q_top = pool->qstrs + pool->len; q < q_top; q++) { + #if MICROPY_ENABLE_GC + *n_str_data_bytes += gc_nbytes(*q); // this counts actual bytes used in heap + #else *n_str_data_bytes += Q_GET_ALLOC(*q); + #endif } + #if MICROPY_ENABLE_GC + *n_total_bytes += gc_nbytes(pool); // this counts actual bytes used in heap + #else *n_total_bytes += sizeof(qstr_pool_t) + sizeof(qstr) * pool->alloc; + #endif } *n_total_bytes += *n_str_data_bytes; } diff --git a/unix/main.c b/unix/main.c index bb65e67c8d..3c0a877673 100644 --- a/unix/main.c +++ b/unix/main.c @@ -226,16 +226,20 @@ int usage(char **argv) { } #if MICROPY_MEM_STATS -STATIC mp_obj_t mem_info(void) { +STATIC mp_obj_t mem_info(mp_uint_t n_args, const mp_obj_t *args) { printf("mem: total=" UINT_FMT ", current=" UINT_FMT ", peak=" UINT_FMT "\n", m_get_total_bytes_allocated(), m_get_current_bytes_allocated(), m_get_peak_bytes_allocated()); printf("stack: " UINT_FMT "\n", mp_stack_usage()); #if MICROPY_ENABLE_GC gc_dump_info(); + if (n_args == 1) { + // arg given means dump gc allocation table + gc_dump_alloc_table(); + } #endif return mp_const_none; } -STATIC MP_DEFINE_CONST_FUN_OBJ_0(mem_info_obj, mem_info); +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mem_info_obj, 0, 1, mem_info); #endif STATIC mp_obj_t qstr_info(void) { |