Skip to content

Commit c340596

Browse files
committed
Add selective collect to memory allocations
By selectively collecting an allocation, we can skip scanning many allocations for pointers because we know up front they won't have them. This helps a ton when large buffers are being used and memory is slow (PSRAM). In one Fruit Jam example GC times drop from 80+ms to ~25ms. The example uses a number of bitmaps that are now no longer scanned.
1 parent 492f6e9 commit c340596

38 files changed

+334
-184
lines changed

extmod/modasyncio.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ mp_obj_t mp_asyncio_context = MP_OBJ_NULL;
179179

180180
static mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
181181
mp_arg_check_num(n_args, n_kw, 1, 2, false);
182-
mp_obj_task_t *self = m_new_obj(mp_obj_task_t);
182+
// CIRCUITPY-CHANGE: Task holds onto core and data so collect it.
183+
mp_obj_task_t *self = m_malloc_with_collect(sizeof(mp_obj_task_t));
183184
self->pairheap.base.type = type;
184185
mp_pairheap_init_node(task_lt, &self->pairheap);
185186
self->coro = args[0];

extmod/vfs.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,8 @@ mp_obj_t mp_vfs_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args
237237
}
238238

239239
// create new object
240-
mp_vfs_mount_t *vfs = m_new_obj(mp_vfs_mount_t);
240+
// CIRCUITPY-CHANGE: Collect the mount object because it references others
241+
mp_vfs_mount_t *vfs = m_malloc_with_collect(sizeof(mp_vfs_mount_t));
241242
vfs->str = mnt_str;
242243
vfs->len = mnt_len;
243244
vfs->obj = vfs_obj;

ports/raspberrypi/boards/adafruit_fruit_jam/board.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
#define I2S_RESET_PIN_NUMBER 22
1818

