summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Shawcroft <scott.shawcroft@gmail.com>2016-11-22 17:32:28 -0800
committerScott Shawcroft <scott.shawcroft@gmail.com>2016-11-22 17:32:28 -0800
commitea1320bee7fbd0f895e8afe528e4b528489b2c5e (patch)
tree8b00cb9098d92fda0e8c9d8f29fbaa247b05c9b0
parentcc412a80adf8ace5e5daa94be995d710727a1ead (diff)
Add uheap for debugging the size of objects. Still not perfect though.
-rw-r--r--atmel-samd/Makefile12
-rw-r--r--atmel-samd/mpconfigport.h4
-rw-r--r--lib/utils/printf.c2
-rw-r--r--shared-bindings/bitbangio/__init__.c1
-rw-r--r--shared-bindings/uheap/__init__.c63
-rw-r--r--shared-bindings/uheap/__init__.h34
-rw-r--r--shared-module/uheap/__init__.c282
7 files changed, 394 insertions, 4 deletions
diff --git a/atmel-samd/Makefile b/atmel-samd/Makefile
index a83c71e4b..1b38503fe 100644
--- a/atmel-samd/Makefile
+++ b/atmel-samd/Makefile
@@ -224,12 +224,22 @@ SRC_BINDINGS = \
SRC_BINDINGS_EXPANDED = $(addprefix shared-bindings/, $(SRC_BINDINGS)) \
$(addprefix common-hal/, $(SRC_BINDINGS))
+SRC_SHARED_MODULE = \
+ bitbangio/__init__.c \
+ bitbangio/I2C.c \
+ bitbangio/SPI.c \
+ uheap/__init__.c \
+
+SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \
+ $(addprefix shared-module/, $(SRC_SHARED_MODULE))
+
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_ASF:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(STM_SRC_C:.c=.o))
OBJ += $(addprefix $(BUILD)/, $(SRC_BINDINGS_EXPANDED:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o))
-SRC_QSTR += $(SRC_C) $(SRC_BINDINGS_EXPANDED) $(STM_SRC_C)
+SRC_QSTR += $(SRC_C) $(SRC_BINDINGS_EXPANDED) $(SRC_SHARED_MODULE_EXPANDED) $(STM_SRC_C)
all: $(BUILD)/firmware.bin
diff --git a/atmel-samd/mpconfigport.h b/atmel-samd/mpconfigport.h
index 225992c51..c6dbdad3c 100644
--- a/atmel-samd/mpconfigport.h
+++ b/atmel-samd/mpconfigport.h
@@ -118,6 +118,7 @@ extern const struct _mp_obj_module_t board_module;
extern const struct _mp_obj_module_t uos_module;
extern const struct _mp_obj_module_t time_module;
extern const struct _mp_obj_module_t neopixel_write_module;
+extern const struct _mp_obj_module_t uheap_module;
#define MICROPY_PORT_BUILTIN_MODULES \
{ MP_OBJ_NEW_QSTR(MP_QSTR_microcontroller), (mp_obj_t)&microcontroller_module }, \
@@ -125,7 +126,8 @@ extern const struct _mp_obj_module_t neopixel_write_module;
{ MP_OBJ_NEW_QSTR(MP_QSTR_board), (mp_obj_t)&board_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_uos), (mp_obj_t)&uos_module }, \
{ MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&time_module }, \
- { MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module } \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_neopixel_write),(mp_obj_t)&neopixel_write_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uheap),(mp_obj_t)&uheap_module } \
// board specific definitions
#include "mpconfigboard.h"
diff --git a/lib/utils/printf.c b/lib/utils/printf.c
index 303edfcca..dab8baf2e 100644
--- a/lib/utils/printf.c
+++ b/lib/utils/printf.c
@@ -60,13 +60,13 @@ int vprintf(const char *fmt, va_list ap) {
}
#if MICROPY_DEBUG_PRINTERS
+extern const mp_print_t MICROPY_DEBUG_PRINTER_DEST;
int DEBUG_printf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
#ifndef MICROPY_DEBUG_PRINTER_DEST
#define MICROPY_DEBUG_PRINTER_DEST mp_plat_print
#endif
- extern const mp_print_t MICROPY_DEBUG_PRINTER_DEST;
int ret = mp_vprintf(&MICROPY_DEBUG_PRINTER_DEST, fmt, ap);
va_end(ap);
return ret;
diff --git a/shared-bindings/bitbangio/__init__.c b/shared-bindings/bitbangio/__init__.c
index 69e39a2e5..6d864fd18 100644
--- a/shared-bindings/bitbangio/__init__.c
+++ b/shared-bindings/bitbangio/__init__.c
@@ -28,7 +28,6 @@
// dependency is nativeio.DigitalInOut.
#include <stdint.h>
-#include <stdio.h>
#include "py/obj.h"
#include "py/runtime.h"
diff --git a/shared-bindings/uheap/__init__.c b/shared-bindings/uheap/__init__.c
new file mode 100644
index 000000000..55050cfa3
--- /dev/null
+++ b/shared-bindings/uheap/__init__.c
@@ -0,0 +1,63 @@
+/*
+ * 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/obj.h"
+#include "py/runtime.h"
+
+#include "shared-bindings/uheap/__init__.h"
+
+//| :mod:`uheap` --- Heap size analysis
+//| ================================================================
+//|
+//| .. module:: uheap
+//| :synopsis: Heap size analysis
+//|
+
+//| .. method:: info(object)
+//|
+//| Prints memory debugging info for the given object and returns the
+//| estimated size.
+//|
+STATIC mp_obj_t uheap_info(mp_obj_t obj) {
+ uint32_t size = shared_module_uheap_info(obj);
+
+ return MP_OBJ_NEW_SMALL_INT(size);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(uheap_info_obj, uheap_info);
+
+STATIC const mp_rom_map_elem_t uheap_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_uheap) },
+ { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&uheap_info_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(uheap_module_globals, uheap_module_globals_table);
+
+const mp_obj_module_t uheap_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&uheap_module_globals,
+};
diff --git a/shared-bindings/uheap/__init__.h b/shared-bindings/uheap/__init__.h
new file mode 100644
index 000000000..79dc0999b
--- /dev/null
+++ b/shared-bindings/uheap/__init__.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#ifndef __MICROPY_INCLUDED_SHARED_BINDINGS_UHEAP___INIT___H__
+#define __MICROPY_INCLUDED_SHARED_BINDINGS_UHEAP___INIT___H__
+
+#include "py/obj.h"
+
+extern uint32_t shared_module_uheap_info(mp_obj_t obj);
+
+#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_UHEAP___INIT___H__
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);
+}