1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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@ruby-lang.org>.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41564 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
ko1 2013-06-22 06:43:30 +00:00
parent 98fec7b4a2
commit d73b9320cc
2 changed files with 173 additions and 81 deletions

View file

@ -1,3 +1,19 @@
Sat Jun 22 15:41:25 2013 Koichi Sasada <ko1@atdot.net>
* 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@ruby-lang.org>.
Sat Jun 22 15:25:00 2013 Charlie Somerville <charliesome@ruby-lang.org> Sat Jun 22 15:25:00 2013 Charlie Somerville <charliesome@ruby-lang.org>
* ext/etc/etc.c (setup_passwd): revert r41560, unnecessary * ext/etc/etc.c (setup_passwd): revert r41560, unnecessary

238
gc.c
View file

@ -392,6 +392,9 @@ typedef struct rb_objspace {
size_t remembered_shady_object_limit; size_t remembered_shady_object_limit;
size_t oldgen_object_count; size_t oldgen_object_count;
size_t oldgen_object_limit; size_t oldgen_object_limit;
#if RGENGC_CHECK_MODE >= 2
int have_saved_bitmaps;
#endif
} rgengc; } rgengc;
#endif /* USE_RGENGC */ #endif /* USE_RGENGC */
} rb_objspace_t; } rb_objspace_t;
@ -424,6 +427,11 @@ struct heaps_slot {
#if USE_RGENGC #if USE_RGENGC
bits_t rememberset_bits[HEAP_BITMAP_LIMIT]; bits_t rememberset_bits[HEAP_BITMAP_LIMIT];
bits_t oldgen_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 #endif
}; };
@ -2990,34 +2998,54 @@ static void
rgengc_check_shady(rb_objspace_t *objspace, VALUE obj) rgengc_check_shady(rb_objspace_t *objspace, VALUE obj)
{ {
#if USE_RGENGC #if USE_RGENGC
if (RGENGC_CHECK_MODE > 1) { #if RGENGC_CHECK_MODE >= 2
if (objspace->rgengc.interesting_object == obj) { VALUE parent = objspace->rgengc.parent_object;
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 == 3) { if (objspace->rgengc.interesting_object == obj) {
if (objspace->rgengc.interesting_object) { /* output interesting parent->child references */
if (FIXNUM_P(objspace->rgengc.parent_object)) { if (FIXNUM_P(parent)) {
fprintf(stderr, "rgengc_check_shady: [line %d] -> %p (%s)\n", fprintf(stderr, "rgengc_check_shady: !!! %p (%s) is pointed at line %d\n",
FIX2INT(objspace->rgengc.parent_object), (void *)obj, obj_type_name(obj)); (void *)obj, obj_type_name(obj), FIX2INT(parent));
} }
else { else {
fprintf(stderr, "rgengc_check_shady: %p (%s) -> %p (%s)\n", fprintf(stderr, "rgengc_check_shady: !!! %p (%s) is pointed by %p (%s)\n",
(void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object), (void *)obj, obj_type_name(obj), (void *)parent, obj_type_name(parent));
(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 && if (objspace->rgengc.parent_object_is_promoted &&
RVALUE_SHADY(obj) && !rgengc_remembered(objspace, obj)) { RVALUE_SHADY(obj) && !rgengc_remembered(objspace, obj)) {
rgengc_remember(objspace, obj); rgengc_remember(objspace, obj);
@ -3054,7 +3082,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
{ {
register RVALUE *obj = RANY(ptr); register RVALUE *obj = RANY(ptr);
#if RGENGC_CHECK_MODE > 1 #if RGENGC_CHECK_MODE >= 2
objspace->rgengc.parent_object = (VALUE)ptr; objspace->rgengc.parent_object = (VALUE)ptr;
#endif #endif
@ -3066,7 +3094,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr)
if (!markable_object_p(objspace, ptr)) return; if (!markable_object_p(objspace, ptr)) return;
rgengc_check_shady(objspace, ptr); rgengc_check_shady(objspace, ptr);
if (!gc_mark_ptr(objspace, ptr)) return; /* already marked */ 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; objspace->rgengc.parent_object = (VALUE)ptr;
#endif #endif
} }
@ -3475,64 +3503,112 @@ gc_marks_body(rb_objspace_t *objspace, int minor_gc)
rgengc_report(1, objspace, "gc_marks_body: end (%s)\n", minor_gc ? "minor" : "major"); rgengc_report(1, objspace, "gc_marks_body: end (%s)\n", minor_gc ? "minor" : "major");
} }
#if USE_RGENGC #if RGENGC_CHECK_MODE >= 2
static bits_t *
gc_store_bitmaps(rb_objspace_t *objspace)
{
bits_t *stored_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");
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);
}
return stored_bitmaps;
}
static void static void
gc_restore_bitmaps(rb_objspace_t *objspace, bits_t *stored_bitmaps) 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_export_bitmaps(rb_objspace_t *objspace)
{
bits_t *exported_bitmaps = (bits_t *)malloc(HEAP_BITMAP_SIZE * heaps_used * 3);
size_t i;
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(&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 exported_bitmaps;
}
static void
gc_restore_exported_bitmaps(rb_objspace_t *objspace, bits_t *exported_bitmaps)
{ {
size_t i; size_t i;
for (i=0; i<heaps_used; i++) { for (i=0; i<heaps_used; i++) {
struct heaps_slot *slot = objspace->heap.sorted[i]->base; 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 */ /* restore bitmaps */
memcpy(&slot->mark_bits[0], &stored_bitmaps[(3*i+0)*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], &stored_bitmaps[(3*i+1)*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], &stored_bitmaps[(3*i+2)*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 */ /* restore oldgen flags */
while (p < pend) { gc_oldgen_bitmap2flag(slot);
if (MARKED_IN_BITMAP(oldgen_bits, p)) FL_SET2(p, FL_OLDGEN);
else FL_UNSET2(p, FL_OLDGEN);
p++;
}
} }
} }
static void 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 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 i;
size_t stored_oldgen, stored_shady; 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"); rgengc_report(1, objspace, "gc_marks_test: test-full-gc\n");
/* run major (full) gc with temporary mark/rememberset */ /* run major (full) gc with temporary mark/rememberset */
@ -3547,14 +3623,14 @@ gc_marks_test(rb_objspace_t *objspace, bits_t *before_stored_bitmaps)
/* check */ /* check */
for (i=0; i<heaps_used; i++) { 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; bits_t *major_mark_bits = objspace->heap.sorted[i]->base->mark_bits;
RVALUE *p = objspace->heap.sorted[i]->start; RVALUE *p = objspace->heap.sorted[i]->start;
RVALUE *pend = p + objspace->heap.sorted[i]->limit; RVALUE *pend = p + objspace->heap.sorted[i]->limit;
while (p < pend) { while (p < pend) {
if (MARKED_IN_BITMAP(major_mark_bits, p) && /* should be lived */ if (MARKED_IN_BITMAP(major_mark_bits, p) && /* should be lived */
!MARKED_IN_BITMAP(minor_mark_bits, p)) { !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)); 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; objspace->rgengc.interesting_object = (VALUE)p;
} }
@ -3563,22 +3639,24 @@ gc_marks_test(rb_objspace_t *objspace, bits_t *before_stored_bitmaps)
} }
if (objspace->rgengc.interesting_object) { if (objspace->rgengc.interesting_object) {
fprintf(stderr, "!!! restart minor gc\n"); fprintf(stderr, "!!! restart major gc\n");
gc_restore_bitmaps(objspace, before_stored_bitmaps); gc_load_bitmaps(objspace);
gc_marks_body(objspace, FALSE); gc_marks_body(objspace, FALSE);
fprintf(stderr, "!!! restart major gc\n"); fprintf(stderr, "!!! restart minor gc\n");
gc_restore_bitmaps(objspace, before_stored_bitmaps); gc_load_bitmaps(objspace);
gc_marks_body(objspace, TRUE); gc_marks_body(objspace, TRUE);
rb_bug("gc_marks_test (again): %p (%s) is living, but not marked && not promoted.\n", 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)); (void *)objspace->rgengc.interesting_object, obj_type_name((VALUE)objspace->rgengc.interesting_object));
} }
else { else {
gc_restore_bitmaps(objspace, stored_bitmaps); gc_restore_exported_bitmaps(objspace, exported_bitmaps);
gc_free_stored_bitmaps(objspace, stored_bitmaps); gc_free_exported_bitmaps(objspace, exported_bitmaps);
objspace->rgengc.have_saved_bitmaps = FALSE;
} }
} }
#endif /* USE_RGENGC */ #endif /* RGENGC_CHECK_MODE >= 2 */
static void static void
gc_marks(rb_objspace_t *objspace, int minor_gc) gc_marks(rb_objspace_t *objspace, int minor_gc)
@ -3603,15 +3681,13 @@ gc_marks(rb_objspace_t *objspace, int minor_gc)
objspace->rgengc.oldgen_object_limit = objspace->rgengc.oldgen_object_count * 2; objspace->rgengc.oldgen_object_limit = objspace->rgengc.oldgen_object_count * 2;
} }
else { /* minor GC */ else { /* minor GC */
if (RGENGC_CHECK_MODE > 1) { #if RGENGC_CHECK_MODE >= 2
bits_t *before_mark_stored_bitmaps = gc_store_bitmaps(objspace); gc_save_bitmaps(objspace);
gc_marks_body(objspace, TRUE); gc_marks_body(objspace, TRUE);
gc_marks_test(objspace, before_mark_stored_bitmaps); gc_marks_test(objspace);
gc_free_stored_bitmaps(objspace, before_mark_stored_bitmaps); #else
} gc_marks_body(objspace, TRUE);
else { #endif
gc_marks_body(objspace, TRUE);
}
} }
#if RGENGC_PROFILE > 0 #if RGENGC_PROFILE > 0