summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan Ringo <nathan@remexre.com>2024-11-28 22:33:47 -0600
committerNathan Ringo <nathan@remexre.com>2024-11-28 22:33:47 -0600
commitb3149099a17d392289db9699b5b5d83444d25173 (patch)
tree24e84d2ca1469bd87b4379ea2b701218d0465d8f /src
parent16e22f9cb39a254bccd20613f7c2cfef75ae15a7 (diff)
Prevent 3DS hangs.
Diffstat (limited to 'src')
-rw-r--r--src/gc.h9
-rw-r--r--src/gc/sms.c36
-rw-r--r--src/platform/3ds.c88
3 files changed, 81 insertions, 52 deletions
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();