Skip to content

Commit bcbbce2

Browse files
Bring back the sweep mark bit optimisation
Now that we have a reliable way of telling whether a slot is in the middle of a garbage struct we don't need to iterate over every slot in the page any more.
1 parent 136f56f commit bcbbce2

File tree

1 file changed

+58
-53
lines changed

1 file changed

+58
-53
lines changed

gc.c

Lines changed: 58 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4439,79 +4439,84 @@ gc_free_garbage(rb_objspace_t *objspace, VALUE garbage)
44394439
return length;
44404440
}
44414441

4442+
static int is_garbage_slot(VALUE obj);
4443+
44424444
static inline int
44434445
gc_page_sweep(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *sweep_page)
44444446
{
4445-
int offset, i;
4446-
int empty_slots = 0, freed_slots = 0, freed_objects = 0, final_objects = 0;
4447-
RVALUE *pstart;
4447+
int i;
4448+
int empty_slots = 0, freed_slots = 0, final_objects = 0;
4449+
RVALUE *p, *offset;
44484450
bits_t *bits, bitset;
44494451

44504452
gc_report(2, objspace, "page_sweep: start.\n");
44514453

44524454
sweep_page->flags.before_sweep = FALSE;
44534455

4454-
pstart = sweep_page->start;
4455-
offset = NUM_IN_PAGE(pstart);
4456+
p = sweep_page->start;
4457+
offset = p - NUM_IN_PAGE(p);
44564458
bits = sweep_page->mark_bits;
44574459

4458-
for (i = 0; i < sweep_page->total_slots;) {
4459-
RVALUE *p = pstart + i;
4460-
VALUE vp = (VALUE)p;
4460+
/* create guard : fill 1 out-of-range */
4461+
bits[BITMAP_INDEX(p)] |= BITMAP_BIT(p)-1;
44614462

4462-
GC_ASSERT(!RVALUE_PAGE_MARKING(sweep_page, p) || sweep_page->flags.has_remembered_objects);
4463-
4464-
bitset = (~bits[BITMAP_INDEX(p)] >> BITMAP_OFFSET(p)) & 1;
4463+
int out_of_range_bits = (NUM_IN_PAGE(p) + sweep_page->total_slots) % BITS_BITLENGTH;
4464+
if (out_of_range_bits != 0) { // sizeof(RVALUE) == 64
4465+
bits[BITMAP_INDEX(p) + sweep_page->total_slots / BITS_BITLENGTH] |= ~(((bits_t)1 << out_of_range_bits) - 1);
4466+
}
44654467

4466-
asan_unpoison_object(vp, false);
4467-
if (bitset) {
4468-
switch (BUILTIN_TYPE(vp)) {
4469-
default: /* majority case */
4470-
gc_report(2, objspace, "page_sweep: free %p\n", (void *)p);
4468+
for (i=0; i < HEAP_PAGE_BITMAP_LIMIT; i++) {
4469+
bitset = ~bits[i];
4470+
if (bitset) {
4471+
p = offset + i * BITS_BITLENGTH;
4472+
do {
4473+
VALUE vp = (VALUE)p;
4474+
asan_unpoison_object(vp, false);
4475+
if (bitset & 1) {
4476+
switch (BUILTIN_TYPE(vp)) {
4477+
default: /* majority case */
4478+
gc_report(2, objspace, "page_sweep: free %p\n", (void *)p);
44714479
#if RGENGC_CHECK_MODE
4472-
if (!is_full_marking(objspace)) {
4473-
if (RVALUE_OLD_P(vp)) rb_bug("page_sweep: old while minor GC: %s.", obj_info(p));
4474-
if (rgengc_remembered_sweep(objspace, vp)) rb_bug("page_sweep: %p - remembered.", (void *)p);
4475-
}
4476-
#endif
4477-
if (obj_free(objspace, vp)) {
4478-
final_objects++;
4479-
}
4480-
else {
4481-
(void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
4482-
heap_page_add_freeobj(objspace, sweep_page, vp);
4483-
gc_report(3, objspace, "page_sweep: %s is added to freelist\n", obj_info(vp));
4484-
4485-
freed_objects++;
4486-
freed_slots++;
4487-
asan_poison_object(vp);
4488-
}
4489-
break;
4490-
4491-
/* minor cases */
4492-
case T_GARBAGE:
4493-
case T_ZOMBIE:
4494-
/* already counted */
4495-
break;
4496-
case T_NONE:
4497-
empty_slots++; /* already freed */
4498-
break;
4499-
}
4500-
}
4501-
4502-
if (BUILTIN_TYPE((VALUE)p) == T_GARBAGE) {
4503-
i += p->as.garbage.length;
4504-
} else {
4505-
i++;
4506-
}
4480+
if (!is_full_marking(objspace)) {
4481+
if (RVALUE_OLD_P(vp)) rb_bug("page_sweep: %p - old while minor GC.", (void *)p);
4482+
if (rgengc_remembered_sweep(objspace, vp)) rb_bug("page_sweep: %p - remembered.", (void *)p);
4483+
}
4484+
#endif
4485+
if (!is_garbage_slot(vp)) {
4486+
if (obj_free(objspace, vp)) {
4487+
final_objects++;
4488+
}
4489+
else {
4490+
(void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE));
4491+
heap_page_add_freeobj(objspace, sweep_page, vp);
4492+
gc_report(3, objspace, "page_sweep: %s is added to freelist\n", obj_info(vp));
4493+
freed_slots++;
4494+
asan_poison_object(vp);
4495+
}
4496+
}
4497+
break;
4498+
4499+
/* minor cases */
4500+
case T_ZOMBIE:
4501+
/* already counted */
4502+
break;
4503+
case T_NONE:
4504+
empty_slots++; /* already freed */
4505+
break;
4506+
}
4507+
}
4508+
p++;
4509+
bitset >>= 1;
4510+
} while (bitset);
4511+
}
45074512
}
45084513

45094514
gc_setup_mark_bits(sweep_page);
45104515

45114516
#if GC_PROFILE_MORE_DETAIL
45124517
if (gc_prof_enabled(objspace)) {
45134518
gc_profile_record *record = gc_prof_record(objspace);
4514-
record->removing_objects += final_objects + freed_slots;
4519+
record->removing_objects += final_objects + freed_slots;
45154520
record->empty_objects += empty_slots;
45164521
}
45174522
#endif
@@ -4521,7 +4526,7 @@ gc_page_sweep(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *sweep_
45214526
freed_slots, empty_slots, final_objects);
45224527

45234528
sweep_page->free_slots = freed_slots + empty_slots;
4524-
objspace->profile.total_freed_objects += freed_objects;
4529+
objspace->profile.total_freed_objects += freed_slots;
45254530
heap_pages_final_objects += final_objects;
45264531
sweep_page->final_objects += final_objects;
45274532

0 commit comments

Comments
 (0)