Skip to content

Commit 9453f1a

Browse files
[ci skip] WIP
Co-Authored-By: Matt Valentine-House <31869+eightbitraptor@users.noreply.github.com>
1 parent 5d8aaf7 commit 9453f1a

2 files changed

Lines changed: 36 additions & 21 deletions

File tree

gc.c

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ struct heap_page {
835835
struct heap_page *free_next;
836836
RVALUE *start;
837837
RVALUE *freelist;
838+
RVALUE *freelist_tail;
838839
struct list_node page_node;
839840

840841
bits_t wb_unprotected_bits[HEAP_PAGE_BITMAP_LIMIT];
@@ -1658,14 +1659,16 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj
16581659
RVALUE *p = (RVALUE *)obj;
16591660
asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false);
16601661

1661-
if (page->freelist) {
1662-
page->freelist->as.free.prev = p;
1663-
}
1664-
16651662
p->as.free.flags = 0;
1666-
p->as.free.prev = NULL;
1667-
p->as.free.next = page->freelist;
1668-
page->freelist = p;
1663+
if (!page->freelist) {
1664+
page->freelist = p;
1665+
}
1666+
if (page->freelist_tail) {
1667+
page->freelist_tail->as.free.next = p;
1668+
}
1669+
p->as.free.prev = page->freelist_tail;
1670+
p->as.free.next = NULL;
1671+
page->freelist_tail = p;
16691672
asan_poison_memory_region(&page->freelist, sizeof(RVALUE*));
16701673

16711674
if (RGENGC_CHECK_MODE &&
@@ -1969,12 +1972,15 @@ heap_increment(rb_objspace_t *objspace, rb_heap_t *heap)
19691972
gc_report(1, objspace, "heap_increment: heap_pages_sorted_length: %d, heap_pages_inc: %d, heap->total_pages: %d\n",
19701973
(int)heap_pages_sorted_length, (int)heap_allocatable_pages, (int)heap->total_pages);
19711974

1975+
printf("heap_increment: heap_allocatable_pages: %d\n", heap_allocatable_pages);
1976+
19721977
GC_ASSERT(heap_allocatable_pages + heap_eden->total_pages <= heap_pages_sorted_length);
19731978
GC_ASSERT(heap_allocated_pages <= heap_pages_sorted_length);
19741979

19751980
heap_assign_page(objspace, heap);
19761981
return TRUE;
19771982
}
1983+
printf("HEAP ALLOCATABLE PAGES NONE\n");
19781984
return FALSE;
19791985
}
19801986

@@ -2014,6 +2020,7 @@ heap_get_freeobj_from_next_freepage(rb_objspace_t *objspace, rb_heap_t *heap)
20142020
asan_unpoison_memory_region(&page->freelist, sizeof(RVALUE*), false);
20152021
p = page->freelist;
20162022
page->freelist = NULL;
2023+
page->freelist_tail = NULL;
20172024
asan_poison_memory_region(&page->freelist, sizeof(RVALUE*));
20182025
page->free_slots = 0;
20192026
asan_unpoison_object((VALUE)p, true);
@@ -2033,18 +2040,17 @@ remove_obj_from_freelist(rb_heap_t *heap, VALUE obj)
20332040
prev->as.free.next = next;
20342041
}
20352042

