From b3149099a17d392289db9699b5b5d83444d25173 Mon Sep 17 00:00:00 2001 From: Nathan Ringo Date: Thu, 28 Nov 2024 22:33:47 -0600 Subject: Prevent 3DS hangs. --- src/gc.h | 9 +++++- src/gc/sms.c | 36 ++++++++++++++++++---- src/platform/3ds.c | 88 ++++++++++++++++++++++++++---------------------------- 3 files changed, 81 insertions(+), 52 deletions(-) (limited to 'src') diff --git a/src/gc.h b/src/gc.h index 8acaacc..af18323 100644 --- a/src/gc.h +++ b/src/gc.h @@ -4,7 +4,14 @@ #include "value.h" void gc_init(void); -void gc_collect(void); + +enum gc_collect_reason { + GC_COLLECT_MANUAL, + GC_COLLECT_LIMIT, + GC_COLLECT_OOM, +}; + +void gc_collect(enum gc_collect_reason); struct object; diff --git a/src/gc/sms.c b/src/gc/sms.c index a2ab18e..eb76dab 100644 --- a/src/gc/sms.c +++ b/src/gc/sms.c @@ -50,6 +50,9 @@ static const struct object_header *hdrc(const void *ptr) { return &((const struct object_header *)ptr)[-1]; } +static size_t collect_amount[5] = {0}; +static size_t collect_amount_i = 0; + void gc_init(void) {} static void gc_mark(const struct value initial_value) { @@ -213,15 +216,38 @@ static void gc_sweep(void) { } } -void gc_collect(void) { - fprintf(stderr, "gc_collect()... "); +static const char *string_of_gc_collect_reason(enum gc_collect_reason reason) { + switch (reason) { + case GC_COLLECT_MANUAL: + return "GC_COLLECT_MANUAL"; + case GC_COLLECT_LIMIT: + return "GC_COLLECT_LIMIT"; + case GC_COLLECT_OOM: + return "GC_COLLECT_OOM"; + default: + return "???"; + } +} + +void gc_collect(enum gc_collect_reason reason) { + debugf("gc_collect(%s)... ", string_of_gc_collect_reason(reason)); for (size_t i = 0; i < root_stack_depth; i++) gc_mark(*root_stack[i]); const size_t before = live_bytes; gc_sweep(); const size_t after = live_bytes; fprintf(stderr, "collected %zu bytes\n", before - after); - assume(live_bytes < limit_bytes); + + collect_amount[collect_amount_i++] = before - after; + const size_t collect_amount_count = + sizeof(collect_amount) / sizeof(collect_amount[0]); + collect_amount_i %= collect_amount_count; + size_t i; + for (i = 0; i < collect_amount_count; i++) + if (collect_amount[i] > before / 50) + break; + if (i == collect_amount_count) + todo("OOM: GC was not productive"); } struct object *gc_alloc(size_t value_slot_count, size_t untraced_slot_count) { @@ -232,10 +258,10 @@ struct object *gc_alloc(size_t value_slot_count, size_t untraced_slot_count) { sizeof(struct object_header) + (value_slot_count + untraced_slot_count) * sizeof(uintptr_t); if ((live_bytes += total_bytes) >= limit_bytes) - gc_collect(); + gc_collect(GC_COLLECT_LIMIT); struct object_header *header = malloc(total_bytes); if (!header) { - gc_collect(); + gc_collect(GC_COLLECT_OOM); header = malloc(total_bytes); if (!header) todo("OOM"); diff --git a/src/platform/3ds.c b/src/platform/3ds.c index 5566121..56d2fa8 100644 --- a/src/platform/3ds.c +++ b/src/platform/3ds.c @@ -46,51 +46,6 @@ noreturn void panic_end(void) { exit(1); } -static void gc_test(void) { - gc_debug(); - - const struct value ZERO = {.bits = (0 << 2) | TAG_FIXNUM}; - - struct object *values = gc_alloc(64, 0); - struct object *value_slot_counts = gc_alloc(64, 0); - gc_root_push(&values); - gc_root_push(&value_slot_counts); - - for (size_t i = 0; i < 10000000; i++) { - if ((rand() & 0b11) == 0) { - size_t value_slot_count = rand() & 63; - if (!value_slot_count) - value_slot_count = 1; - size_t untraced_slot_count = rand() & 63; - struct value value = - alloc_builtin_object(ZERO, value_slot_count, untraced_slot_count); - size_t i = rand() % 63; - gc_write_value_slot(values, i, value); - gc_write_value_slot(value_slot_counts, i, - integer_of_int(value_slot_count)); - } else { - size_t i = rand() & 63; - struct value value = gc_read_value_slot(values, i); - struct value value_slot_count_value = - gc_read_value_slot(value_slot_counts, i); - if (!value.bits) - continue; - assume(get_tag(value) == TAG_BUILTIN_OBJECT); - assume(get_tag(value_slot_count_value) == TAG_FIXNUM); - struct object *obj = untag_ptr(value); - intptr_t value_slot_count = untag_fixnum(value_slot_count_value); - size_t j = rand() % value_slot_count; - size_t k = rand() % 63; - gc_write_value_slot(obj, j, gc_read_value_slot(values, k)); - } - } - - gc_root_pop(); - gc_root_pop(); - - gc_debug(); -} - int main(int argc, char **argv) { gfxInit(GSP_BGR8_OES, GSP_BGR8_OES, false); @@ -111,6 +66,13 @@ int main(int argc, char **argv) { printf("\x1b[29;16HPress Start to exit.\n"); // Main loop + const struct value ZERO = {.bits = (0 << 2) | TAG_FIXNUM}; + + struct object *values = gc_alloc(64, 0); + struct object *value_slot_counts = gc_alloc(64, 0); + gc_root_push(&values); + gc_root_push(&value_slot_counts); + bool gc_test = false; while (aptMainLoop()) { // Scan all the inputs. This should be done once for each frame hidScanInput(); @@ -122,12 +84,45 @@ int main(int argc, char **argv) { if (kDown & KEY_START) break; // break in order to return to hbmenu if (kDown & KEY_A) - gc_test(); + gc_test = true; circlePosition pos; hidCircleRead(&pos); printf("\x1b[0;0H\x1b[K(%" PRId16 ", %" PRId16 ")\n", pos.dx, pos.dy); + if (gc_test) { + for (size_t j = 0; j < 1000; j++) { + if ((rand() & 0b11) == 0) { + size_t value_slot_count = rand() & 7; + if (!value_slot_count) + value_slot_count = 1; + size_t untraced_slot_count = rand() & 7; + struct value value = + alloc_builtin_object(ZERO, value_slot_count, untraced_slot_count); + size_t i = rand() % 63; + gc_write_value_slot(values, i, value); + gc_write_value_slot(value_slot_counts, i, + integer_of_int(value_slot_count)); + } else { + size_t i = rand() & 63; + struct value value = gc_read_value_slot(values, i); + struct value value_slot_count_value = + gc_read_value_slot(value_slot_counts, i); + if (!value.bits) + continue; + assume(get_tag(value) == TAG_BUILTIN_OBJECT); + assume(get_tag(value_slot_count_value) == TAG_FIXNUM); + struct object *obj = untag_ptr(value); + intptr_t value_slot_count = untag_fixnum(value_slot_count_value); + size_t j = rand() % value_slot_count; + size_t k = rand() % 63; + gc_write_value_slot(obj, j, gc_read_value_slot(values, k)); + } + } + gc_debug(); + } + + /* // Get the bottom screen's frame buffer u16 w, h; u8 *fb = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &w, &h); @@ -143,6 +138,7 @@ int main(int argc, char **argv) { // Flush and swap framebuffers gfxFlushBuffers(); gfxSwapBuffers(); + */ // Wait for VBlank gspWaitForVBlank(); -- cgit v1.2.3