ruby-changes:29512
From: ko1 <ko1@a...>
Date: Sat, 22 Jun 2013 15:43:43 +0900 (JST)
Subject: [ruby-changes:29512] ko1:r41564 (trunk): * gc.c (rgengc_check_shady): add new WB miss checking
ko1 2013-06-22 15:43:30 +0900 (Sat, 22 Jun 2013) New Revision: 41564 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41564 Log: * gc.c (rgengc_check_shady): add new WB miss checking on RGENGC_CHECK_MODE >= 2. (1) Save bitmaps before marking (2) Run full marking (3) On each traceable object, (a) object was not oldgen (== newly or shady object) && (b) parent object was oldgen && (c) parent object was not remembered && (d) object was not rememberd then, it should be WB miss. This idea of this checker is by Masaya Tarui <tarui@r...>. Modified files: trunk/ChangeLog trunk/gc.c Index: ChangeLog =================================================================== --- ChangeLog (revision 41563) +++ ChangeLog (revision 41564) @@ -1,3 +1,19 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Sat Jun 22 15:41:25 2013 Koichi Sasada <ko1@a...> + + * gc.c (rgengc_check_shady): add new WB miss checking + on RGENGC_CHECK_MODE >= 2. + + (1) Save bitmaps before marking + (2) Run full marking + (3) On each traceable object, + (a) object was not oldgen (== newly or shady object) && + (b) parent object was oldgen && + (c) parent object was not remembered && + (d) object was not rememberd + then, it should be WB miss. + + This idea of this checker is by Masaya Tarui <tarui@r...>. + Sat Jun 22 15:25:00 2013 Charlie Somerville <charliesome@r...> * ext/etc/etc.c (setup_passwd): revert r41560, unnecessary Index: gc.c =================================================================== --- gc.c (revision 41563) +++ gc.c (revision 41564) @@ -392,6 +392,9 @@ typedef struct rb_objspace { https://github.com/ruby/ruby/blob/trunk/gc.c#L392 size_t remembered_shady_object_limit; size_t oldgen_object_count; size_t oldgen_object_limit; +#if RGENGC_CHECK_MODE >= 2 + int have_saved_bitmaps; +#endif } rgengc; #endif /* USE_RGENGC */ } rb_objspace_t; @@ -424,6 +427,11 @@ struct heaps_slot { https://github.com/ruby/ruby/blob/trunk/gc.c#L427 #if USE_RGENGC bits_t rememberset_bits[HEAP_BITMAP_LIMIT]; bits_t oldgen_bits[HEAP_BITMAP_LIMIT]; +#if RGENGC_CHECK_MODE >= 2 + bits_t saved_mark_bits[HEAP_BITMAP_LIMIT]; + bits_t saved_rememberset_bits[HEAP_BITMAP_LIMIT]; + bits_t saved_oldgen_bits[HEAP_BITMAP_LIMIT]; +#endif #endif }; @@ -2990,33 +2998,53 @@ static void https://github.com/ruby/ruby/blob/trunk/gc.c#L2998 rgengc_check_shady(rb_objspace_t *objspace, VALUE obj) { #if USE_RGENGC - if (RGENGC_CHECK_MODE > 1) { - if (objspace->rgengc.interesting_object == obj) { - if (FIXNUM_P(objspace->rgengc.parent_object)) { - fprintf(stderr, "rgengc_check_shady: !!! %p (%s) is pointed at line %d\n", - (void *)obj, obj_type_name(obj), FIX2INT(objspace->rgengc.parent_object)); - } - else { - fprintf(stderr, "rgengc_check_shady: !!! %p (%s) is pointed by %p (%s)\n", - (void *)obj, obj_type_name(obj), - (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object)); - } +#if RGENGC_CHECK_MODE >= 2 + VALUE parent = objspace->rgengc.parent_object; + + if (objspace->rgengc.interesting_object == obj) { + /* output interesting parent->child references */ + if (FIXNUM_P(parent)) { + fprintf(stderr, "rgengc_check_shady: !!! %p (%s) is pointed at line %d\n", + (void *)obj, obj_type_name(obj), FIX2INT(parent)); + } + else { + fprintf(stderr, "rgengc_check_shady: !!! %p (%s) is pointed by %p (%s)\n", + (void *)obj, obj_type_name(obj), (void *)parent, obj_type_name(parent)); } + } - if (RGENGC_CHECK_MODE == 3) { - if (objspace->rgengc.interesting_object) { - if (FIXNUM_P(objspace->rgengc.parent_object)) { - fprintf(stderr, "rgengc_check_shady: [line %d] -> %p (%s)\n", - FIX2INT(objspace->rgengc.parent_object), (void *)obj, obj_type_name(obj)); - } - else { - fprintf(stderr, "rgengc_check_shady: %p (%s) -> %p (%s)\n", - (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object), - (void *)obj, obj_type_name(obj)); - } - } +#if RGENGC_CHECK_MODE >= 3 + /* output all parent->child references */ + if (objspace->rgengc.interesting_object) { + if (FIXNUM_P(parent)) { + fprintf(stderr, "rgengc_check_shady: [line %d] -> %p (%s)\n", + FIX2INT(parent), (void *)obj, obj_type_name(obj)); + } + else { + fprintf(stderr, "rgengc_check_shady: %p (%s) -> %p (%s)\n", + (void *)parent, obj_type_name(parent), (void *)obj, obj_type_name(obj)); } } +#endif /* RGENGC_CHECK_MODE >= 3 */ + + if (objspace->rgengc.have_saved_bitmaps) { + /* check WB sanity */ +#define SAVED_OLD(x) MARKED_IN_BITMAP(GET_HEAP_SLOT(x)->saved_oldgen_bits, (x)) +#define SAVED_REM(x) MARKED_IN_BITMAP(GET_HEAP_SLOT(x)->saved_rememberset_bits, (x)) + if (!SAVED_OLD(obj) && /* obj is young object (newly created or shady) */ + (!FIXNUM_P(parent) && SAVED_OLD(parent)) && /* parent was old */ + !SAVED_REM(parent) && /* parent was not remembered */ + !SAVED_REM(obj)) { /* obj was not remembered */ + fprintf(stderr, "rgengc_check_shady: !!! WB miss: %p (%s) -> %p (%s)\n", + (void *)parent, obj_type_name(parent), + (void *)obj, obj_type_name(obj)); + rb_bug("!!!"); + objspace->rgengc.interesting_object = obj; + } +#undef SAVED_OLD +#undef SAVED_REM + } +#endif /* RGENGC_CHECK_MODE >= 2 */ if (objspace->rgengc.parent_object_is_promoted && RVALUE_SHADY(obj) && !rgengc_remembered(objspace, obj)) { @@ -3054,7 +3082,7 @@ gc_mark_children(rb_objspace_t *objspace https://github.com/ruby/ruby/blob/trunk/gc.c#L3082 { register RVALUE *obj = RANY(ptr); -#if RGENGC_CHECK_MODE > 1 +#if RGENGC_CHECK_MODE >= 2 objspace->rgengc.parent_object = (VALUE)ptr; #endif @@ -3066,7 +3094,7 @@ gc_mark_children(rb_objspace_t *objspace https://github.com/ruby/ruby/blob/trunk/gc.c#L3094 if (!markable_object_p(objspace, ptr)) return; rgengc_check_shady(objspace, ptr); if (!gc_mark_ptr(objspace, ptr)) return; /* already marked */ -#if RGENGC_CHECK_MODE > 1 +#if RGENGC_CHECK_MODE >= 2 objspace->rgengc.parent_object = (VALUE)ptr; #endif } @@ -3475,64 +3503,112 @@ gc_marks_body(rb_objspace_t *objspace, i https://github.com/ruby/ruby/blob/trunk/gc.c#L3503 rgengc_report(1, objspace, "gc_marks_body: end (%s)\n", minor_gc ? "minor" : "major"); } -#if USE_RGENGC +#if RGENGC_CHECK_MODE >= 2 + +static void +gc_oldgen_bitmap2flag(struct heaps_slot *slot) +{ + bits_t *oldgen_bits = &slot->oldgen_bits[0]; + RVALUE *p = slot->header->start; + RVALUE *pend = p + slot->header->limit; + + while (p < pend) { + if (MARKED_IN_BITMAP(oldgen_bits, p)) FL_SET2(p, FL_OLDGEN); + else FL_UNSET2(p, FL_OLDGEN); + p++; + } +} + static bits_t * -gc_store_bitmaps(rb_objspace_t *objspace) +gc_export_bitmaps(rb_objspace_t *objspace) { - bits_t *stored_bitmaps = (bits_t *)malloc(HEAP_BITMAP_SIZE * heaps_used * 3); + bits_t *exported_bitmaps = (bits_t *)malloc(HEAP_BITMAP_SIZE * heaps_used * 3); size_t i; - if (stored_bitmaps == 0) rb_bug("gc_store_bitmaps: not enough memory to test.\n"); + if (exported_bitmaps == 0) rb_bug("gc_store_bitmaps: not enough memory to test.\n"); for (i=0; i<heaps_used; i++) { struct heaps_slot *slot = objspace->heap.sorted[i]->base; - memcpy(&stored_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT], &slot->mark_bits[0], HEAP_BITMAP_SIZE); - memcpy(&stored_bitmaps[(3*i+1)*HEAP_BITMAP_LIMIT], &slot->rememberset_bits[0], HEAP_BITMAP_SIZE); - memcpy(&stored_bitmaps[(3*i+2)*HEAP_BITMAP_LIMIT], &slot->oldgen_bits[0], HEAP_BITMAP_SIZE); + memcpy(&exported_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT], &slot->mark_bits[0], HEAP_BITMAP_SIZE); + memcpy(&exported_bitmaps[(3*i+1)*HEAP_BITMAP_LIMIT], &slot->rememberset_bits[0], HEAP_BITMAP_SIZE); + memcpy(&exported_bitmaps[(3*i+2)*HEAP_BITMAP_LIMIT], &slot->oldgen_bits[0], HEAP_BITMAP_SIZE); } - return stored_bitmaps; - } + return exported_bitmaps; +} static void -gc_restore_bitmaps(rb_objspace_t *objspace, bits_t *stored_bitmaps) +gc_restore_exported_bitmaps(rb_objspace_t *objspace, bits_t *exported_bitmaps) { size_t i; for (i=0; i<heaps_used; i++) { struct heaps_slot *slot = objspace->heap.sorted[i]->base; - bits_t *oldgen_bits = &slot->oldgen_bits[0]; - RVALUE *p = objspace->heap.sorted[i]->start; - RVALUE *pend = p + objspace->heap.sorted[i]->limit; /* restore bitmaps */ - memcpy(&slot->mark_bits[0], &stored_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT], HEAP_BITMAP_SIZE); - memcpy(&slot->rememberset_bits[0], &stored_bitmaps[(3*i+1)*HEAP_BITMAP_LIMIT], HEAP_BITMAP_SIZE); - memcpy(&slot->oldgen_bits[0], &stored_bitmaps[(3*i+2)*HEAP_BITMAP_LIMIT], HEAP_BITMAP_SIZE); + memcpy(&slot->mark_bits[0], &exported_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT], HEAP_BITMAP_SIZE); + memcpy(&slot->rememberset_bits[0], &exported_bitmaps[(3*i+1)*HEAP_BITMAP_LIMIT], HEAP_BITMAP_SIZE); + memcpy(&slot->oldgen_bits[0], &exported_bitmaps[(3*i+2)*HEAP_BITMAP_LIMIT], HEAP_BITMAP_SIZE); - /* resotre oldgen bits */ - while (p < pend) { - if (MARKED_IN_BITMAP(oldgen_bits, p)) FL_SET2(p, FL_OLDGEN); - else FL_UNSET2(p, FL_OLDGEN); - p++; - } + /* restore oldgen flags */ + gc_oldgen_bitmap2flag(slot); } } static void -gc_free_stored_bitmaps(rb_objspace_t *objspace, bits_t *stored_bitmaps) +gc_free_exported_bitmaps(rb_objspace_t *objspace, bits_t *exported_bitmaps) { - free(stored_bitmaps); + free(exported_bitmaps); } static void -gc_marks_test(rb_objspace_t *objspace, bits_t *before_stored_bitmaps) +gc_save_bitmaps(rb_objspace_t *objspace) { - bits_t *stored_bitmaps = gc_store_bitmaps(objspace); + size_t i; + + for (i=0; i<heaps_used; i++) { + struct heaps_slot *slot = objspace->heap.sorted[i]->base; + + /* save bitmaps */ + memcpy(&slot->saved_mark_bits[0], &slot->mark_bits[0], HEAP_BITMAP_SIZE); + memcpy(&slot->saved_rememberset_bits[0], &slot->rememberset_bits[0], HEAP_BITMAP_SIZE); + memcpy(&slot->saved_oldgen_bits[0], &slot->oldgen_bits[0], HEAP_BITMAP_SIZE); + } + + objspace->rgengc.have_saved_bitmaps = TRUE; +} + +static void +gc_load_bitmaps(rb_objspace_t *objspace) +{ + size_t i; + + for (i=0; i<heaps_used; i++) { + struct heaps_slot *slot = objspace->heap.sorted[i]->base; + + /* load bitmaps */ + memcpy(&slot->mark_bits[0], &slot->saved_mark_bits[0], HEAP_BITMAP_SIZE); + memcpy(&slot->rememberset_bits[0], &slot->saved_rememberset_bits[0], HEAP_BITMAP_SIZE); + memcpy(&slot->oldgen_bits[0], &slot->saved_oldgen_bits[0], HEAP_BITMAP_SIZE); + + gc_oldgen_bitmap2flag(slot); + } +} + +static void +gc_marks_test(rb_objspace_t *objspace) +{ + bits_t *exported_bitmaps = gc_export_bitmaps(objspace); size_t i; size_t stored_oldgen, stored_shady; + /* + * Now, we have 2 types bitmaps: + * saved_bitmap: before minor marking + * exported_bitmap: after minor marking + */ + rgengc_report(1, objspace, "gc_marks_test: test-full-gc\n"); /* run major (full) gc with temporary mark/rememberset */ @@ -3547,14 +3623,14 @@ gc_marks_test(rb_objspace_t *objspace, b https://github.com/ruby/ruby/blob/trunk/gc.c#L3623 /* check */ for (i=0; i<heaps_used; i++) { - bits_t *minor_mark_bits = &stored_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT]; + bits_t *minor_mark_bits = &exported_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT]; bits_t *major_mark_bits = objspace->heap.sorted[i]->base->mark_bits; RVALUE *p = objspace->heap.sorted[i]->start; RVALUE *pend = p + objspace->heap.sorted[i]->limit; while (p < pend) { - if (MARKED_IN_BITMAP(major_mark_bits, p) && /* should be lived */ - !MARKED_IN_BITMAP(minor_mark_bits, p)) { + if (MARKED_IN_BITMAP(major_mark_bits, p) && /* should be lived */ + !MARKED_IN_BITMAP(minor_mark_bits, p)) { /* not marked -> BUG! */ fprintf(stderr, "gc_marks_test: %p (%s) is living, but not marked && not promoted.\n", p, obj_type_name((VALUE)p)); objspace->rgengc.interesting_object = (VALUE)p; } @@ -3563,22 +3639,24 @@ gc_marks_test(rb_objspace_t *objspace, b https://github.com/ruby/ruby/blob/trunk/gc.c#L3639 } if (objspace->rgengc.interesting_object) { - fprintf(stderr, "!!! restart minor gc\n"); - gc_restore_bitmaps(objspace, before_stored_bitmaps); + fprintf(stderr, "!!! restart major gc\n"); + gc_load_bitmaps(objspace); gc_marks_body(objspace, FALSE); - fprintf(stderr, "!!! restart major gc\n"); - gc_restore_bitmaps(objspace, before_stored_bitmaps); + fprintf(stderr, "!!! restart minor gc\n"); + gc_load_bitmaps(objspace); gc_marks_body(objspace, TRUE); + rb_bug("gc_marks_test (again): %p (%s) is living, but not marked && not promoted.\n", (void *)objspace->rgengc.interesting_object, obj_type_name((VALUE)objspace->rgengc.interesting_object)); } else { - gc_restore_bitmaps(objspace, stored_bitmaps); - gc_free_stored_bitmaps(objspace, stored_bitmaps); + gc_restore_exported_bitmaps(objspace, exported_bitmaps); + gc_free_exported_bitmaps(objspace, exported_bitmaps); + objspace->rgengc.have_saved_bitmaps = FALSE; } } -#endif /* USE_RGENGC */ +#endif /* RGENGC_CHECK_MODE >= 2 */ static void gc_marks(rb_objspace_t *objspace, int minor_gc) @@ -3603,15 +3681,13 @@ gc_marks(rb_objspace_t *objspace, int mi https://github.com/ruby/ruby/blob/trunk/gc.c#L3681 objspace->rgengc.oldgen_object_limit = objspace->rgengc.oldgen_object_count * 2; } else { /* minor GC */ - if (RGENGC_CHECK_MODE > 1) { - bits_t *before_mark_stored_bitmaps = gc_store_bitmaps(objspace); - gc_marks_body(objspace, TRUE); - gc_marks_test(objspace, before_mark_stored_bitmaps); - gc_free_stored_bitmaps(objspace, before_mark_stored_bitmaps); - } - else { - gc_marks_body(objspace, TRUE); - } +#if RGENGC_CHECK_MODE >= 2 + gc_save_bitmaps(objspace); + gc_marks_body(objspace, TRUE); + gc_marks_test(objspace); +#else + gc_marks_body(objspace, TRUE); +#endif } #if RGENGC_PROFILE > 0 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/