diff options
| author | Scott Shawcroft <scott.shawcroft@gmail.com> | 2016-11-22 17:32:28 -0800 |
|---|---|---|
| committer | Scott Shawcroft <scott.shawcroft@gmail.com> | 2016-11-22 17:32:28 -0800 |
| commit | ea1320bee7fbd0f895e8afe528e4b528489b2c5e (patch) | |
| tree | 8b00cb9098d92fda0e8c9d8f29fbaa247b05c9b0 /shared-module | |
| parent | cc412a80adf8ace5e5daa94be995d710727a1ead (diff) | |
Add uheap for debugging the size of objects. Still not perfect though.
Diffstat (limited to 'shared-module')
| -rw-r--r-- | shared-module/uheap/__init__.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/shared-module/uheap/__init__.c b/shared-module/uheap/__init__.c new file mode 100644 index 000000000..feb3a643a --- /dev/null +++ b/shared-module/uheap/__init__.c @@ -0,0 +1,282 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2016 Scott Shawcroft + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <stdint.h> + +#include "py/bc.h" +#include "py/binary.h" +#include "py/gc.h" +#include "py/obj.h" +#include "py/objarray.h" +#include "py/objfun.h" +#include "py/objint.h" +#include "py/objstr.h" +#include "py/objtype.h" +#include "py/runtime.h" + +#include "shared-bindings/uheap/__init__.h" + +#define VERIFY_PTR(ptr) ( \ + (void *) ptr >= (void*)MP_STATE_MEM(gc_pool_start) /* must be above start of pool */ \ + && (void *) ptr < (void*)MP_STATE_MEM(gc_pool_end) /* must be below end of pool */ \ + ) + +static void indent(uint8_t levels) { + for (int i = 0; i < levels; i++) { + mp_printf(&mp_plat_print, " "); + } +} + +static uint32_t object_size(uint8_t indent_level, mp_obj_t obj); + +static uint32_t int_size(uint8_t indent_level, mp_obj_t obj) { + if (MP_OBJ_IS_SMALL_INT(obj)) { + return sizeof(mp_obj_t); + } + if (!VERIFY_PTR(obj)) { + return 0; + } + #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_MPZ + mp_obj_int_t* i = MP_OBJ_TO_PTR(obj); + return sizeof(mp_obj_int_t) + i->mpz.len * sizeof(mpz_dig_t); + #else + return sizeof(mp_obj_int_t); + #endif +} + +static uint32_t string_size(uint8_t indent_level, mp_obj_t obj) { + if (MP_OBJ_IS_QSTR(obj)) { + qstr qs = MP_OBJ_QSTR_VALUE(obj); + const char* s = qstr_str(qs); + if (!VERIFY_PTR(s)) { + return 0; + } + indent(indent_level); + mp_printf(&mp_plat_print, "%s\n", s); + return qstr_len(qs); + } else { // MP_OBJ_IS_TYPE(o, &mp_type_str) + mp_obj_str_t* s = MP_OBJ_TO_PTR(obj); + return sizeof(mp_obj_str_t) + s->len * sizeof(const byte); + } +} + +static uint32_t map_size(uint8_t indent_level, const mp_map_t *map) { + uint32_t total_size = 0; + for (int i = 0; i < map->used; i++) { + uint32_t this_size = sizeof(mp_map_elem_t); + indent(indent_level); + if (map->table[i].key != NULL) { + mp_print_str(&mp_plat_print, "key: "); + mp_obj_print_helper(&mp_plat_print, map->table[i].key, PRINT_STR); + mp_print_str(&mp_plat_print, "\n"); + } else { + mp_print_str(&mp_plat_print, "null key\n"); + } + this_size += object_size(indent_level + 1, map->table[i].key); + this_size += object_size(indent_level + 1, map->table[i].value); + + indent(indent_level); + mp_printf(&mp_plat_print, "Entry size: %u\n\n", this_size); + total_size += this_size; + } + + total_size += sizeof(mp_map_elem_t) * (map->alloc - map->used); + return total_size; +} + +static uint32_t dict_size(uint8_t indent_level, mp_obj_dict_t *dict) { + uint32_t total_size = sizeof(mp_obj_dict_t); + + indent(indent_level); + mp_printf(&mp_plat_print, "Dictionary @%x\n", dict); + + total_size += map_size(indent_level, &dict->map); + + return total_size; +} + +static uint32_t function_size(uint8_t indent_level, mp_obj_t obj) { + //indent(indent_level); + //mp_print_str(&mp_plat_print, "function\n"); + if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_0)) { + return 0; + } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_1)) { + return 0; + } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_2)) { + return 0; + } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_3)) { + return 0; + } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_builtin_var)) { + return 0; + } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_bc)) { + mp_obj_fun_bc_t* fn = MP_OBJ_TO_PTR(obj); + uint32_t total_size = gc_nbytes(fn->bytecode) + gc_nbytes(fn->const_table); + #if MICROPY_DEBUG_PRINTERS + mp_printf(&mp_plat_print, "BYTECODE START\n"); + mp_bytecode_print(fn, fn->bytecode, gc_nbytes(fn->bytecode), fn->const_table); + mp_printf(&mp_plat_print, "BYTECODE END\n"); + #endif + return total_size; + #if MICROPY_EMIT_NATIVE + } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_native)) { + return 0; + #endif + #if MICROPY_EMIT_NATIVE + } else if (MP_OBJ_IS_TYPE(obj, &mp_obj_fun_viper_t)) { + return 0; + #endif + #if MICROPY_EMIT_THUMB + } else if (MP_OBJ_IS_TYPE(obj, &mp_type_fun_asm)) { + return 0; + #endif + } + return 0; +} + +static uint32_t array_size(uint8_t indent_level, mp_obj_array_t *array) { + uint32_t total_size = sizeof(mp_obj_array_t); + + int typecode_size = mp_binary_get_size('@', array->typecode, NULL); + total_size += typecode_size * (array->free + array->len); + indent(indent_level); + mp_printf(&mp_plat_print, "Array of size: %u\n\n", (array->free + array->len)); + + return total_size; +} + +static uint32_t type_size(uint8_t indent_level, mp_obj_type_t *type) { + uint32_t total_size = sizeof(mp_obj_type_t); + + // mp_obj_base_t base; + // qstr name; + //total_size += string_size(indent_level, MP_OBJ_TO_PTR(type->name)); + // mp_print_fun_t print; + // mp_make_new_fun_t make_new; // to make an instance of the type + // + // mp_call_fun_t call; + // mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported + // mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported + // + // // implements load, store and delete attribute + // // + // // dest[0] = MP_OBJ_NULL means load + // // return: for fail, do nothing + // // for attr, dest[0] = value + // // for method, dest[0] = method, dest[1] = self + // // + // // dest[0,1] = {MP_OBJ_SENTINEL, MP_OBJ_NULL} means delete + // // dest[0,1] = {MP_OBJ_SENTINEL, object} means store + // // return: for fail, do nothing + // // for success set dest[0] = MP_OBJ_NULL + // mp_attr_fun_t attr; + // + // mp_subscr_fun_t subscr; // implements load, store, delete subscripting + // // value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store + // // can return MP_OBJ_NULL if op not supported + // + // mp_fun_1_t getiter; // corresponds to __iter__ special method + // mp_fun_1_t iternext; // may return MP_OBJ_STOP_ITERATION as an optimisation instead of raising StopIteration() (with no args) + // + // mp_buffer_p_t buffer_p; + // // One of disjoint protocols (interfaces), like mp_stream_p_t, etc. + // const void *protocol; + // + // // these are for dynamically created types (classes) + // struct _mp_obj_tuple_t *bases_tuple; + // struct _mp_obj_dict_t *locals_dict; + if (type->locals_dict != NULL) { + total_size += dict_size(indent_level, type->locals_dict); + } + + indent(indent_level); + mp_printf(&mp_plat_print, "TYPE\n"); + return total_size; +} + + +static uint32_t instance_size(uint8_t indent_level, mp_obj_instance_t *instance) { + uint32_t total_size = sizeof(mp_obj_instance_t); + + total_size += map_size(indent_level, &instance->members); + + return total_size; +} + +static uint32_t module_size(uint8_t indent_level, mp_obj_module_t *module) { + uint32_t total_size = sizeof(mp_obj_module_t); + + indent(indent_level); + mp_printf(&mp_plat_print, ".globals\n"); + + total_size += dict_size(indent_level + 1, module->globals); + + indent(indent_level); + mp_printf(&mp_plat_print, "Module size: %u\n", total_size); + return total_size; +} + +static uint32_t object_size(uint8_t indent_level, mp_obj_t obj) { + if (obj == NULL) { + return 0; + } + if (MP_OBJ_IS_INT(obj)) { + return int_size(indent_level, MP_OBJ_TO_PTR(obj)); + } else if (MP_OBJ_IS_STR(obj)) { + return string_size(indent_level, MP_OBJ_TO_PTR(obj)); + } else if (MP_OBJ_IS_FUN(obj)) { + return function_size(indent_level, MP_OBJ_TO_PTR(obj)); + } + if (!VERIFY_PTR(obj)) { + //indent(indent_level); + //mp_printf(&mp_plat_print, "In ROM\n"); + return 0; + } + mp_obj_t type = MP_OBJ_FROM_PTR(mp_obj_get_type(obj)); + + if (type == &mp_type_module) { + return module_size(indent_level, MP_OBJ_TO_PTR(obj)); + } else if (type == &mp_type_dict) { + return dict_size(indent_level, MP_OBJ_TO_PTR(obj)); + } else if (type == &mp_type_type) { + return type_size(indent_level, MP_OBJ_TO_PTR(obj)); + } else if (type == &mp_type_bytearray || type == &mp_type_array) { + return array_size(indent_level, MP_OBJ_TO_PTR(obj)); + } else if (MP_OBJ_IS_OBJ(obj) && VERIFY_PTR(type)) { + return instance_size(indent_level, MP_OBJ_TO_PTR(obj)); + } + + indent(indent_level); + mp_printf(&mp_plat_print, "unknown type %x\n", type); + return 0; +} + +uint32_t shared_module_uheap_info(mp_obj_t obj) { + if (!VERIFY_PTR(obj)) { + mp_printf(&mp_plat_print, "Object not on heap.\n"); + return 0; + } + return object_size(0, obj); +} |