2036-
if (p == heap->freelist) {
2037-
GC_ASSERT(prev == NULL);
2038-
heap->freelist = next;
2043+
if (next) {
2044+
next->as.free.prev = prev;
20392045
}
20402046

2041-
if (p == GET_HEAP_PAGE(p)->freelist) {
2047+
if (p == heap->freelist) {
20422048
GC_ASSERT(prev == NULL);
2043-
GET_HEAP_PAGE(p)->freelist = next;
2049+
heap->freelist = next;
20442050
}
20452051

2046-
if (next) {
2047-
next->as.free.prev = prev;
2052+
if (p == GET_HEAP_PAGE(p)->freelist || p == GET_HEAP_PAGE(p)->freelist_tail) { // ?
2053+
rb_bug("NOPE");
20482054
}
20492055
}
20502056

@@ -2702,6 +2708,8 @@ obj_free_object_id(rb_objspace_t *objspace, VALUE obj)
27022708
static int
27032709
obj_free(rb_objspace_t *objspace, VALUE obj)
27042710
{
2711+
GC_ASSERT(BUILTIN_TYPE(obj) != T_GARBAGE);
2712+
27052713
RB_DEBUG_COUNTER_INC(obj_free);
27062714

27072715
gc_event_hook(objspace, RUBY_INTERNAL_EVENT_FREEOBJ, obj);
@@ -4189,6 +4197,7 @@ type_sym(size_t type)
41894197
COUNT_TYPE(T_ICLASS);
41904198
COUNT_TYPE(T_ZOMBIE);
41914199
COUNT_TYPE(T_MOVED);
4200+
COUNT_TYPE(T_GARBAGE);
41924201
#undef COUNT_TYPE
41934202
default: return SIZET2NUM(type); break;
41944203
}
@@ -4235,6 +4244,7 @@ count_objects(int argc, VALUE *argv, VALUE os)
42354244
rb_objspace_t *objspace = &rb_objspace;
42364245
size_t counts[T_MASK+1];
42374246
size_t freed = 0;
4247+
size_t garbage = 0;
42384248
size_t total = 0;
42394249
size_t i;
42404250
VALUE hash = Qnil;
@@ -4270,7 +4280,12 @@ count_objects(int argc, VALUE *argv, VALUE os)
42704280
asan_poison_object(vp);
42714281
}
42724282

4273-
p += obj_slot_stride((VALUE)p);
4283+
if (BUILTIN_TYPE(p) == T_GARBAGE) {
4284+
garbage += p->as.garbage.length;
4285+
p += p->as.garbage.length;
4286+
} else {
4287+
p++;
4288+
}
42744289
}
42754290
total += page->total_slots;
42764291
}
@@ -4282,6 +4297,7 @@ count_objects(int argc, VALUE *argv, VALUE os)
42824297
rb_hash_stlike_foreach(hash, set_zero, hash);
42834298
}
42844299
rb_hash_aset(hash, ID2SYM(rb_intern("TOTAL")), SIZET2NUM(total));
4300+
rb_hash_aset(hash, ID2SYM(rb_intern("GARBAGE")), SIZET2NUM(garbage));
42854301
rb_hash_aset(hash, ID2SYM(rb_intern("FREE")), SIZET2NUM(freed));
42864302

42874303
for (i = 0; i <= T_MASK; i++) {
@@ -4398,11 +4414,6 @@ gc_page_sweep(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *sweep_
43984414
heap_page_add_freeobj(objspace, sweep_page, vp);
43994415
gc_report(3, objspace, "page_sweep: %s is added to freelist\n", obj_info(vp));
44004416

4401-
// Demo freeing garbage slots - remove me later
4402-
if (NUM_IN_PAGE(p + 1) < GET_PAGE_HEADER(p)->page->total_slots &&
4403-
BUILTIN_TYPE(p + 1) == T_GARBAGE) {
4404-
freed_slots += gc_free_garbage(objspace, p + 1);
4405-
}
44064417

44074418
freed_objects++;
44084419
freed_slots++;
@@ -6619,6 +6630,10 @@ gc_marks_finish(rb_objspace_t *objspace)
66196630
/* decide full GC is needed or not */
66206631
rb_heap_t *heap = heap_eden;
66216632
size_t total_slots = heap_allocatable_pages * HEAP_PAGE_OBJ_LIMIT + heap->total_slots;
6633+
// FIXME: number of free slots (i.e. swept slots) is not equal to total slots - marked slots (this does not account for garbage slots).
6634+
// This causes the number of free slots to seem much larger than there actually are, so `heap_extend_pages` does not add more pages.
6635+
// When no more pages are added, GC is kicked off much more frequently which causes a lot of slowdown.
6636+
// Solution idea: keep track of number of free & garbage slots we encounter during sweeping.
66226637
size_t sweep_slots = total_slots - objspace->marked_slots; /* will be swept slots */
66236638
size_t max_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_max_ratio);
66246639
size_t min_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_min_ratio);

test/ruby/test_gc.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def test_stat
9898
# repeat same methods invocation for cache object creation.
9999
GC.stat(stat)
100100
ObjectSpace.count_objects(count)
101-
assert_equal(count[:TOTAL]-count[:FREE], stat[:heap_live_objects])
101+
assert_equal(count[:TOTAL]-count[:FREE]-count[:GARBAGE], stat[:heap_live_objects])
102102
assert_equal(count[:FREE], stat[:heap_free_slots])
103103

104104
# measure again without GC.start

0 commit comments

Comments
 (0)