ruby-changes:29384
From: ko1 <ko1@a...>
Date: Wed, 19 Jun 2013 23:59:50 +0900 (JST)
Subject: [ruby-changes:29384] ko1:r41436 (trunk): * gc.c (garbage_collect_test): rewrite checking code.
ko1 2013-06-19 23:59:35 +0900 (Wed, 19 Jun 2013) New Revision: 41436 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=41436 Log: * gc.c (garbage_collect_test): rewrite checking code. When RGENGC_CHECK_MODE >= 2, all minor marking, run normal minor marking *and* major/full marking. After that, compare the results and shows BUG if a object living with major/full marking but dead with minor marking. After detecting bugs, print references information. (RGENGC_CHECK_MODE == 2, show references to dead object) (RGENGC_CHECK_MODE == 3, show all references) Modified files: trunk/ChangeLog trunk/gc.c Index: ChangeLog =================================================================== --- ChangeLog (revision 41435) +++ ChangeLog (revision 41436) @@ -1,3 +1,14 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Wed Jun 19 23:39:01 2013 Koichi Sasada <ko1@a...> + + * gc.c (garbage_collect_test): rewrite checking code. + When RGENGC_CHECK_MODE >= 2, all minor marking, run normal minor + marking *and* major/full marking. After that, compare the results + and shows BUG if a object living with major/full marking but dead + with minor marking. + After detecting bugs, print references information. + (RGENGC_CHECK_MODE == 2, show references to dead object) + (RGENGC_CHECK_MODE == 3, show all references) + Wed Jun 19 23:51:48 2013 Tanaka Akira <akr@f...> * bignum.c (bigfixize): Use rb_absint_size. Index: gc.c =================================================================== --- gc.c (revision 41435) +++ gc.c (revision 41436) @@ -3437,13 +3437,17 @@ gc_mark_stacked_objects(rb_objspace_t *o https://github.com/ruby/ruby/blob/trunk/gc.c#L3437 } static void -gc_marks_body(rb_objspace_t *objspace, rb_thread_t *th) +gc_marks_body(rb_objspace_t *objspace, rb_thread_t *th, int minor_gc) { struct gc_list *list; /* start marking */ rgengc_report(1, objspace, "gc_marks_body: start.\n"); + objspace->rgengc.parent_object_is_promoted = FALSE; + objspace->rgengc.parent_object = Qundef; + objspace->rgengc.during_minor_gc = minor_gc; + #if USE_RGENGC if (objspace->rgengc.during_minor_gc) { objspace->profile.minor_gc_count++; @@ -3504,77 +3508,99 @@ gc_marks_body(rb_objspace_t *objspace, r https://github.com/ruby/ruby/blob/trunk/gc.c#L3508 rgengc_report(1, objspace, "gc_marks_body: end.\n"); } -static void -gc_marks_test(rb_objspace_t *objspace, rb_thread_t *th) +static uintptr_t * +gc_store_bitmaps(rb_objspace_t *objspace) { -#if USE_RGENGC + uintptr_t *stored_bitmaps = (uintptr_t *)malloc((HEAP_BITMAP_LIMIT * sizeof(uintptr_t)) * heaps_used * 3); size_t i; - uintptr_t **prev_bitmaps = (uintptr_t **)malloc(sizeof(uintptr_t **) * heaps_used * 3); - uintptr_t *temp_bitmaps = (uintptr_t *)malloc((HEAP_BITMAP_LIMIT * sizeof(uintptr_t)) * heaps_used * 3); - rgengc_report(1, objspace, "gc_marks_test: test-full-gc\n"); + if (stored_bitmaps == 0) rb_bug("gc_store_bitmaps: not enough memory to test.\n"); - if (prev_bitmaps == 0 || temp_bitmaps == 0) { - rb_bug("gc_marks_test: not enough memory to test.\n"); + for (i=0; i<heaps_used; i++) { + memcpy(&stored_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT], objspace->heap.sorted[i]->mark_bits, sizeof(uintptr_t) * HEAP_BITMAP_LIMIT); + memcpy(&stored_bitmaps[(3*i+1)*HEAP_BITMAP_LIMIT], objspace->heap.sorted[i]->rememberset_bits, sizeof(uintptr_t) * HEAP_BITMAP_LIMIT); + memcpy(&stored_bitmaps[(3*i+2)*HEAP_BITMAP_LIMIT], objspace->heap.sorted[i]->oldgen_bits, sizeof(uintptr_t) * HEAP_BITMAP_LIMIT); } - memset(temp_bitmaps, 0, (HEAP_BITMAP_LIMIT * sizeof(uintptr_t)) * heaps_used * 3); - /* swap with temporary bitmaps */ + return stored_bitmaps; + } + +static void +gc_restore_bitmaps(rb_objspace_t *objspace, uintptr_t *stored_bitmaps) +{ + size_t i; + for (i=0; i<heaps_used; i++) { - prev_bitmaps[3*i+0] = objspace->heap.sorted[i]->mark_bits; - prev_bitmaps[3*i+1] = objspace->heap.sorted[i]->rememberset_bits; - prev_bitmaps[3*i+2] = objspace->heap.sorted[i]->oldgen_bits; - objspace->heap.sorted[i]->mark_bits = &temp_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT]; - objspace->heap.sorted[i]->rememberset_bits = &temp_bitmaps[(3*i+1)*HEAP_BITMAP_LIMIT]; - objspace->heap.sorted[i]->oldgen_bits = &temp_bitmaps[(3*i+2)*HEAP_BITMAP_LIMIT]; + uintptr_t *oldgen_bits = objspace->heap.sorted[i]->oldgen_bits; + RVALUE *p = objspace->heap.sorted[i]->start; + RVALUE *pend = p + objspace->heap.sorted[i]->limit; + + /* restore bitmaps */ + memcpy(objspace->heap.sorted[i]->mark_bits, &stored_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT], sizeof(uintptr_t) * HEAP_BITMAP_LIMIT); + memcpy(objspace->heap.sorted[i]->rememberset_bits, &stored_bitmaps[(3*i+1)*HEAP_BITMAP_LIMIT], sizeof(uintptr_t) * HEAP_BITMAP_LIMIT); + memcpy(objspace->heap.sorted[i]->oldgen_bits, &stored_bitmaps[(3*i+2)*HEAP_BITMAP_LIMIT], sizeof(uintptr_t) * HEAP_BITMAP_LIMIT); + + + /* 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++; + } + } +} + +static void +gc_free_stored_bitmaps(rb_objspace_t *objspace, uintptr_t *stored_bitmaps) +{ + free(stored_bitmaps); } +static void +gc_marks_test(rb_objspace_t *objspace, rb_thread_t *th, uintptr_t *before_stored_bitmaps) +{ +#if USE_RGENGC + uintptr_t *stored_bitmaps = gc_store_bitmaps(objspace); + size_t i; + + rgengc_report(1, objspace, "gc_marks_test: test-full-gc\n"); + /* run major (full) gc with temporary mark/rememberset */ - objspace->rgengc.parent_object_is_promoted = FALSE; - objspace->rgengc.parent_object = Qundef; - objspace->rgengc.during_minor_gc = FALSE; /* major/full GC with temporary bitmaps */ - gc_marks_body(objspace, th); + gc_marks_body(objspace, th, FALSE); + objspace->rgengc.during_minor_gc = TRUE; - /* check & restore */ + /* check */ for (i=0; i<heaps_used; i++) { - uintptr_t *minor_mark_bits = prev_bitmaps[3*i+0]; - uintptr_t *minor_rememberset_bits = prev_bitmaps[3*i+1]; - uintptr_t *minor_oldgen_bits = prev_bitmaps[3*i+2]; + uintptr_t *minor_mark_bits = &stored_bitmaps[(3*i+0)*HEAP_BITMAP_LIMIT]; uintptr_t *major_mark_bits = objspace->heap.sorted[i]->mark_bits; - /* uintptr_t *major_rememberset_bits = objspace->heap.sorted[i]->rememberset_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) && - !RVALUE_PROMOTED((VALUE)p)) { - + !MARKED_IN_BITMAP(minor_mark_bits, 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; - break; } p++; } - objspace->heap.sorted[i]->mark_bits = minor_mark_bits; - objspace->heap.sorted[i]->rememberset_bits = minor_rememberset_bits; - objspace->heap.sorted[i]->oldgen_bits = minor_oldgen_bits; } - free(prev_bitmaps); - free(temp_bitmaps); - - objspace->rgengc.during_minor_gc = TRUE; if (objspace->rgengc.interesting_object) { fprintf(stderr, "!!! restart minor gc\n"); - objspace->rgengc.during_minor_gc = TRUE; - gc_marks_body(objspace, th); + gc_restore_bitmaps(objspace, before_stored_bitmaps); + gc_marks_body(objspace, th, FALSE); + fprintf(stderr, "!!! restart major gc\n"); - objspace->rgengc.during_minor_gc = FALSE; - gc_marks_body(objspace, th); + gc_restore_bitmaps(objspace, before_stored_bitmaps); + gc_marks_body(objspace, th, 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); + } #endif } @@ -3589,30 +3615,27 @@ gc_marks(rb_objspace_t *objspace, int mi https://github.com/ruby/ruby/blob/trunk/gc.c#L3615 /* setup marking */ prev_mark_func_data = objspace->mark_func_data; objspace->mark_func_data = 0; - objspace->count++; - - SET_STACK_END; - - objspace->rgengc.parent_object_is_promoted = FALSE; - objspace->rgengc.parent_object = Qundef; - objspace->rgengc.during_minor_gc = minor_gc; if (minor_gc == FALSE) { /* major/full GC */ objspace->rgengc.remembered_shady_object_count = 0; objspace->rgengc.oldgen_object_count = 0; - gc_marks_body(objspace, th); + gc_marks_body(objspace, th, FALSE); /* Do full GC if old/remembered_shady object counts is greater than counts two times at last full GC counts */ objspace->rgengc.remembered_shady_object_limit = objspace->rgengc.remembered_shady_object_count * 2; objspace->rgengc.oldgen_object_limit = objspace->rgengc.oldgen_object_count * 2; } else { /* minor GC */ - gc_marks_body(objspace, th); + if (RGENGC_CHECK_MODE > 1) { + uintptr_t *before_mark_stored_bitmaps = gc_store_bitmaps(objspace); + gc_marks_body(objspace, th, TRUE); + gc_marks_test(objspace, th, before_mark_stored_bitmaps); + gc_free_stored_bitmaps(objspace, before_mark_stored_bitmaps); + } + else { + gc_marks_body(objspace, th, FALSE); } - - if (RGENGC_CHECK_MODE > 1 && minor_gc) { - gc_marks_test(objspace, th); } objspace->mark_func_data = prev_mark_func_data; @@ -3920,12 +3943,8 @@ garbage_collect_body(rb_objspace_t *objs https://github.com/ruby/ruby/blob/trunk/gc.c#L3943 immediate_sweep = TRUE; } - if (full_mark) { - objspace->rgengc.oldgen_object_count = 0; - } - if (GC_NOTIFY) fprintf(stderr, "start garbage_collect(%d, %d, %d)\n", full_mark, immediate_sweep, reason); - + objspace->count++; gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_START, 0 /* TODO: pass minor/immediate flag? */); gc_prof_timer_start(objspace, reason | (minor_gc ? GPR_FLAG_MINOR : 0)); -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/