46
46
#define DEBUG_printf (...) (void)0
47
47
#endif
48
48
49
+ // make this 1 to dump the heap each time it changes
50
+ #define EXTENSIVE_HEAP_PROFILING (0)
51
+
49
52
#define WORDS_PER_BLOCK (4)
50
53
#define BYTES_PER_BLOCK (WORDS_PER_BLOCK * BYTES_PER_WORD)
51
54
#define STACK_SIZE (64) // tunable; minimum is 1
@@ -405,7 +408,8 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
405
408
// Set last free ATB index to block after last block we found, for start of
406
409
// next scan. To reduce fragmentation, we only do this if we were looking
407
410
// for a single free block, which guarantees that there are no free blocks
408
- // before this one.
411
+ // before this one. Also, whenever we free or shink a block we must check
412
+ // if this index needs adjusting (see gc_realloc and gc_free).
409
413
if (n_free == 1 ) {
410
414
gc_last_free_atb_index = (i + 1 ) / BLOCKS_PER_ATB ;
411
415
}
@@ -439,6 +443,10 @@ void *gc_alloc(mp_uint_t n_bytes, bool has_finaliser) {
439
443
}
440
444
#endif
441
445
446
+ #if EXTENSIVE_HEAP_PROFILING
447
+ gc_dump_alloc_table ();
448
+ #endif
449
+
442
450
return ret_ptr ;
443
451
}
444
452
@@ -465,11 +473,20 @@ void gc_free(void *ptr_in) {
465
473
if (VERIFY_PTR (ptr )) {
466
474
mp_uint_t block = BLOCK_FROM_PTR (ptr );
467
475
if (ATB_GET_KIND (block ) == AT_HEAD ) {
476
+ // set the last_free pointer to this block if it's earlier in the heap
477
+ if (block / BLOCKS_PER_ATB < gc_last_free_atb_index ) {
478
+ gc_last_free_atb_index = block / BLOCKS_PER_ATB ;
479
+ }
480
+
468
481
// free head and all of its tail blocks
469
482
do {
470
483
ATB_ANY_TO_FREE (block );
471
484
block += 1 ;
472
485
} while (ATB_GET_KIND (block ) == AT_TAIL );
486
+
487
+ #if EXTENSIVE_HEAP_PROFILING
488
+ gc_dump_alloc_table ();
489
+ #endif
473
490
}
474
491
}
475
492
}
@@ -581,6 +598,16 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
581
598
for (mp_uint_t bl = block + new_blocks ; ATB_GET_KIND (bl ) == AT_TAIL ; bl ++ ) {
582
599
ATB_ANY_TO_FREE (bl );
583
600
}
601
+
602
+ // set the last_free pointer to end of this block if it's earlier in the heap
603
+ if ((block + new_blocks ) / BLOCKS_PER_ATB < gc_last_free_atb_index ) {
604
+ gc_last_free_atb_index = (block + new_blocks ) / BLOCKS_PER_ATB ;
605
+ }
606
+
607
+ #if EXTENSIVE_HEAP_PROFILING
608
+ gc_dump_alloc_table ();
609
+ #endif
610
+
584
611
return ptr_in ;
585
612
}
586
613
@@ -595,6 +622,10 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
595
622
// zero out the additional bytes of the newly allocated blocks (see comment above in gc_alloc)
596
623
memset ((byte * )ptr_in + n_bytes , 0 , new_blocks * BYTES_PER_BLOCK - n_bytes );
597
624
625
+ #if EXTENSIVE_HEAP_PROFILING
626
+ gc_dump_alloc_table ();
627
+ #endif
628
+
598
629
return ptr_in ;
599
630
}
600
631
@@ -628,9 +659,34 @@ void gc_dump_info() {
628
659
}
629
660
630
661
void gc_dump_alloc_table (void ) {
662
+ static const mp_uint_t DUMP_BYTES_PER_LINE = 64 ;
663
+ #if !EXTENSIVE_HEAP_PROFILING
664
+ // When comparing heap output we don't want to print the starting
665
+ // pointer of the heap because it changes from run to run.
631
666
printf ("GC memory layout; from %p:" , gc_pool_start );
667
+ #endif
632
668
for (mp_uint_t bl = 0 ; bl < gc_alloc_table_byte_len * BLOCKS_PER_ATB ; bl ++ ) {
633
- if (bl % 64 == 0 ) {
669
+ if (bl % DUMP_BYTES_PER_LINE == 0 ) {
670
+ // a new line of blocks
671
+ #if EXTENSIVE_HEAP_PROFILING
672
+ {
673
+ // check if this line contains only free blocks
674
+ bool only_free_blocks = true;
675
+ for (mp_uint_t bl2 = bl ; bl2 < gc_alloc_table_byte_len * BLOCKS_PER_ATB && bl2 < bl + DUMP_BYTES_PER_LINE ; bl2 ++ ) {
676
+ if (ATB_GET_KIND (bl2 ) != AT_FREE ) {
677
+
678
+ only_free_blocks = false;
679
+ break ;
680
+ }
681
+ }
682
+ if (only_free_blocks ) {
683
+ // line contains only free blocks, so skip printing it
684
+ bl += DUMP_BYTES_PER_LINE - 1 ;
685
+ continue ;
686
+ }
687
+ }
688
+ #endif
689
+ // print header for new line of blocks
634
690
printf ("\n%04x: " , (uint )bl );
635
691
}
636
692
int c = ' ' ;
0 commit comments