Skip to content

Instantly share code, notes, and snippets.

@authorNari
Last active December 30, 2015 03:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save authorNari/7772756 to your computer and use it in GitHub Desktop.
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のバグをあぶり出すために作成。
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