Skip to content

Commit 3b51b3e

Browse files
committed
stmhal: Collect all root pointers together in 1 place.
A GC in stmhal port now only scans true root pointers, not entire BSS. This reduces base GC time from 1700ms to 900ms.
1 parent 7a0636e commit 3b51b3e

16 files changed

Lines changed: 142 additions & 138 deletions

File tree

esp8266/mpconfigport.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ extern const struct _mp_obj_module_t pyb_module;
6161
#define MICROPY_PORT_BUILTIN_MODULES \
6262
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
6363

64+
#define MP_STATE_PORT MP_STATE_VM
65+
66+
#define MICROPY_PORT_ROOT_POINTERS \
67+
const char *readline_hist[8];
68+
6469
// We need to provide a declaration/definition of alloca()
6570
#include <alloca.h>
6671

stmhal/extint.c

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,6 @@
2828
#include <stddef.h>
2929
#include <string.h>
3030

31-
#include <stm32f4xx_hal.h>
32-
3331
#include "py/nlr.h"
3432
#include "py/runtime.h"
3533
#include "py/gc.h"
@@ -101,13 +99,7 @@ typedef struct {
10199
mp_int_t line;
102100
} extint_obj_t;
103101

104-
typedef struct {
105-
mp_obj_t callback_obj;
106-
void *param;
107-
uint32_t mode;
108-
} extint_vector_t;
109-
110-
STATIC extint_vector_t extint_vector[EXTI_NUM_VECTORS];
102+
STATIC uint32_t pyb_extint_mode[EXTI_NUM_VECTORS];
111103

112104
#if !defined(ETH)
113105
#define ETH_WKUP_IRQn 62 // The 405 doesn't have ETH, but we want a value to put in our table
@@ -123,10 +115,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
123115

124116
// Set override_callback_obj to true if you want to unconditionally set the
125117
// callback function.
126-
//
127-
// NOTE: param is for C callers. Python can use closure to get an object bound
128-
// with the function.
129-
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj, void *param) {
118+
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj) {
130119
const pin_obj_t *pin = NULL;
131120
uint v_line;
132121

@@ -159,22 +148,21 @@ uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t ca
159148
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid ExtInt Pull: %d", pull));
160149
}
161150

162-
extint_vector_t *v = &extint_vector[v_line];
163-
if (!override_callback_obj && v->callback_obj != mp_const_none && callback_obj != mp_const_none) {
151+
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[v_line];
152+
if (!override_callback_obj && *cb != mp_const_none && callback_obj != mp_const_none) {
164153
nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d is already in use", v_line));
165154
}
166155

167-
// We need to update callback and param atomically, so we disable the line
156+
// We need to update callback atomically, so we disable the line
168157
// before we update anything.
169158

170159
extint_disable(v_line);
171160

172-
v->callback_obj = callback_obj;
173-
v->param = param;
174-
v->mode = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
161+
*cb = callback_obj;
162+
pyb_extint_mode[v_line] = (mode & 0x00010000) ? // GPIO_MODE_IT == 0x00010000
175163
EXTI_Mode_Interrupt : EXTI_Mode_Event;
176164

177-
if (v->callback_obj != mp_const_none) {
165+
if (*cb != mp_const_none) {
178166

179167
GPIO_InitTypeDef exti;
180168
exti.Pin = pin->pin_mask;
@@ -199,7 +187,7 @@ void extint_enable(uint line) {
199187
// Since manipulating IMR/EMR is a read-modify-write, and we want this to
200188
// be atomic, we use the bit-band area to just affect the bit we're
201189
// interested in.
202-
EXTI_MODE_BB(extint_vector[line].mode, line) = 1;
190+
EXTI_MODE_BB(pyb_extint_mode[line], line) = 1;
203191
}
204192

205193
void extint_disable(uint line) {
@@ -303,7 +291,7 @@ STATIC mp_obj_t extint_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_
303291

304292
extint_obj_t *self = m_new_obj(extint_obj_t);
305293
self->base.type = type_in;
306-
self->line = extint_register(vals[0].u_obj, vals[1].u_int, vals[2].u_int, vals[3].u_obj, false, NULL);
294+
self->line = extint_register(vals[0].u_obj, vals[1].u_int, vals[2].u_int, vals[3].u_obj, false);
307295

308296
return self;
309297
}
@@ -343,30 +331,29 @@ const mp_obj_type_t extint_type = {
343331
};
344332

345333
void extint_init0(void) {
346-
for (extint_vector_t *v = extint_vector; v < &extint_vector[EXTI_NUM_VECTORS]; v++) {
347-
v->callback_obj = mp_const_none;
348-
v->param = NULL;
349-
v->mode = EXTI_Mode_Interrupt;
350-
}
334+
for (int i = 0; i < PYB_EXTI_NUM_VECTORS; i++) {
335+
MP_STATE_PORT(pyb_extint_callback)[i] = mp_const_none;
336+
pyb_extint_mode[i] = EXTI_Mode_Interrupt;
337+
}
351338
}
352339

353340
// Interrupt handler
354341
void Handle_EXTI_Irq(uint32_t line) {
355342
if (__HAL_GPIO_EXTI_GET_FLAG(1 << line)) {
356343
__HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
357344
if (line < EXTI_NUM_VECTORS) {
358-
extint_vector_t *v = &extint_vector[line];
359-
if (v->callback_obj != mp_const_none) {
345+
mp_obj_t *cb = &MP_STATE_PORT(pyb_extint_callback)[line];
346+
if (*cb != mp_const_none) {
360347
// When executing code within a handler we must lock the GC to prevent
361348
// any memory allocations. We must also catch any exceptions.
362349
gc_lock();
363350
nlr_buf_t nlr;
364351
if (nlr_push(&nlr) == 0) {
365-
mp_call_function_1(v->callback_obj, MP_OBJ_NEW_SMALL_INT(line));
352+
mp_call_function_1(*cb, MP_OBJ_NEW_SMALL_INT(line));
366353
nlr_pop();
367354
} else {
368355
// Uncaught exception; disable the callback so it doesn't run again.
369-
v->callback_obj = mp_const_none;
356+
*cb = mp_const_none;
370357
extint_disable(line);
371358
printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line);
372359
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);

stmhal/extint.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
#define EXTI_RTC_TIMESTAMP (21)
3838
#define EXTI_RTC_WAKEUP (22)
3939

40-
#define EXTI_NUM_VECTORS (23)
40+
#define EXTI_NUM_VECTORS (PYB_EXTI_NUM_VECTORS)
4141

4242
#define EXTI_MODE_INTERRUPT (offsetof(EXTI_TypeDef, IMR))
4343
#define EXTI_MODE_EVENT (offsetof(EXTI_TypeDef, EMR))
@@ -48,7 +48,7 @@
4848

4949
void extint_init0(void);
5050

51-
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj, void *param);
51+
uint extint_register(mp_obj_t pin_obj, uint32_t mode, uint32_t pull, mp_obj_t callback_obj, bool override_callback_obj);
5252

5353
void extint_enable(uint line);
5454
void extint_disable(uint line);

stmhal/gccollect.c

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,19 @@
3030
#include "py/obj.h"
3131
#include "py/gc.h"
3232
#include "gccollect.h"
33-
#include MICROPY_HAL_H
33+
#include "systick.h"
3434

3535
mp_uint_t gc_helper_get_regs_and_sp(mp_uint_t *regs);
3636

37-
// obsolete
38-
// void gc_helper_get_regs_and_clean_stack(mp_uint_t *regs, mp_uint_t heap_end);
39-
4037
void gc_collect(void) {
4138
// get current time, in case we want to time the GC
42-
uint32_t start = HAL_GetTick();
39+
#if 0
40+
uint32_t start = sys_tick_get_microseconds();
41+
#endif
4342

4443
// start the GC
4544
gc_collect_start();
4645

47-
// We need to scan everything in RAM that can hold a pointer.
48-
// The data segment is used, but should not contain pointers, so we just scan the bss.
49-
gc_collect_root((void**)&_sbss, ((uint32_t)&_ebss - (uint32_t)&_sbss) / sizeof(uint32_t));
50-
5146
// get the registers and the sp
5247
mp_uint_t regs[10];
5348
mp_uint_t sp = gc_helper_get_regs_and_sp(regs);
@@ -58,14 +53,14 @@ void gc_collect(void) {
5853
// end the GC
5954
gc_collect_end();
6055

61-
if (0) {
62-
// print GC info
63-
uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
64-
gc_info_t info;
65-
gc_info(&info);
66-
printf("GC@%lu %lums\n", start, ticks);
67-
printf(" " UINT_FMT " total\n", info.total);
68-
printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
69-
printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
70-
}
56+
#if 0
57+
// print GC info
58+
uint32_t ticks = sys_tick_get_microseconds() - start;
59+
gc_info_t info;
60+
gc_info(&info);
61+
printf("GC@%lu %lums\n", start, ticks);
62+
printf(" " UINT_FMT " total\n", info.total);
63+
printf(" " UINT_FMT " : " UINT_FMT "\n", info.used, info.free);
64+
printf(" 1=" UINT_FMT " 2=" UINT_FMT " m=" UINT_FMT "\n", info.num_1block, info.num_2block, info.max_block);
65+
#endif
7166
}

stmhal/main.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,20 +112,17 @@ void MP_WEAK __assert_func(const char *file, int line, const char *func, const c
112112
}
113113
#endif
114114

115-
STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL;
116-
STATIC mp_obj_t pyb_config_usb_mode = MP_OBJ_NULL;
117-
118115
STATIC mp_obj_t pyb_main(mp_obj_t main) {
119116
if (MP_OBJ_IS_STR(main)) {
120-
pyb_config_main = main;
117+
MP_STATE_PORT(pyb_config_main) = main;
121118
}
122119
return mp_const_none;
123120
}
124121
MP_DEFINE_CONST_FUN_OBJ_1(pyb_main_obj, pyb_main);
125122

126123
STATIC mp_obj_t pyb_usb_mode(mp_obj_t usb_mode) {
127124
if (MP_OBJ_IS_STR(usb_mode)) {
128-
pyb_config_usb_mode = usb_mode;
125+
MP_STATE_PORT(pyb_config_usb_mode) = usb_mode;
129126
}
130127
return mp_const_none;
131128
}
@@ -303,7 +300,7 @@ int main(void) {
303300
pyb_stdio_uart = pyb_uart_type.make_new((mp_obj_t)&pyb_uart_type, MP_ARRAY_SIZE(args), 0, args);
304301
}
305302
#else
306-
pyb_stdio_uart = NULL;
303+
MP_STATE_PORT(pyb_stdio_uart) = NULL;
307304
#endif
308305

309306
// Initialise low-level sub-systems. Here we need to very basic things like
@@ -444,8 +441,8 @@ int main(void) {
444441
#endif
445442

446443
// reset config variables; they should be set by boot.py
447-
pyb_config_main = MP_OBJ_NULL;
448-
pyb_config_usb_mode = MP_OBJ_NULL;
444+
MP_STATE_PORT(pyb_config_main) = MP_OBJ_NULL;
445+
MP_STATE_PORT(pyb_config_usb_mode) = MP_OBJ_NULL;
449446

450447
// run boot.py, if it exists
451448
// TODO perhaps have pyb.reboot([bootpy]) function to soft-reboot and execute custom boot.py
@@ -479,8 +476,8 @@ int main(void) {
479476
// USB device
480477
usb_device_mode_t usb_mode = USB_DEVICE_MODE_CDC_MSC;
481478
// if we are not in reset_mode==1, this config variable will always be NULL
482-
if (pyb_config_usb_mode != MP_OBJ_NULL) {
483-
if (strcmp(mp_obj_str_get_str(pyb_config_usb_mode), "CDC+HID") == 0) {
479+
if (MP_STATE_PORT(pyb_config_usb_mode) != MP_OBJ_NULL) {
480+
if (strcmp(mp_obj_str_get_str(MP_STATE_PORT(pyb_config_usb_mode)), "CDC+HID") == 0) {
484481
usb_mode = USB_DEVICE_MODE_CDC_HID;
485482
}
486483
}
@@ -509,10 +506,10 @@ int main(void) {
509506
// Run the main script from the current directory.
510507
if (reset_mode == 1 && pyexec_mode_kind == PYEXEC_MODE_FRIENDLY_REPL) {
511508
const char *main_py;
512-
if (pyb_config_main == MP_OBJ_NULL) {
509+
if (MP_STATE_PORT(pyb_config_main) == MP_OBJ_NULL) {
513510
main_py = "main.py";
514511
} else {
515-
main_py = mp_obj_str_get_str(pyb_config_main);
512+
main_py = mp_obj_str_get_str(MP_STATE_PORT(pyb_config_main));
516513
}
517514
FRESULT res = f_stat(main_py, NULL);
518515
if (res == FR_OK) {

stmhal/modpyb.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include "stm32f4xx_hal.h"
3131

32+
#include "py/mpstate.h"
3233
#include "py/nlr.h"
3334
#include "py/obj.h"
3435
#include "py/gc.h"
@@ -475,16 +476,16 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_have_cdc_obj, pyb_have_cdc);
475476
/// Get or set the UART object that the REPL is repeated on.
476477
STATIC mp_obj_t pyb_repl_uart(mp_uint_t n_args, const mp_obj_t *args) {
477478
if (n_args == 0) {
478-
if (pyb_stdio_uart == NULL) {
479+
if (MP_STATE_PORT(pyb_stdio_uart) == NULL) {
479480
return mp_const_none;
480481
} else {
481-
return pyb_stdio_uart;
482+
return MP_STATE_PORT(pyb_stdio_uart);
482483
}
483484
} else {
484485
if (args[0] == mp_const_none) {
485-
pyb_stdio_uart = NULL;
486+
MP_STATE_PORT(pyb_stdio_uart) = NULL;
486487
} else if (mp_obj_get_type(args[0]) == &pyb_uart_type) {
487-
pyb_stdio_uart = args[0];
488+
MP_STATE_PORT(pyb_stdio_uart) = args[0];
488489
} else {
489490
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "need a UART object"));
490491
}

stmhal/mpconfigport.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,34 @@ extern const struct _mp_obj_module_t mp_module_network;
122122
{ MP_OBJ_NEW_QSTR(MP_QSTR_pyb), (mp_obj_t)&pyb_module }, \
123123
{ MP_OBJ_NEW_QSTR(MP_QSTR_stm), (mp_obj_t)&stm_module }, \
124124

125+
#define PYB_EXTI_NUM_VECTORS (23)
126+
127+
#define MP_STATE_PORT MP_STATE_VM
128+
129+
#define MICROPY_PORT_ROOT_POINTERS \
130+
const char *readline_hist[8]; \
131+
\
132+
mp_obj_t mp_const_vcp_interrupt; \
133+
\
134+
mp_obj_t pyb_config_main; \
135+
mp_obj_t pyb_config_usb_mode; \
136+
\
137+
mp_obj_t pyb_switch_callback; \
138+
\
139+
mp_obj_t pin_class_mapper; \
140+
mp_obj_t pin_class_map_dict; \
141+
\
142+
mp_obj_t pyb_extint_callback[PYB_EXTI_NUM_VECTORS]; \
143+
\
144+
/* Used to do callbacks to Python code on interrupt */ \
145+
struct _pyb_timer_obj_t *pyb_timer_obj_all[14]; \
146+
\
147+
/* stdio is repeated on this UART object if it's not null */ \
148+
struct _pyb_uart_obj_t *pyb_stdio_uart; \
149+
\
150+
/* pointers to all UART objects (if they have been created) */ \
151+
struct _pyb_uart_obj_t *pyb_uart_obj_all[6]; \
152+
125153
// type definitions for the specific machine
126154

127155
#define BYTES_PER_WORD (4)

stmhal/pendsv.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131
#include "py/runtime.h"
3232
#include "pendsv.h"
3333

34-
static void *pendsv_object = NULL;
34+
// Note: this can contain point to the heap but is not traced by GC.
35+
// This is okay because we only ever set it to mp_const_vcp_interrupt
36+
// which is in the root-pointer set.
37+
STATIC void *pendsv_object;
3538

3639
void pendsv_init(void) {
3740
// set PendSV interrupt at lowest priority

0 commit comments

Comments
 (0)