Measure and report maximum stack usage. (#175)
Add max stack usage tracking, visible via debug module ustack. Add separate cpp flag for enabling modules: MICROPY_DEBUG_MODULES
This commit is contained in:
parent
af1ede930b
commit
f91493c97e
@ -128,10 +128,10 @@ CFLAGS_CORTEX_M0 = \
|
|||||||
CFLAGS = $(INC) -Wall -Werror -std=gnu11 -nostdlib $(CFLAGS_CORTEX_M0) $(CFLAGS_MOD) $(COPT)
|
CFLAGS = $(INC) -Wall -Werror -std=gnu11 -nostdlib $(CFLAGS_CORTEX_M0) $(CFLAGS_MOD) $(COPT)
|
||||||
|
|
||||||
#Debugging/Optimization
|
#Debugging/Optimization
|
||||||
# TODO(tannewt): Figure out what NDEBUG does. Adding it to the debug build
|
|
||||||
# reduces code size pretty dramatically.
|
|
||||||
ifeq ($(DEBUG), 1)
|
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
|
else
|
||||||
CFLAGS += -Os -DNDEBUG -flto
|
CFLAGS += -Os -DNDEBUG -flto
|
||||||
endif
|
endif
|
||||||
@ -279,6 +279,7 @@ SRC_SHARED_MODULE = \
|
|||||||
random/__init__.c \
|
random/__init__.c \
|
||||||
storage/__init__.c \
|
storage/__init__.c \
|
||||||
uheap/__init__.c \
|
uheap/__init__.c \
|
||||||
|
ustack/__init__.c
|
||||||
|
|
||||||
SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \
|
SRC_SHARED_MODULE_EXPANDED = $(addprefix shared-bindings/, $(SRC_SHARED_MODULE)) \
|
||||||
$(addprefix shared-module/, $(SRC_SHARED_MODULE))
|
$(addprefix shared-module/, $(SRC_SHARED_MODULE))
|
||||||
|
@ -581,6 +581,13 @@ int main(void) {
|
|||||||
mp_stack_ctrl_init();
|
mp_stack_ctrl_init();
|
||||||
mp_stack_set_limit((char*)&_estack - (char*)&_ebss - 1024);
|
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();
|
init_flash_fs();
|
||||||
|
|
||||||
// Reset everything and prep MicroPython to run boot.py.
|
// Reset everything and prep MicroPython to run boot.py.
|
||||||
|
@ -105,6 +105,11 @@
|
|||||||
|
|
||||||
#define MICROPY_STACK_CHECK (1)
|
#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
|
// This port is intended to be 32-bit, but unfortunately, int32_t for
|
||||||
// different targets may be defined in different ways - either as int
|
// different targets may be defined in different ways - either as int
|
||||||
// or as long. This requires different printf formatting specifiers
|
// 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 time_module;
|
||||||
extern const struct _mp_obj_module_t neopixel_write_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 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 samd_module;
|
||||||
extern const struct _mp_obj_module_t touchio_module;
|
extern const struct _mp_obj_module_t touchio_module;
|
||||||
extern const struct _mp_obj_module_t usb_hid_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
|
EXTRA_BUILTIN_MODULES
|
||||||
|
|
||||||
#define MICROPY_PORT_BUILTIN_DEBUG_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
|
#ifndef MICROPY_PIN_DEFS_PORT_H
|
||||||
#define MICROPY_PIN_DEFS_PORT_H "pins.h"
|
#define MICROPY_PIN_DEFS_PORT_H "pins.h"
|
||||||
|
@ -446,6 +446,11 @@
|
|||||||
#define MICROPY_STACK_CHECK (0)
|
#define MICROPY_STACK_CHECK (0)
|
||||||
#endif
|
#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
|
// Whether to have an emergency exception buffer
|
||||||
#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
#ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF
|
||||||
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
|
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0)
|
||||||
|
@ -221,6 +221,10 @@ typedef struct _mp_state_thread_t {
|
|||||||
// Stack top at the start of program
|
// Stack top at the start of program
|
||||||
char *stack_top;
|
char *stack_top;
|
||||||
|
|
||||||
|
#if MICROPY_MAX_STACK_USAGE
|
||||||
|
char* stack_bottom;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if MICROPY_STACK_CHECK
|
#if MICROPY_STACK_CHECK
|
||||||
size_t stack_limit;
|
size_t stack_limit;
|
||||||
#endif
|
#endif
|
||||||
|
@ -226,7 +226,7 @@ STATIC const mp_rom_map_elem_t mp_builtin_module_table[] = {
|
|||||||
// extra builtin modules as defined by a port
|
// extra builtin modules as defined by a port
|
||||||
MICROPY_PORT_BUILTIN_MODULES
|
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
|
, MICROPY_PORT_BUILTIN_DEBUG_MODULES
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -66,3 +66,28 @@ void mp_stack_check(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif // MICROPY_STACK_CHECK
|
#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
|
||||||
|
@ -45,4 +45,12 @@ void mp_stack_check(void);
|
|||||||
|
|
||||||
#endif
|
#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__
|
#endif // __MICROPY_INCLUDED_PY_STACKCTRL_H__
|
||||||
|
88
shared-bindings/ustack/__init__.c
Normal file
88
shared-bindings/ustack/__init__.c
Normal file
@ -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,
|
||||||
|
};
|
38
shared-bindings/ustack/__init__.h
Normal file
38
shared-bindings/ustack/__init__.h
Normal file
@ -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__
|
52
shared-module/ustack/__init__.c
Normal file
52
shared-module/ustack/__init__.c
Normal file
@ -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();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user