Skip to content

Commit c6d3e54

Browse files
committed
Helper code to debug selective collect
1 parent 09b23ca commit c6d3e54

4 files changed

Lines changed: 66 additions & 6 deletions

File tree

main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,7 @@ int __attribute__((used)) main(void) {
11301130
}
11311131

11321132
void gc_collect(void) {
1133+
uint32_t start_time = supervisor_ticks_ms32();
11331134
gc_collect_start();
11341135

11351136
mp_uint_t regs[10];
@@ -1171,6 +1172,9 @@ void gc_collect(void) {
11711172
// range.
11721173
gc_collect_root((void **)sp, ((mp_uint_t)port_stack_get_top() - sp) / sizeof(mp_uint_t));
11731174
gc_collect_end();
1175+
uint32_t end_time = supervisor_ticks_ms32();
1176+
uint32_t duration = end_time - start_time;
1177+
console_uart_printf("GC took %dms\r\n", duration);
11741178
}
11751179

11761180
// Ports may provide an implementation of this function if it is needed

ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939

4040
#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO47)
4141

42-
// #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO44)
43-
// #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO45)
42+
#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO44)
43+
#define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO45)
4444

45-
// #define CIRCUITPY_DEBUG_TINYUSB 0
45+
#define CIRCUITPY_DEBUG_TINYUSB 1
4646

4747
#define CIRCUITPY_SAVES_PARTITION_SIZE (2 * 1024 * 1024)

py/gc.c

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,24 @@ static inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) {
471471
#endif
472472
#endif
473473

474+
// Use this to debug a specific pointer that should have been collected and break on the particular
475+
// allocation that returns the pointer.
476+
// Set debug_collect to true to perform the subtree scan for everything and print out any blocks that
477+
// have pointers that would have been collected. Then, set the block's ptr to target_ptr to print out
478+
// the allocation that returns the pointer. Set target_count to the number of allocations to skip
479+
// before breaking on the allocation (so you can get a backtrace.) This approach only works if the
480+
// code is deterministic. You may want to turn off USB host to make it so.
481+
//
482+
// Otherwise, you can inspect word 0 of the block to likely get the Python object type of the memory
483+
// that should have been collected. Compare that pointer to those in the matching firmware.elf.map.
484+
static bool debug_collect = false;
485+
static void *target_ptr = (void *)0x1101b8d0;
486+
487+
#if MICROPY_ENABLE_SELECTIVE_COLLECT
488+
static uint32_t target_count = 100;
489+
static uint32_t current_count = 0;
490+
#endif
491+
474492
// Take the given block as the topmost block on the stack. Check all it's
475493
// children: mark the unmarked child blocks and put those newly marked
476494
// blocks on the stack. When all children have been checked, pop off the
@@ -506,12 +524,14 @@ static void MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_mark_subtree)(size_t block)
506524
#endif
507525

508526
// Only scan the block's children if it's not a leaf
509-
if (should_scan) {
527+
if (debug_collect || should_scan) {
510528
// check this block's children
511529
void **ptrs = (void **)PTR_FROM_BLOCK(area, block);
512530
for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof(void *); i > 0; i--, ptrs++) {
513531
MICROPY_GC_HOOK_LOOP(i);
514532
void *ptr = *ptrs;
533+
void **block_ptr = ptrs;
534+
bool found_collect_candidate = false;
515535
// If this is a heap pointer that hasn't been marked, mark it and push
516536
// it's children to the stack.
517537
#if MICROPY_GC_SPLIT_HEAP
@@ -526,6 +546,19 @@ static void MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_mark_subtree)(size_t block)
526546
}
527547
mp_state_mem_area_t *ptr_area = area;
528548
#endif
549+
if (!should_scan) {
550+
if (!found_collect_candidate) {
551+
console_uart_printf("should have scanned %p\n", block_ptr);
552+
// This is often the pointer to the Python type in RAM.
553+
// It is helpful to know the allocation path that should use mp_obj_malloc.
554+
console_uart_printf(" [0] = %p\n", block_ptr[0]);
555+
console_uart_printf(" [1] = %p\n", block_ptr[1]);
556+
}
557+
console_uart_printf(" [%d] = %p\n", i, ptr);
558+
found_collect_candidate = true;
559+
ptr = NULL;
560+
continue;
561+
}
529562
size_t ptr_block = BLOCK_FROM_PTR(ptr_area, ptr);
530563
if (ATB_GET_KIND(ptr_area, ptr_block) != AT_HEAD) {
531564
// This block is already marked.
@@ -925,7 +958,7 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {
925958

926959
// CIRCUITPY-CHANGE
927960
#if CIRCUITPY_DEBUG
928-
gc_dump_alloc_table(&mp_plat_print);
961+
// gc_dump_alloc_table(&mp_plat_print);
929962
#endif
930963
return NULL;
931964
}
@@ -1027,6 +1060,22 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {
10271060
memorymonitor_track_allocation(end_block - start_block + 1);
10281061
#endif
10291062

1063+
#if MICROPY_ENABLE_SELECTIVE_COLLECT
1064+
if (debug_collect) {
1065+
if (ret_ptr == target_ptr) {
1066+
if (current_count == target_count && do_not_collect) {
1067+
asm ("bkpt");
1068+
}
1069+
console_uart_printf("target_count = %d\n", current_count);
1070+
current_count++;
1071+
}
1072+
1073+
if (target_ptr != NULL && ret_ptr == target_ptr) {
1074+
console_uart_printf("gc_alloc(%d, %01x) = %p\n", n_bytes, alloc_flags, ret_ptr);
1075+
}
1076+
}
1077+
#endif
1078+
10301079
return ret_ptr;
10311080
}
10321081

@@ -1060,6 +1109,10 @@ void gc_free(void *ptr) {
10601109
return;
10611110
}
10621111

1112+
if (debug_collect && target_ptr != NULL && ptr == target_ptr) {
1113+
console_uart_printf("gc_free(%p)\n", ptr);
1114+
}
1115+
10631116
// get the GC block number corresponding to this pointer
10641117
mp_state_mem_area_t *area;
10651118
#if MICROPY_GC_SPLIT_HEAP
@@ -1345,6 +1398,9 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
13451398
// can't resize inplace; try to find a new contiguous chain
13461399
void *ptr_out = gc_alloc(n_bytes, alloc_flags);
13471400

1401+
if (debug_collect && target_ptr != NULL && (ptr_out == target_ptr || ptr_in == target_ptr)) {
1402+
console_uart_printf("gc_realloc: moving %p -> %p, %d -> %d bytes\n", ptr_in, ptr_out, n_blocks * BYTES_PER_BLOCK, n_bytes);
1403+
}
13481404
// check that the alloc succeeded
13491405
if (ptr_out == NULL) {
13501406
return NULL;

supervisor/shared/serial.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) {
406406
#endif
407407

408408
#if CIRCUITPY_CONSOLE_UART
409-
length_sent = console_uart_write(text, length);
409+
// length_sent = console_uart_write(text, length);
410410
#endif
411411

412412
#if CIRCUITPY_SERIAL_BLE

0 commit comments

Comments
 (0)