Skip to content

py/gc: Support multiple heaps (version 3). #8526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions ports/unix/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -464,8 +464,22 @@ MP_NOINLINE int main_(int argc, char **argv) {
pre_process_options(argc, argv);

#if MICROPY_ENABLE_GC
#if !MICROPY_GC_MULTIHEAP
char *heap = malloc(heap_size);
gc_init(heap, heap + heap_size);
#else
assert(MICROPY_GC_N_HEAPS > 0);
char *heaps[MICROPY_GC_N_HEAPS];
long multi_heap_size = heap_size / MICROPY_GC_N_HEAPS;
for (size_t i = 0; i < MICROPY_GC_N_HEAPS; i++) {
heaps[i] = malloc(multi_heap_size);
if (i == 0) {
gc_init(heaps[i], heaps[i] + multi_heap_size);
} else {
gc_add(heaps[i], heaps[i] + multi_heap_size);
}
}
#endif
#endif

#if MICROPY_ENABLE_PYSTACK
Expand Down Expand Up @@ -716,7 +730,13 @@ MP_NOINLINE int main_(int argc, char **argv) {
#if MICROPY_ENABLE_GC && !defined(NDEBUG)
// We don't really need to free memory since we are about to exit the
// process, but doing so helps to find memory leaks.
#if !MICROPY_GC_MULTIHEAP
free(heap);
#else
for (size_t i = 0; i < MICROPY_GC_N_HEAPS; i++) {
free(heaps[i]);
}
#endif
#endif

// printf("total bytes = %d\n", m_get_total_bytes_allocated());
Expand Down
4 changes: 4 additions & 0 deletions ports/unix/mpconfigport.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@
#define MICROPY_EMIT_ARM (1)
#endif
#define MICROPY_ENABLE_GC (1)
// Number of heaps to assign if MICROPY_GC_MULTIHEAP=1
#ifndef MICROPY_GC_N_HEAPS
#define MICROPY_GC_N_HEAPS (1)
#endif
#define MICROPY_MALLOC_USES_ALLOCATED_SIZE (1)
#define MICROPY_MEM_STATS (1)
#define MICROPY_DEBUG_PRINTERS (1)
Expand Down
2 changes: 2 additions & 0 deletions ports/unix/variants/coverage/mpconfigvariant.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@
#define MICROPY_PY_UCRYPTOLIB (1)
#define MICROPY_PY_UCRYPTOLIB_CTR (1)
#define MICROPY_PY_MICROPYTHON_HEAP_LOCKED (1)
#define MICROPY_GC_MULTIHEAP (1)
#define MICROPY_GC_N_HEAPS (4)
797 changes: 495 additions & 302 deletions py/gc.c

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions py/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@

void gc_init(void *start, void *end);

// Used to add additional heaps when multiple heaps are enabled.
void gc_add(void *start, void *end);

// These lock/unlock functions can be nested.
// They can be used to prevent the GC from allocating/freeing.
void gc_lock(void);
Expand Down
5 changes: 5 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@
#define MICROPY_GC_ALLOC_THRESHOLD (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif

// Support adding more memory to the heap.
#ifndef MICROPY_GC_MULTIHEAP
#define MICROPY_GC_MULTIHEAP (0)
#endif

// Number of bytes to allocate initially when creating new chunks to store
// interned string data. Smaller numbers lead to more chunks being needed
// and more wastage at the end of the chunk. Larger numbers lead to wasted
Expand Down
34 changes: 26 additions & 8 deletions py/mpstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,11 @@ typedef struct _mp_sched_item_t {
mp_obj_t arg;
} mp_sched_item_t;

// This structure hold information about the memory allocation system.
typedef struct _mp_state_mem_t {
#if MICROPY_MEM_STATS
size_t total_bytes_allocated;
size_t current_bytes_allocated;
size_t peak_bytes_allocated;
// This structure holds information about a single contiguous area of
// memory reserved for the memory manager.
typedef struct _mp_state_mem_area_t {
#if MICROPY_GC_MULTIHEAP
struct _mp_state_mem_area_t *next;
#endif

byte *gc_alloc_table_start;
Expand All @@ -88,8 +87,25 @@ typedef struct _mp_state_mem_t {
byte *gc_pool_start;
byte *gc_pool_end;

size_t gc_last_free_atb_index;
} mp_state_mem_area_t;

// This structure hold information about the memory allocation system.
typedef struct _mp_state_mem_t {
#if MICROPY_MEM_STATS
size_t total_bytes_allocated;
size_t current_bytes_allocated;
size_t peak_bytes_allocated;
#endif

mp_state_mem_area_t area;

int gc_stack_overflow;
MICROPY_GC_STACK_ENTRY_TYPE gc_stack[MICROPY_ALLOC_GC_STACK_SIZE];
MICROPY_GC_STACK_ENTRY_TYPE gc_block_stack[MICROPY_ALLOC_GC_STACK_SIZE];
#if MICROPY_GC_MULTIHEAP
// Array that that track area for each block on the stack.
mp_state_mem_area_t *gc_area_stack[MICROPY_ALLOC_GC_STACK_SIZE];
#endif

// This variable controls auto garbage collection. If set to 0 then the
// GC won't automatically run when gc_alloc can't find enough blocks. But
Expand All @@ -101,7 +117,9 @@ typedef struct _mp_state_mem_t {
size_t gc_alloc_threshold;
#endif

size_t gc_last_free_atb_index;
#if MICROPY_GC_MULTIHEAP
mp_state_mem_area_t *gc_last_free_area;
#endif

#if MICROPY_PY_GC_COLLECT_RETVAL
size_t gc_collected;
Expand Down