19-
#if defined(DEFAULT_USB_HOST_5V_POWER)
2019
bool board_reset_pin_number(uint8_t pin_number) {
20+
#if defined(DEFAULT_USB_HOST_5V_POWER)
2121
if (pin_number == DEFAULT_USB_HOST_5V_POWER->number) {
2222
// doing this (rather than gpio_init) in this specific order ensures no
2323
// glitch if pin was already configured as a high output. gpio_init() temporarily
@@ -29,6 +29,7 @@ bool board_reset_pin_number(uint8_t pin_number) {
2929

3030
return true;
3131
}
32+
#endif
3233
// Set I2S out of reset.
3334
if (pin_number == I2S_RESET_PIN_NUMBER) {
3435
gpio_put(pin_number, 1);
@@ -39,7 +40,6 @@ bool board_reset_pin_number(uint8_t pin_number) {
3940
}
4041
return false;
4142
}
42-
#endif
4343

4444
void board_init(void) {
4545
// Reset the DAC to put it in a known state.

ports/unix/alloc.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ void mp_unix_alloc_exec(size_t min_size, void **ptr, size_t *size) {
5858
}
5959

6060
// add new link to the list of mmap'd regions
61-
mmap_region_t *rg = m_new_obj(mmap_region_t);
61+
// CIRCUITPY-CHANGE: Collect the mmap region because it points to others.
62+
mmap_region_t *rg = m_malloc_with_collect(sizeof(mmap_region_t));
6263
rg->ptr = *ptr;
6364
rg->len = min_size;
6465
rg->next = MP_STATE_VM(mmap_region_head);

ports/unix/mpconfigport.h

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ typedef long mp_off_t;
112112

113113
// Always enable GC.
114114
#define MICROPY_ENABLE_GC (1)
115+
#define MICROPY_ENABLE_SELECTIVE_COLLECT (1)
115116

116117
#if !(defined(MICROPY_GCREGS_SETJMP) || defined(__x86_64__) || defined(__i386__) || defined(__thumb2__) || defined(__thumb__) || defined(__arm__))
117118
// Fall back to setjmp() implementation for discovery of GC pointers in registers.

py/bc.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -302,14 +302,14 @@ static inline void mp_module_context_alloc_tables(mp_module_context_t *context,
302302
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
303303
size_t nq = (n_qstr * sizeof(qstr_short_t) + sizeof(mp_uint_t) - 1) / sizeof(mp_uint_t);
304304
size_t no = n_obj;
305-
mp_uint_t *mem = m_new(mp_uint_t, nq + no);
305+
mp_uint_t *mem = m_malloc_items(nq + no);
306306
context->constants.qstr_table = (qstr_short_t *)mem;
307307
context->constants.obj_table = (mp_obj_t *)(mem + nq);
308308
#else
309309
if (n_obj == 0) {
310310
context->constants.obj_table = NULL;
311311
} else {
312-
context->constants.obj_table = m_new(mp_obj_t, n_obj);
312+
context->constants.obj_table = m_malloc_items(n_obj);
313313
}
314314
#endif
315315
}

py/circuitpy_mpconfig.h

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ extern void common_hal_mcu_enable_interrupts(void);
6262
#define MICROPY_EMIT_X64 (0)
6363
#define MICROPY_ENABLE_DOC_STRING (0)
6464
#define MICROPY_ENABLE_FINALISER (1)
65+
#define MICROPY_ENABLE_SELECTIVE_COLLECT (1)
6566
#define MICROPY_ENABLE_GC (1)
6667
#define MICROPY_ENABLE_PYSTACK (1)
6768
#define MICROPY_TRACKED_ALLOC (CIRCUITPY_SSL_MBEDTLS)

py/compile.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ static void mp_emit_common_start_pass(mp_emit_common_t *emit, pass_kind_t pass)
221221
if (emit->ct_cur_child == 0) {
222222
emit->children = NULL;
223223
} else {
224-
emit->children = m_new0(mp_raw_code_t *, emit->ct_cur_child);
224+
// CIRCUITPY-CHANGE: Use m_malloc_helper with collect flag to support selective collection
225+
emit->children = m_malloc_helper(sizeof(mp_raw_code_t *) * (emit->ct_cur_child), M_MALLOC_ENSURE_ZEROED | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT);
225226
}
226227
}
227228
emit->ct_cur_child = 0;
@@ -3688,7 +3689,7 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool
36883689

36893690
mp_obj_t mp_compile(mp_parse_tree_t *parse_tree, qstr source_file, bool is_repl) {
36903691
mp_compiled_module_t cm;
3691-
cm.context = m_new_obj(mp_module_context_t);
3692+
cm.context = m_malloc_with_collect(sizeof(mp_module_context_t));
36923693
cm.context->module.globals = mp_globals_get();
36933694
mp_compile_to_raw_code(parse_tree, source_file, is_repl, &cm);
36943695
// return function that executes the outer module

py/emitbc.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ struct _emit_t {
7676
};
7777

7878
emit_t *emit_bc_new(mp_emit_common_t *emit_common) {
79-
emit_t *emit = m_new0(emit_t, 1);
79+
emit_t *emit = m_new_struct_with_collect(emit_t, 1);
8080
emit->emit_common = emit_common;
8181
return emit;
8282
}

py/emitglue.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ mp_uint_t mp_verbose_flag = 0;
5454
#endif
5555

5656
mp_raw_code_t *mp_emit_glue_new_raw_code(void) {
57-
mp_raw_code_t *rc = m_new0(mp_raw_code_t, 1);
57+
// CIRCUITPY-CHANGE: Use m_malloc_helper with collect flag because raw code children are allocations too.
58+
mp_raw_code_t *rc = m_malloc_helper(sizeof(mp_raw_code_t), M_MALLOC_ENSURE_ZEROED | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT);
5859
rc->kind = MP_CODE_RESERVED;
5960
#if MICROPY_PY_SYS_SETTRACE
6061
rc->line_of_definition = 0;

0 commit comments

Comments
 (0)