summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--atmel-samd/Makefile7
-rw-r--r--atmel-samd/main.c7
-rw-r--r--atmel-samd/mpconfigport.h9
-rw-r--r--py/mpconfig.h5
-rw-r--r--py/mpstate.h4
-rw-r--r--py/objmodule.c2
-rw-r--r--py/stackctrl.c25
-rw-r--r--py/stackctrl.h8
-rw-r--r--shared-bindings/ustack/__init__.c88
-rw-r--r--shared-bindings/ustack/__init__.h38
-rw-r--r--shared-module/ustack/__init__.c52
11 files changed, 240 insertions, 5 deletions
diff --git a/atmel-samd/Makefile b/atmel-samd/Makefile
index cc3e0b399..ed5981d09 100644
--- a/atmel-samd/Makefile
+++ b/atmel-samd/Makefile
@@ -128,10 +128,10 @@ CFLAGS_CORTEX_M0 = \
CFLAGS = $(INC) -Wall -Werror -std=gnu11 -nostdlib $(CFLAGS_CORTEX_M0) $(CFLAGS_MOD) $(COPT)
#Debugging/Optimization
-# TODO(tannewt): Figure out what NDEBUG does. Adding it to the debug build
-# reduces code size pretty dramatically.
ifeq ($(DEBUG), 1)
-CFLAGS += -Os -ggdb -DNDEBUG -DENABLE_MICRO_TRACE_BUFFER
+# NDEBUG disables assert() statements. This reduces code size pretty dramatically, per tannewt.
+# Turn on Python modules useful for debugging (e.g. uheap, ustack).
+CFLAGS += -Os -ggdb -DNDEBUG -DENABLE_MICRO_TRACE_BUFFER -DMICROPY_DEBUG_MODULES
else
CFLAGS += -Os -DNDEBUG -flto
endif
@@ -279,6 +279,7 @@ SRC_SHARED_MODULE = \
random/__init__.c \
storage/__init__.c \
uheap/__init__.c \
+ ustack/__init__.c
SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \
$(addprefix shared-module/, $(SRC_SHARED_MODULE))
diff --git a/atmel-samd/main.c b/atmel-samd/main.c
index 64b7d8c7f..842dae451 100644
--- a/atmel-samd/main.c
+++ b/atmel-samd/main.c
@@ -581,6 +581,13 @@ int main(void) {
mp_stack_ctrl_init();
mp_stack_set_limit((char*)&_estack - (char*)&_ebss - 1024);
+
+#if MICROPY_MAX_STACK_USAGE
+ // _ezero (same as _ebss) is an int, so start 4 bytes above it.
+ mp_stack_set_bottom(&_ezero + 1);
+ mp_stack_fill_with_sentinel();
+#endif
+
init_flash_fs();
// Reset everything and prep MicroPython to run boot.py.
diff --git a/atmel-samd/mpconfigport.h b/atmel-samd/mpconfigport.h
index dd62a9f05..7755959ea 100644
--- a/atmel-samd/mpconfigport.h
+++ b/atmel-samd/mpconfigport.h
@@ -105,6 +105,11 @@
#define MICROPY_STACK_CHECK (1)
+// Track stack usage on a debug build. Expose results via ustack module.
+#ifdef MICROPY_DEBUG_MODULES
+#define MICROPY_MAX_STACK_USAGE (1)
+#endif
+
// This port is intended to be 32-bit, but unfortunately, int32_t for
// different targets may be defined in different ways - either as int
// or as long. This requires different printf formatting specifiers
@@ -145,6 +150,7 @@ extern const struct _mp_obj_module_t storage_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;
+extern const struct _mp_obj_module_t ustack_module;
extern const struct _mp_obj_module_t samd_module;
extern const struct _mp_obj_module_t touchio_module;
extern const struct _mp_obj_module_t usb_hid_module;
@@ -188,7 +194,8 @@ extern const struct _mp_obj_module_t usb_hid_module;
EXTRA_BUILTIN_MODULES
#define MICROPY_PORT_BUILTIN_DEBUG_MODULES \
- { MP_OBJ_NEW_QSTR(MP_QSTR_uheap),(mp_obj_t)&uheap_module }
+ { MP_OBJ_NEW_QSTR(MP_QSTR_uheap),(mp_obj_t)&uheap_module }, \
+ { MP_OBJ_NEW_QSTR(MP_QSTR_ustack),(mp_obj_t)&ustack_module }
#ifndef MICROPY_PIN_DEFS_PORT_H
#define MICROPY_PIN_DEFS_PORT_H "pins.h"
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 39e773183..14c5af3e7 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -446,6 +446,11 @@
#define MICROPY_STACK_CHECK (0)
#endif
+// Whether to measure maximum stack excursion
+#ifndef MICROPY_MAX_STACK_USAGE
+#define MICROPY_MAX_STACK_USAGE (0)
+#endif
+
// Whether to have an emergency exception buffer
#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
diff --git a/py/mpstate.h b/py/mpstate.h
index 30785775b..0b195a096 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -221,6 +221,10 @@ typedef struct _mp_state_thread_t {
// Stack top at the start of program
char *stack_top;
+ #if MICROPY_MAX_STACK_USAGE
+ char* stack_bottom;
+ #endif
+
#if MICROPY_STACK_CHECK
size_t stack_limit;
#endif
diff --git a/py/objmodule.c b/py/objmodule.c
index 9171b2b22..1b9b9d65e 100644
--- a/py/objmodule.c
+++ b/py/objmodule.c
@@ -226,7 +226,7 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
// extra builtin modules as defined by a port
MICROPY_PORT_BUILTIN_MODULES
-#if defined(DEBUG) && defined(MICROPY_PORT_BUILTIN_DEBUG_MODULES)
+#if defined(MICROPY_DEBUG_MODULES) && defined(MICROPY_PORT_BUILTIN_DEBUG_MODULES)
, MICROPY_PORT_BUILTIN_DEBUG_MODULES
#endif
};
diff --git a/py/stackctrl.c b/py/stackctrl.c
index d9969b56c..202ae3d48 100644
--- a/py/stackctrl.c
+++ b/py/stackctrl.c
@@ -66,3 +66,28 @@ void mp_stack_check(void) {
}
#endif // MICROPY_STACK_CHECK
+
+#if MICROPY_MAX_STACK_USAGE
+
+// Fill stack space with this unusual value.
+const char MP_MAX_STACK_USAGE_SENTINEL_BYTE = 0xEE;
+
+// Record absolute bottom (logical limit) of stack.
+void mp_stack_set_bottom(void* stack_bottom) {
+ MP_STATE_THREAD(stack_bottom) = stack_bottom;
+}
+
+// Fill stack space down toward the stack limit with a known unusual value.
+void mp_stack_fill_with_sentinel(void) {
+ // Force routine to not be inlined. Better guarantee than MP_NOINLINE for -flto.
+ __asm volatile ("");
+ volatile char* volatile p;
+ // Start filling stack just below the last variable in the current stack frame, which is p.
+ // Continue until we've hit the bottom of the stack (lowest address, logical "ceiling" of stack).
+ p = (char *) (&p - 1);
+ while(p >= MP_STATE_THREAD(stack_bottom)) {
+ *p-- = MP_MAX_STACK_USAGE_SENTINEL_BYTE;
+ }
+}
+
+#endif // MICROPY_MAX_STACK_USAGE
diff --git a/py/stackctrl.h b/py/stackctrl.h
index e915f5000..2fb3784c5 100644
--- a/py/stackctrl.h
+++ b/py/stackctrl.h
@@ -45,4 +45,12 @@ void mp_stack_check(void);
#endif
+#if MICROPY_MAX_STACK_USAGE
+
+const char MP_MAX_STACK_USAGE_SENTINEL_BYTE;
+void mp_stack_set_bottom(void* stack_bottom);
+void mp_stack_fill_with_sentinel(void);
+
+#endif
+
#endif // __MICROPY_INCLUDED_PY_STACKCTRL_H__
diff --git a/shared-bindings/ustack/__init__.c b/shared-bindings/ustack/__init__.c
new file mode 100644
index 000000000..c4391c132
--- /dev/null
+++ b/shared-bindings/ustack/__init__.c
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Dan Halbert for Adafruit Industries
+ *
+ * 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/ustack/__init__.h"
+
+//| :mod:`ustack` --- Stack information and analysis
+//| ========================================================
+//|
+//| .. module:: ustack
+//| :synopsis: stack information functions
+//|
+
+#if MICROPY_MAX_STACK_USAGE
+//| .. method:: max_stack_usage()
+//|
+//| Return the maximum excursion of the stack so far.
+//|
+STATIC mp_obj_t max_stack_usage(void) {
+ return MP_OBJ_NEW_SMALL_INT(shared_module_ustack_max_stack_usage());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(max_stack_usage_obj, max_stack_usage);
+
+#endif // MICROPY_MAX_STACK_USAGE
+
+//| .. method:: stack_size()
+//|
+//| Return the size of the entire stack.
+//| Same as in micropython.mem_info(), but returns a value instead
+//| of just printing it.
+//|
+STATIC mp_obj_t stack_size(void) {
+ return MP_OBJ_NEW_SMALL_INT(shared_module_ustack_stack_size());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(stack_size_obj, stack_size);
+
+//| .. method:: stack_usage()
+//|
+//| Return how much stack is currently in use.
+//| Same as micropython.stack_use(); duplicated here for convenience.
+//|
+STATIC mp_obj_t stack_usage(void) {
+ return MP_OBJ_NEW_SMALL_INT(shared_module_ustack_stack_usage());
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(stack_usage_obj, stack_usage);
+
+STATIC const mp_rom_map_elem_t ustack_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ustack) },
+ #if MICROPY_MAX_STACK_USAGE
+ { MP_ROM_QSTR(MP_QSTR_max_stack_usage), MP_ROM_PTR(&max_stack_usage_obj) },
+ #endif
+ { MP_ROM_QSTR(MP_QSTR_stack_size), MP_ROM_PTR(&stack_size_obj) },
+ { MP_ROM_QSTR(MP_QSTR_stack_usage), MP_ROM_PTR(&stack_usage_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(ustack_module_globals, ustack_module_globals_table);
+
+const mp_obj_module_t ustack_module = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&ustack_module_globals,
+};
diff --git a/shared-bindings/ustack/__init__.h b/shared-bindings/ustack/__init__.h
new file mode 100644
index 000000000..d4f3d50a8
--- /dev/null
+++ b/shared-bindings/ustack/__init__.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Dan Halbert for Adafruit Industries
+ *
+ * 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_USTACK___INIT___H__
+#define __MICROPY_INCLUDED_SHARED_BINDINGS_USTACK___INIT___H__
+
+#include "py/obj.h"
+
+#if MICROPY_MAX_STACK_USAGE
+extern uint32_t shared_module_ustack_max_stack_usage(void);
+#endif
+extern uint32_t shared_module_ustack_stack_size(void);
+extern uint32_t shared_module_ustack_stack_usage(void);
+
+#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_USTACK___INIT___H__
diff --git a/shared-module/ustack/__init__.c b/shared-module/ustack/__init__.c
new file mode 100644
index 000000000..947f81f8e
--- /dev/null
+++ b/shared-module/ustack/__init__.c
@@ -0,0 +1,52 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Dan Halbert
+ *
+ * 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/mpstate.h"
+#include "py/stackctrl.h"
+
+#include "shared-bindings/ustack/__init__.h"
+
+#if MICROPY_MAX_STACK_USAGE
+uint32_t shared_module_ustack_max_stack_usage(void) {
+ // Start at stack limit and move up.
+ // Untouched stack was filled with a sentinel value.
+ // Stop at first non-sentinel byte.
+ char* p = MP_STATE_THREAD(stack_bottom);
+ while (*p++ == MP_MAX_STACK_USAGE_SENTINEL_BYTE) { }
+ return MP_STATE_THREAD(stack_top) - p;
+}
+#endif
+
+uint32_t shared_module_ustack_stack_size() {
+ return MP_STATE_THREAD(stack_limit);
+}
+
+uint32_t shared_module_ustack_stack_usage() {
+ return mp_stack_usage();
+}
+