[前][次][番号順一覧][スレッド一覧]

ruby-changes:28832

From: ko1 <ko1@a...>
Date: Wed, 22 May 2013 08:09:35 +0900 (JST)
Subject: [ruby-changes:28832] ko1:r40884 (trunk): * gc.c (garbage_collect): all GC is start from garbage_collect()

ko1	2013-05-22 08:09:22 +0900 (Wed, 22 May 2013)

  New Revision: 40884

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=40884

  Log:
    * gc.c (garbage_collect): all GC is start from garbage_collect()
      (or garbage_collect_body()). `garbage_collect()' accept additional
      two parameters `full_mark' and `immediate_sweep'.
      If `full_mark' is TRUE, then force it full gc (major gc), otherwise,
      it depends on status of object space. Now, it will be minor gc.
      If `immediate_sweep' is TRUE, then disable lazy sweep.
      To allocate free memory, `full_mark' and `immediate_sweep' should be
      TRUE. Otherwise, they should be FALSE.
    * gc.c (gc_prepare_free_objects): use `garbage_collect_body()'.
    * gc.c (slot_sweep, before_gc_sweep, after_gc_sweep): add logging code.

  Modified files:
    trunk/ChangeLog
    trunk/gc.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 40883)
+++ ChangeLog	(revision 40884)
@@ -1,3 +1,18 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Wed May 22 07:36:08 2013  Koichi Sasada  <ko1@a...>
+
+	* gc.c (garbage_collect): all GC is start from garbage_collect()
+	  (or garbage_collect_body()). `garbage_collect()' accept additional
+	  two parameters `full_mark' and `immediate_sweep'.
+	  If `full_mark' is TRUE, then force it full gc (major gc), otherwise,
+	  it depends on status of object space. Now, it will be minor gc.
+	  If `immediate_sweep' is TRUE, then disable lazy sweep.
+	  To allocate free memory, `full_mark' and `immediate_sweep' should be
+	  TRUE. Otherwise, they should be FALSE.
+
+	* gc.c (gc_prepare_free_objects): use `garbage_collect_body()'.
+
+	* gc.c (slot_sweep, before_gc_sweep, after_gc_sweep): add logging code.
+
 Tue May 21 22:47:06 2013  NARUSE, Yui  <naruse@r...>
 
 	* ext/strscan/strscan.c (strscan_aref): support named captures.
Index: gc.c
===================================================================
--- gc.c	(revision 40883)
+++ gc.c	(revision 40884)
@@ -106,7 +106,7 @@ static ruby_gc_params_t initial_params = https://github.com/ruby/ruby/blob/trunk/gc.c#L106
 
 #if USE_RGENGC
 /* RGENGC_DEBUG:
- * 1:
+ * 1: basic information
  * 2: remember set operation
  * 3: mark
  * 4:
@@ -450,7 +450,8 @@ static void aligned_free(void *); https://github.com/ruby/ruby/blob/trunk/gc.c#L450
 static void init_mark_stack(mark_stack_t *stack);
 
 static VALUE lazy_sweep_enable(void);
-static int garbage_collect(rb_objspace_t *, int reason);
+static int garbage_collect(rb_objspace_t *, int full_mark, int immediate_sweep, int reason);
+static int garbage_collect_body(rb_objspace_t *, int full_mark, int immediate_sweep, int reason);
 static int gc_prepare_free_objects(rb_objspace_t *);
 static void mark_tbl(rb_objspace_t *, st_table *);
 static void rest_sweep(rb_objspace_t *);
@@ -813,8 +814,7 @@ newobj_of(VALUE klass, VALUE flags, VALU https://github.com/ruby/ruby/blob/trunk/gc.c#L814
     }
 
     if (UNLIKELY(ruby_gc_stress && !ruby_disable_gc_stress)) {
-	/* if (!garbage_collect(objspace)) { */
-	if (!gc_prepare_free_objects(objspace)) {
+	if (!garbage_collect(objspace, FALSE, FALSE, GPR_FLAG_NEWOBJ)) {
 	    during_gc = 0;
 	    rb_memerror();
 	}
@@ -860,7 +860,6 @@ newobj_of(VALUE klass, VALUE flags, VALU https://github.com/ruby/ruby/blob/trunk/gc.c#L860
     rgengc_report(5, objspace, "newobj: %p (%s)\n", (void *)obj, obj_type_name(obj));
 
 #if USE_RGENGC && RGENGC_CHECK_MODE
-    if (RBASIC(obj)->flags) rb_bug("newobj: flags of %p (%s) is not zero (%-8lx).\n", (void *)obj, obj_type_name(obj), RBASIC(obj)->flags);
     if (RVALUE_PROMOTED(obj)) rb_bug("newobj: %p (%s) is promoted.\n", (void *)obj, obj_type_name(obj));
     if (rgengc_remembered(objspace, (VALUE)obj)) rb_bug("newobj: %p (%s) is remembered.\n", (void *)obj, obj_type_name(obj));
 #endif
@@ -2018,8 +2017,6 @@ count_objects(int argc, VALUE *argv, VAL https://github.com/ruby/ruby/blob/trunk/gc.c#L2017
     return hash;
 }
 
-
-
 /*
   ------------------------ Garbage Collection ------------------------
 */
@@ -2182,6 +2179,7 @@ slot_sweep_major(rb_objspace_t *objspace https://github.com/ruby/ruby/blob/trunk/gc.c#L2179
 static void
 slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
 {
+    rgengc_report(1, objspace, "slot_sweep: start\n");
     gc_prof_sweep_slot_timer_start(objspace);
     {
 #if USE_RGENGC
@@ -2196,6 +2194,7 @@ slot_sweep(rb_objspace_t *objspace, stru https://github.com/ruby/ruby/blob/trunk/gc.c#L2194
 #endif
     }
     gc_prof_sweep_slot_timer_stop(objspace);
+    rgengc_report(1, objspace, "slot_sweep: end\n");
 }
 
 static int
@@ -2216,6 +2215,8 @@ ready_to_gc(rb_objspace_t *objspace) https://github.com/ruby/ruby/blob/trunk/gc.c#L2215
 static void
 before_gc_sweep(rb_objspace_t *objspace)
 {
+    rgengc_report(1, objspace, "before_gc_sweep\n");
+
     objspace->heap.do_heap_free = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.65);
     objspace->heap.free_min = (size_t)((heaps_used * HEAP_OBJ_LIMIT)  * 0.2);
     if (objspace->heap.free_min < initial_free_min) {
@@ -2238,15 +2239,19 @@ after_gc_sweep(rb_objspace_t *objspace) https://github.com/ruby/ruby/blob/trunk/gc.c#L2239
 {
     size_t inc;
 
+    rgengc_report(1, objspace, "after_gc_sweep\n");
+
     gc_prof_set_malloc_info(objspace);
     rgengc_report(5, objspace, "after_gc_sweep: objspace->heap.free_num: %d, objspace->heap.free_min: %d\n",
 		  objspace->heap.free_num, objspace->heap.free_min);
+
     if (objspace->heap.free_num < objspace->heap.free_min) {
         set_heaps_increment(objspace);
         heaps_increment(objspace);
     }
 
     inc = ATOMIC_SIZE_EXCHANGE(malloc_increase, 0);
+
     if (inc > malloc_limit) {
 	malloc_limit +=
 	  (size_t)((inc - malloc_limit) * (double)objspace_live_num(objspace) / (heaps_used * HEAP_OBJ_LIMIT));
@@ -2287,37 +2292,46 @@ rest_sweep(rb_objspace_t *objspace) https://github.com/ruby/ruby/blob/trunk/gc.c#L2292
     }
 }
 
-static void gc_marks(rb_objspace_t *objspace, int minor_gc);
-
 static void
-gc_sweep(rb_objspace_t *objspace)
+gc_sweep(rb_objspace_t *objspace, int immediate_sweep)
 {
-    struct heaps_slot *next;
+    if (immediate_sweep) {
+	struct heaps_slot *next;
+	before_gc_sweep(objspace);
 
-    before_gc_sweep(objspace);
+	while (objspace->heap.sweep_slots) {
+	    next = objspace->heap.sweep_slots->next;
+	    slot_sweep(objspace, objspace->heap.sweep_slots);
+	    objspace->heap.sweep_slots = next;
+	}
 
-    while (objspace->heap.sweep_slots) {
-        next = objspace->heap.sweep_slots->next;
-	slot_sweep(objspace, objspace->heap.sweep_slots);
-        objspace->heap.sweep_slots = next;
+	after_gc_sweep(objspace);
+    }
+    else {
+	before_gc_sweep(objspace);
+	lazy_sweep(objspace);
     }
 
-    after_gc_sweep(objspace);
-
-    during_gc = 0;
+    if (!has_free_object) {
+	/* there is no freespace after slot_sweep() */
+	/* TODO: [RGENGC] Should do major GC before adding hepas */
+	set_heaps_increment(objspace);
+	if (!heaps_increment(objspace)) {
+	    during_gc = 0;
+	    rb_memerror();
+	}
+    }
 }
 
 static int
 gc_prepare_free_objects(rb_objspace_t *objspace)
 {
-    int res;
-
     if (!GC_ENABLE_LAZY_SWEEP || objspace->flags.dont_lazy_sweep) {
 	if (heaps_increment(objspace)) {
 	    return TRUE;
 	}
 	else {
-	    return garbage_collect(objspace, GPR_FLAG_NEWOBJ);
+	    return garbage_collect(objspace, FALSE, TRUE, GPR_FLAG_NEWOBJ);
 	}
     }
 
@@ -2326,42 +2340,18 @@ gc_prepare_free_objects(rb_objspace_t *o https://github.com/ruby/ruby/blob/trunk/gc.c#L2340
     during_gc++;
 
     if (objspace->heap.sweep_slots) {
-        res = lazy_sweep(objspace);
-	if (res) {
-            return res;
-        }
+	if (lazy_sweep(objspace)) {
+	    return TRUE;
+	}
     }
     else {
         if (heaps_increment(objspace)) {
-            during_gc = 0;
+	    during_gc = 0;
             return TRUE;
         }
     }
 
-    gc_prof_timer_start(objspace, GPR_FLAG_NEWOBJ | GPR_FLAG_MINOR);
-    {
-	gc_marks(objspace, TRUE);
-
-	before_gc_sweep(objspace);
-	if (!(res = lazy_sweep(objspace))) {
-	    /* there is no freespace after slot_sweep() */
-	    while (1) {
-		/* There is no empty RVALUE spaces */
-		/* TODO: [RGENGC] Should do major GC before adding hepas */
-
-		set_heaps_increment(objspace);
-		heaps_increment(objspace);
-
-		if (has_free_object) {
-		    res = TRUE;
-		    during_gc = 0;
-		    break;
-		}
-	    }
-	}
-    }
-    gc_prof_timer_stop(objspace);
-    return res;
+    return garbage_collect_body(objspace, 0, 0, GPR_FLAG_NEWOBJ);
 }
 
 /* Marking stack */
@@ -2967,31 +2957,33 @@ gc_mark_children(rb_objspace_t *objspace https://github.com/ruby/ruby/blob/trunk/gc.c#L2957
   marking:
 
 #if USE_RGENGC
-    if (RGENGC_CHECK_MODE && RVALUE_SHADY(obj) && RVALUE_PROMOTED(obj)) {
-	rb_bug("gc_mark_children: (1) %p (%s) is shady and promoted.\n", (void *)obj, obj_type_name((VALUE)obj));
-    }
+    if (LIKELY(objspace->mark_func_data == 0)) {
+	if (RGENGC_CHECK_MODE && RVALUE_SHADY(obj) && RVALUE_PROMOTED(obj)) {
+	    rb_bug("gc_mark_children: (1) %p (%s) is shady and promoted.\n", (void *)obj, obj_type_name((VALUE)obj));
+	}
 
-    if (objspace->rgengc.during_minor_gc) {
-	/* only minor gc skip marking promoted objects */
-	if (RVALUE_PROMOTED(obj)) {
-	    rgengc_report(3, objspace, "gc_mark_children: %p (%s) was promoted.\n", obj, obj_type_name((VALUE)obj));
-	    return; /* old gen */
+	if (objspace->rgengc.during_minor_gc) {
+	    /* only minor gc skip marking promoted objects */
+	    if (RVALUE_PROMOTED(obj)) {
+		rgengc_report(3, objspace, "gc_mark_children: %p (%s) was promoted.\n", obj, obj_type_name((VALUE)obj));
+		return; /* old gen */
+	    }
 	}
-    }
 
-    /* minor/major common */
-    if (RVALUE_SUNNY(obj)) {
-	RVALUE_PROMOTE(obj); /* Sunny object can be promoted to OLDGEN object */
-	rgengc_report(3, objspace, "gc_mark_children: promote %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj));
-	objspace->rgengc.parent_object_is_promoted = TRUE;
-    }
-    else {
-	rgengc_report(3, objspace, "gc_mark_children: do not promote shady %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj));
-	objspace->rgengc.parent_object_is_promoted = FALSE;
-    }
+	/* minor/major common */
+	if (RVALUE_SUNNY(obj)) {
+	    RVALUE_PROMOTE(obj); /* Sunny object can be promoted to OLDGEN object */
+	    rgengc_report(3, objspace, "gc_mark_children: promote %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj));
+	    objspace->rgengc.parent_object_is_promoted = TRUE;
+	}
+	else {
+	    rgengc_report(3, objspace, "gc_mark_children: do not promote shady %p (%s).\n", (void *)obj, obj_type_name((VALUE)obj));
+	    objspace->rgengc.parent_object_is_promoted = FALSE;
+	}
 
-    if (RGENGC_CHECK_MODE && RVALUE_SHADY(obj) && RVALUE_PROMOTED(obj)) {
-	rb_bug("gc_mark_children: (2) %p (%s) is shady and promoted.\n", (void *)obj, obj_type_name((VALUE)obj));
+	if (RGENGC_CHECK_MODE && RVALUE_SHADY(obj) && RVALUE_PROMOTED(obj)) {
+	    rb_bug("gc_mark_children: (2) %p (%s) is shady and promoted.\n", (void *)obj, obj_type_name((VALUE)obj));
+	}
     }
 #endif /* USE_RGENGC */
 
@@ -3689,24 +3681,34 @@ rb_gc_unregister_address(VALUE *addr) https://github.com/ruby/ruby/blob/trunk/gc.c#L3681
 #define GC_NOTIFY 0
 
 static int
-garbage_collect(rb_objspace_t *objspace, int reason)
+garbage_collect_body(rb_objspace_t *objspace, int full_mark, int immediate_sweep, int reason)
 {
-    if (GC_NOTIFY) printf("start garbage_collect()\n");
+    int minor_gc;
 
-    if (!heaps) {
-	return FALSE;
+    if (ruby_gc_stress && !ruby_disable_gc_stress) {
+	minor_gc = TRUE;
+	immediate_sweep = TRUE;
     }
-    if (!ready_to_gc(objspace)) {
-        return TRUE;
+    else {
+	if (full_mark) {
+	    minor_gc = FALSE;
+	}
+	else {
+	    /* TODO: count old object size and so on */
+	    minor_gc = TRUE;
+	}
     }
 
-    rest_sweep(objspace);
+    if (GC_ENABLE_LAZY_SWEEP || objspace->flags.dont_lazy_sweep) {
+	immediate_sweep = TRUE;
+    }
 
-    gc_prof_timer_start(objspace, reason);
+    gc_prof_timer_start(objspace, reason | (minor_gc ? GPR_FLAG_MINOR : 0));
     {
-	during_gc++;
-	gc_marks(objspace, FALSE);
-	gc_sweep(objspace);
+	assert(during_gc > 0);
+	gc_marks(objspace, minor_gc);
+	gc_sweep(objspace, immediate_sweep);
+	during_gc = 0;
     }
     gc_prof_timer_stop(objspace);
 
@@ -3714,30 +3716,55 @@ garbage_collect(rb_objspace_t *objspace, https://github.com/ruby/ruby/blob/trunk/gc.c#L3716
     return TRUE;
 }
 
+static int
+garbage_collect(rb_objspace_t *objspace, int full_mark, int immediate_sweep, int reason)
+{
+    if (GC_NOTIFY) printf("start garbage_collect(%d, %d, %d)\n", full_mark, immediate_sweep, reason);
+
+    if (!heaps) {
+	during_gc = 0;
+	return FALSE;
+    }
+    if (!ready_to_gc(objspace)) {
+	during_gc = 0;
+	return TRUE;
+    }
+
+    rest_sweep(objspace);
+
+    during_gc++;
+
+    return garbage_collect_body(objspace, full_mark, immediate_sweep, reason);
+}
+
 struct objspace_and_reason {
     rb_objspace_t *objspace;
     int reason;
+    int full_mark;
+    int immediate_sweep;
 };
 
 static void *
 gc_with_gvl(void *ptr)
 {
     struct objspace_and_reason *oar = (struct objspace_and_reason *)ptr;
-    return (void *)(VALUE)garbage_collect(oar->objspace, oar->reason);
+    return (void *)(VALUE)garbage_collect(oar->objspace, oar->full_mark, oar->immediate_sweep, oar->reason);
 }
 
 static int
-garbage_collect_with_gvl(rb_objspace_t *objspace, int reason)
+garbage_collect_with_gvl(rb_objspace_t *objspace, int full_mark, int immediate_sweep, int reason)
 {
     if (dont_gc) return TRUE;
     if (ruby_thread_has_gvl_p()) {
-	return garbage_collect(objspace, reason);
+	return garbage_collect(objspace, full_mark, immediate_sweep, reason);
     }
     else {
 	if (ruby_native_thread_p()) {
 	    struct objspace_and_reason oar;
 	    oar.objspace = objspace;
 	    oar.reason = reason;
+	    oar.full_mark = full_mark;
+	    oar.immediate_sweep = immediate_sweep;
 	    return (int)(VALUE)rb_thread_call_with_gvl(gc_with_gvl, (void *)&oar);
 	}
 	else {
@@ -3751,7 +3778,7 @@ garbage_collect_with_gvl(rb_objspace_t * https://github.com/ruby/ruby/blob/trunk/gc.c#L3778
 int
 rb_garbage_collect(void)
 {
-    return garbage_collect(&rb_objspace, GPR_FLAG_CAPI);
+    return garbage_collect(&rb_objspace, TRUE, TRUE, GPR_FLAG_CAPI);
 }
 
 #undef Init_stack
@@ -3783,7 +3810,7 @@ void https://github.com/ruby/ruby/blob/trunk/gc.c#L3810
 rb_gc(void)
 {
     rb_objspace_t *objspace = &rb_objspace;
-    garbage_collect(objspace, GPR_FLAG_METHOD);
+    garbage_collect(objspace, TRUE, TRUE, GPR_FLAG_METHOD);
     if (!finalizing) finalize_deferred(objspace);
     free_unused_heaps(objspace);
 }
@@ -4213,7 +4240,7 @@ vm_malloc_prepare(rb_objspace_t *objspac https://github.com/ruby/ruby/blob/trunk/gc.c#L4240
 
     if ((ruby_gc_stress && !ruby_disable_gc_stress) ||
 	(malloc_increase+size) > malloc_limit) {
-	garbage_collect_with_gvl(objspace, GPR_FLAG_MALLOC);
+	garbage_collect_with_gvl(objspace, 0, 0, GPR_FLAG_MALLOC);
     }
 
     return size;
@@ -4236,7 +4263,7 @@ vm_malloc_fixup(rb_objspace_t *objspace, https://github.com/ruby/ruby/blob/trunk/gc.c#L4263
 
 #define TRY_WITH_GC(alloc) do { \
 	if (!(alloc) && \
-	    (!garbage_collect_with_gvl(objspace, GPR_FLAG_MALLOC) || \
+	    (!garbage_collect_with_gvl(objspace, 1, 1, GPR_FLAG_MALLOC) || /* full mark && immediate sweep */ \
 	     !(alloc))) { \
 	    ruby_memerror(); \
 	} \
@@ -4276,7 +4303,7 @@ vm_xrealloc(rb_objspace_t *objspace, voi https://github.com/ruby/ruby/blob/trunk/gc.c#L4303
 	return 0;
     }
     if (ruby_gc_stress && !ruby_disable_gc_stress)
-	garbage_collect_with_gvl(objspace, GPR_FLAG_MALLOC);
+	garbage_collect_with_gvl(objspace, 0, 0, GPR_FLAG_MALLOC);
 
 #if CALC_EXACT_MALLOC_SIZE
     size += sizeof(size_t);
@@ -4286,7 +4313,7 @@ vm_xrealloc(rb_objspace_t *objspace, voi https://github.com/ruby/ruby/blob/trunk/gc.c#L4313
 
     mem = realloc(ptr, size);
     if (!mem) {
-	if (garbage_collect_with_gvl(objspace, GPR_FLAG_MALLOC)) {
+	if (garbage_collect_with_gvl(objspace, 1, 1, GPR_FLAG_MALLOC)) {
 	    mem = realloc(ptr, size);
 	}
 	if (!mem) {

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]