Last active
December 30, 2015 03:59
-
-
Save authorNari/7772756 to your computer and use it in GitHub Desktop.
eager sweepを指定したオブジェクト生成分遅らせるGC.stressみたいなやつ。Ruby2.0.0用。
環境変数をRUBY_DELAY_SWEEP_INTERVAL=2に設定で「2個生成したあとにsweep,mark」みたいなことができる。
lazy sweepのバグをあぶり出すために作成。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/gc.c b/gc.c | |
index 84af4d6..278661e 100644 | |
--- a/gc.c | |
+++ b/gc.c | |
@@ -76,6 +76,7 @@ typedef struct { | |
unsigned int initial_malloc_limit; | |
unsigned int initial_heap_min_slots; | |
unsigned int initial_free_min; | |
+ unsigned int initial_delay_sweep_interval; | |
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE | |
int gc_stress; | |
#endif | |
@@ -85,6 +86,7 @@ static ruby_gc_params_t initial_params = { | |
GC_MALLOC_LIMIT, | |
HEAP_MIN_SLOTS, | |
FREE_MIN, | |
+ 0, | |
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE | |
FALSE, | |
#endif | |
@@ -288,6 +290,7 @@ int *ruby_initial_gc_stress_ptr = &rb_objspace.gc_stress; | |
#define initial_malloc_limit initial_params.initial_malloc_limit | |
#define initial_heap_min_slots initial_params.initial_heap_min_slots | |
#define initial_free_min initial_params.initial_free_min | |
+#define initial_delay_sweep_interval initial_params.initial_delay_sweep_interval | |
#define is_lazy_sweeping(objspace) ((objspace)->heap.sweep_slots != 0) | |
@@ -650,7 +653,14 @@ newobj(VALUE klass, VALUE flags) | |
} | |
} | |
- if (UNLIKELY(!has_free_object)) { | |
+ if (UNLIKELY(initial_delay_sweep_interval > 0)) { | |
+ if (!has_free_object && is_lazy_sweeping(objspace)) { | |
+ rest_sweep(objspace); | |
+ objspace->heap.free_slots = NULL; | |
+ } | |
+ } | |
+ | |
+ if (UNLIKELY(!has_free_object)){ | |
if (!gc_prepare_free_objects(objspace)) { | |
during_gc = 0; | |
rb_memerror(); | |
@@ -1429,8 +1439,10 @@ finalize_list(rb_objspace_t *objspace, RVALUE *p) | |
run_final(objspace, (VALUE)p); | |
objspace->total_freed_object_num++; | |
if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */ | |
- add_slot_local_freelist(objspace, p); | |
- objspace->heap.free_num++; | |
+ if (LIKELY(initial_delay_sweep_interval == 0)) { | |
+ add_slot_local_freelist(objspace, p); | |
+ objspace->heap.free_num++; | |
+ } | |
} | |
else { | |
struct heaps_slot *slot = (struct heaps_slot *)(VALUE)RDATA(p)->dmark; | |
@@ -2032,6 +2044,60 @@ rest_sweep(rb_objspace_t *objspace) | |
} | |
} | |
+static int gc_mark_ptr(rb_objspace_t *, VALUE); | |
+ | |
+static void | |
+relink_limited_freelist(rb_objspace_t *objspace, size_t limit) | |
+{ | |
+ struct heaps_slot *next, *slot; | |
+ RVALUE *p, *pend; | |
+ size_t count = 0; | |
+ uintptr_t *bits; | |
+ | |
+ objspace->heap.free_slots = NULL; | |
+ | |
+ if (objspace->heap.sweep_slots) { | |
+ slot = objspace->heap.sweep_slots; | |
+ while (slot) { | |
+ p = slot->header->start; pend = p + slot->header->limit; | |
+ bits = GET_HEAP_BITMAP(p); | |
+ while (p < pend) { | |
+ if ((!(MARKED_IN_BITMAP(bits, p))) && BUILTIN_TYPE(p) != T_ZOMBIE && !FL_TEST(p, FL_FINALIZE)) { | |
+ if (p->as.basic.flags && obj_free(objspace, (VALUE)p)) { | |
+ p->as.free.flags = T_ZOMBIE; | |
+ RDATA(p)->dfree = 0; | |
+ p->as.free.next = deferred_final_list; | |
+ deferred_final_list = p; | |
+ assert(BUILTIN_TYPE(p) == T_ZOMBIE); | |
+ } | |
+ else { | |
+ if (objspace->heap.free_slots != slot) { | |
+ slot->freelist = NULL; | |
+ link_free_heap_slot(objspace, slot); | |
+ } | |
+ (void)VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); | |
+ p->as.free.flags = 0; | |
+ p->as.free.next = slot->freelist; | |
+ slot->freelist = p; | |
+ objspace->heap.free_num++; | |
+ gc_mark_ptr(objspace, (VALUE)p); | |
+ count++; | |
+ if (count > limit) { | |
+ return; | |
+ } | |
+ } | |
+ } | |
+ p++; | |
+ } | |
+ slot = slot->next; | |
+ } | |
+ if (count == 0) { | |
+ set_heaps_increment(objspace); | |
+ heaps_increment(objspace); | |
+ } | |
+ } | |
+} | |
+ | |
static void gc_marks(rb_objspace_t *objspace); | |
static int | |
@@ -2074,13 +2140,20 @@ gc_prepare_free_objects(rb_objspace_t *objspace) | |
} | |
gc_prof_sweep_timer_start(objspace); | |
- if (!(res = lazy_sweep(objspace))) { | |
- after_gc_sweep(objspace); | |
- if (has_free_object) { | |
- res = TRUE; | |
- during_gc = 0; | |
+ if (LIKELY(initial_delay_sweep_interval == 0)) { | |
+ if (!(res = lazy_sweep(objspace))) { | |
+ after_gc_sweep(objspace); | |
+ if (has_free_object) { | |
+ res = TRUE; | |
+ during_gc = 0; | |
+ } | |
} | |
} | |
+ else { | |
+ relink_limited_freelist(objspace, initial_delay_sweep_interval); | |
+ res = TRUE; | |
+ during_gc = 0; | |
+ } | |
gc_prof_sweep_timer_stop(objspace); | |
gc_prof_timer_stop(objspace, Qtrue); | |
@@ -3294,7 +3367,7 @@ rb_gc_disable(void) | |
void | |
rb_gc_set_params(void) | |
{ | |
- char *malloc_limit_ptr, *heap_min_slots_ptr, *free_min_ptr; | |
+ char *malloc_limit_ptr, *heap_min_slots_ptr, *free_min_ptr, *delay_sweep_interval_ptr; | |
if (rb_safe_level() > 0) return; | |
@@ -3330,6 +3403,16 @@ rb_gc_set_params(void) | |
initial_free_min = free_min_i; | |
} | |
} | |
+ | |
+ delay_sweep_interval_ptr = getenv("RUBY_DELAY_SWEEP_INTERVAL"); | |
+ if (delay_sweep_interval_ptr != NULL) { | |
+ int delay_sweep_interval_i = atoi(delay_sweep_interval_ptr); | |
+ if (RTEST(ruby_verbose)) | |
+ fprintf(stderr, "delay_sweep_interval_i=%d (%d)\n", delay_sweep_interval_i, initial_delay_sweep_interval); | |
+ if (delay_sweep_interval_i > 0) { | |
+ initial_delay_sweep_interval = delay_sweep_interval_i; | |
+ } | |
+ } | |
} | |
void |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment