[#5218] Ruby Book Eng tl, ch1 question — Jon Babcock <jon@...>

13 messages 2000/10/02

[#5404] Object.foo, setters and so on — "Hal E. Fulton" <hal9000@...>

OK, here is what I think I know.

14 messages 2000/10/11

[#5425] Ruby Book Eng. tl, 9.8.11 -- seishitsu ? — Jon Babcock <jon@...>

18 messages 2000/10/11
[#5427] RE: Ruby Book Eng. tl, 9.8.11 -- seishitsu ? — OZAWA -Crouton- Sakuro <crouton@...> 2000/10/11

At Thu, 12 Oct 2000 03:49:46 +0900,

[#5429] Re: Ruby Book Eng. tl, 9.8.11 -- seishitsu ? — Jon Babcock <jon@...> 2000/10/11

Thanks for the input.

[#5432] Re: Ruby Book Eng. tl, 9.8.11 -- seishitsu ? — Yasushi Shoji <yashi@...> 2000/10/11

At Thu, 12 Oct 2000 04:53:41 +0900,

[#5516] Re: Some newbye question — ts <decoux@...>

>>>>> "D" == Davide Marchignoli <marchign@di.unipi.it> writes:

80 messages 2000/10/13
[#5531] Re: Some newbye question — matz@... (Yukihiro Matsumoto) 2000/10/14

Hi,

[#5544] Re: Some newbye question — Davide Marchignoli <marchign@...> 2000/10/15

On Sat, 14 Oct 2000, Yukihiro Matsumoto wrote:

[#5576] Re: local variables (nested, in-block, parameters, etc.) — Dave Thomas <Dave@...> 2000/10/16

matz@zetabits.com (Yukihiro Matsumoto) writes:

[#5617] Re: local variables (nested, in-block, parameters, etc.) — "Brian F. Feldman" <green@...> 2000/10/16

Dave Thomas <Dave@thomases.com> wrote:

[#5705] Dynamic languages, SWOT ? — Hugh Sasse Staff Elec Eng <hgs@...>

There has been discussion on this list/group from time to time about

16 messages 2000/10/20
[#5712] Re: Dynamic languages, SWOT ? — Charles Hixson <charleshixsn@...> 2000/10/20

Hugh Sasse Staff Elec Eng wrote:

[#5882] [RFC] Towards a new synchronisation primitive — hipster <hipster@...4all.nl>

Hello fellow rubyists,

21 messages 2000/10/26

[ruby-talk:5917] gc.c.diff

From: Mathieu Bouchard <matju@...>
Date: 2000-10-27 14:54:52 UTC
List: ruby-talk #5917
in attachment, a diff -u patch for gc.c including:
  * disabled malloc_memories' effect
  * scale-proportionality
  * documentation
  * tuning on those values

this took way too long :-(

it will have to be tested with real programs. also i'd like that some
people post silly programs that take advantage of the weaknesses of this
version of ruby GC (seek the worst cases...)

(maybe one of the first things we'll notice is that we need to reenable
the malloc_memories condition again...) 

matju

Attachments (1)

gc.c.diff (7.19 KB, text/x-diff)
Index: gc.c
===================================================================
RCS file: /home/cvs/ruby/gc.c,v
retrieving revision 1.41
diff -u -r1.41 gc.c
--- gc.c	2000/10/16 09:13:16	1.41
+++ gc.c	2000/10/27 14:31:16
@@ -39,16 +39,104 @@
 
 static void run_final();
 
-#ifndef GC_MALLOC_LIMIT
-#if defined(MSDOS) || defined(__human68k__)
-#define GC_MALLOC_LIMIT 200000
-#else
-#define GC_MALLOC_LIMIT 8000000
-#endif
-#endif
+long gc_oalloc_live   = 0;
+long gc_oalloc_recent = 0;
+long gc_malloc_recent = 0;  /* unused */
+long gc_realloc_recent = 0; /* unused */
+
+void
+gc_clear_recent()
+{
+	long gc_oalloc_recent = 0;
+	long gc_malloc_recent = 0;
+	long gc_realloc_recent = 0;
+}
+
+/*!@#$ use RStruct instead to hold those constants/variables, etc. */
+
+/*******************************************************************/
+
+/*
+Garbage Collection Tuning Code and Documentation, by matju.
+
+  log for cvs:
+	added GC tuning code doc
+	GC_MALLOC_LIMIT removed 
+	added three equations for tuning GC (
+
+  note: GC_MALLOC_LIMIT is no longer supported.
+
+  Garbage Collection is done when:
+	1. when gc_oalloc_recent > gc_oalloc_threshold
+	2. the free-list is empty
+	3. when there is not enough free system memory (rare)
+
+  Heap activation is done when:
+	1. after a GC phase the free-list size is too small
+
+  Heap allocation is done when:
+	1. there are no more pre-allocated, inactive object pages.
+
+  Four counters:
+	1. gc_oalloc_live:   number of objs currently live,
+		including objects that are dead but not dealloced.
+	2. gc_oalloc_recent: number of obj.allocs since last GC.
+	3. gc_malloc_recent: (unused)
+		sum of malloc sizes since last GC.
+	4. gc_realloc_recent: (unused)
+		sum of realloc target-sizes since last GC.
+
+  Three 1st degree polynomials:
+	1. gc_oalloc_threshold: GC is run every N allocs
+	2. gc_minimum_free_cells: when to stop activating heaps
+	3. gc_heaps_increment: new heap allocation done in batch of N heaps
+
+  Linear equations make Ruby scale with the amount of data being processed.
+  In general you shouldn't (?) have to tune the polynomials. Exceptional
+  systems, however, should be given exceptional settings.
+
+  Even on a large machine, small process size may become important, if
+  you intend to have lots of processes.
+
+  Polynomials are of the form gc_oalloc_live * k_1n / k_1d + k_0.
+  As you see, Ruby GC scales up and down with memory usage, so that
+  the fraction of time spent on GC remains constant on average. However
+  remember that, as with most allocators/gc's, process size and number of
+  active heaps only goes up, not down, and some of the behaviour depends
+  on those values.
+*/
+
+typedef struct LinPoly {
+	long base   ; /* 0th degree */
+	long slope_n; /* 1st degree: numerator */
+	long slope_d; /* 1st degree: denominator */
+} LinPoly;
+
+const LinPoly gc_oalloc_threshold   = {    1024, 4,     1 };
+const LinPoly gc_minimum_free_cells = {    1024, 1,     5 };
+const LinPoly gc_heaps_increment    = {       1, 1, 65536 };
 
-static unsigned long malloc_memories = 0;
+/* pages of 160k on an i386 */
+#define HEAP_SLOTS 8192
 
+static int
+linpoly_calc(self)
+	LinPoly *self;
+{
+	/* beware of overflows here */
+	return
+		gc_oalloc_live * self->slope_n / self->slope_d
+		+ self->base;
+}
+
+static int
+gc_enough_allocs()
+{
+	return gc_oalloc_recent >= linpoly_calc(&gc_oalloc_threshold);
+}
+
+/*******************************************************************/
+
 static void
 mem_error(mesg)
     char *mesg;
@@ -69,9 +157,8 @@
 	rb_raise(rb_eNoMemError, "negative allocation size (or too big)");
     }
     if (size == 0) size = 1;
-    malloc_memories += size;
-
-    if (malloc_memories > GC_MALLOC_LIMIT) {
+    gc_malloc_recent += size;
+    if (gc_enough_allocs()) {
 	rb_gc();
     }
     mem = malloc(size);
@@ -80,7 +167,7 @@
 	mem = malloc(size);
 	if (!mem) {
 	    if (size >= 10 * 1024 * 1024) {
-		rb_raise(rb_eNoMemError, "tryed to allocate too big memory");
+		rb_raise(rb_eNoMemError, "tried to allocate too big memory");
 	    }
 	    mem_error("failed to allocate memory");
 	}
@@ -113,14 +200,14 @@
     }
     if (!ptr) return xmalloc(size);
     if (size == 0) size = 1;
-    malloc_memories += size;
+    gc_realloc_recent += size;
     mem = realloc(ptr, size);
     if (!mem) {
 	rb_gc();
 	mem = realloc(ptr, size);
 	if (!mem)
 	    if (size >= 50 * 1024 * 1024) {
-		rb_raise(rb_eNoMemError, "tryed to re-allocate too big memory");
+		rb_raise(rb_eNoMemError, "tried to re-allocate too big memory");
 	    }
 	    mem_error("failed to allocate memory(realloc)");
     }
@@ -132,6 +219,9 @@
 ruby_xfree(x)
     void *x;
 {
+    /*
+        assert(x);
+    */
     if (x) free(x);
 }
 
@@ -208,6 +298,7 @@
     rb_gc_register_address(var);
 }
 
+/* seems that on i386, sizeof(RVALUE) == 20 */
 typedef struct RVALUE {
     union {
 	struct {
@@ -235,14 +326,10 @@
 
 static RVALUE *freelist = 0;
 
-#define HEAPS_INCREMENT 10
 static RVALUE **heaps;
 static int heaps_length = 0;
 static int heaps_used   = 0;
 
-#define HEAP_SLOTS 10000
-#define FREE_MIN  4096
-
 static RVALUE *himem, *lomem;
 
 static void
@@ -252,7 +339,7 @@
 
     if (heaps_used == heaps_length) {
 	/* Realloc heaps */
-	heaps_length += HEAPS_INCREMENT;
+	heaps_length += linpoly_calc(&gc_heaps_increment);
 	heaps = (heaps_used>0)?
 	    (RVALUE**)realloc(heaps, heaps_length*sizeof(RVALUE*)):
 	    (RVALUE**)malloc(heaps_length*sizeof(RVALUE*));
@@ -284,6 +371,8 @@
     obj = (VALUE)freelist;
     freelist = freelist->as.free.next;
     MEMZERO((void*)obj, RVALUE, 1);
+    gc_oalloc_recent++;
+    gc_oalloc_live++;
     return obj;
 }
 
@@ -692,8 +781,9 @@
 	}
 	freed += n;
     }
-    if (freed < FREE_MIN) {
+    while (freed < linpoly_calc(&gc_minimum_free_cells)) {
 	add_heap();
+	freed += HEAP_SLOTS;
     }
     during_gc = 0;
 
@@ -846,6 +936,7 @@
 	rb_bug("gc_sweep(): unknown data type %d",
 	       RANY(obj)->as.basic.flags & T_MASK);
     }
+    gc_oalloc_live--;
 }
 
 void
@@ -914,14 +1005,15 @@
 #endif
 
     if (dont_gc || during_gc || rb_prohibit_interrupt || ruby_in_compile) {
-	if (!freelist || malloc_memories > GC_MALLOC_LIMIT) {
-	    malloc_memories = 0;
+	/* !@#$ enough_allocs ???? */
+	if (!freelist || gc_enough_allocs()) {
+            gc_clear_recent();
 	    add_heap();
 	}
 	return;
     }
 
-    malloc_memories = 0;
+    gc_clear_recent();
 
     if (during_gc) return;
     during_gc++;
@@ -1253,12 +1345,23 @@
     return (VALUE)ptr;
 }
 
+#define attr_reader(__a) static VALUE gc_##__a##_f() {\
+	return INT2NUM(gc_##__a);}
+
+attr_reader(oalloc_live)
+
 void
 Init_GC()
 {
     VALUE rb_mObSpace;
 
     rb_mGC = rb_define_module("GC");
+
+#define attr_reader_def(__a) rb_define_singleton_method(\
+	rb_mGC,#__a,gc_##__a##_f, 0);
+
+    attr_reader_def(oalloc_live);
+
     rb_define_singleton_method(rb_mGC, "start", gc_start, 0);
     rb_define_singleton_method(rb_mGC, "enable", gc_enable, 0);
     rb_define_singleton_method(rb_mGC, "disable", gc_disable, 0);
@@ -1316,3 +1419,4 @@
 {
     ruby_xfree(ptr);
 }
+

In This Thread

Prev Next