[Gc] Configurable GC_INIT

Ivan Maidanski ivmai at mail.ru
Mon Nov 17 10:25:06 PST 2008


Hi!

The concept of "configurable" GC_INIT() is to have a mean of GC fine-grained tuning at the stage of an application compilation (without the need to modify the source of that application).

For tuning, the following macros could be used:
- GC_FREE_SPACE_DIVISOR=<value>,
- GC_FULL_FREQ=<value>,
- GC_TIME_LIMIT=<millis>,
- GC_DONT_EXPAND - for setting GC_dont_expand to 1,
- GC_MAX_RETRIES=<value>,
- GC_IGNORE_WARN - for ignoring all warnings,
- GC_INITIAL_HEAP_SIZE=<size_in_bytes>.

For convenience, these macros (except for GC_IGNORE_WARN) could be also used when GC itself is compiled.

This patch also does the following (minor) things:
- remove locking (and an initialization check) in GC_set_warn_proc() (that's consistent with GC_set_oom_fn() and GC_set_finalizer_notifier());
- recognize "GC_FULL_FREQUENCY" environment var (unless SMALL_CONFIG);
- add exported GC_ignore_warn_proc() (for GC_IGNORE_WARN macro);
- add exported GC_set_full_freq() and GC_set_time_limit() for setting (and getting) the corresponding global vars;
- add volatile modifier for "frames" var in GC_clear_a_few_frames() (also: NWORDS is renamed to CLEAR_NWORDS);
- the definitions of GC_RATE, MAX_PRIOR_ATTEMPTS, PREF_DIST, N_LOCAL_ITERS, ENTRIES_TO_GET macros are guarded with "ifndef";
- TIME_LIMIT macro is renamed to GC_TIME_LIMIT (to be consistent with "configurable" GC_INIT());
- update GC_copyright[].

Bye.

-------------- next part --------------
diff -ru bdwgc/alloc.c updated/bdwgc/alloc.c
--- bdwgc/alloc.c	2008-10-31 19:43:49.000000000 +0300
+++ updated/bdwgc/alloc.c	2008-11-17 13:39:50.000000000 +0300
@@ -65,9 +65,13 @@
 
 int GC_parallel = FALSE;   /* By default, parallel GC is off.	*/
 
-int GC_full_freq = 19;	   /* Every 20th collection is a full	*/
+#ifndef GC_FULL_FREQ
+# define GC_FULL_FREQ 19   /* Every 20th collection is a full	*/
 			   /* collection, whether we need it 	*/
 			   /* or not.			        */
+#endif
+
+int GC_full_freq = GC_FULL_FREQ;
 
 GC_bool GC_need_full_gc = FALSE;
 			   /* Need full GC do to heap growth.	*/
@@ -85,7 +89,7 @@
 {"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ",
 "Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved. ",
 "Copyright (c) 1996-1998 by Silicon Graphics.  All rights reserved. ",
-"Copyright (c) 1999-2001 by Hewlett-Packard Company.  All rights reserved. ",
+"Copyright (c) 1999-2008 by Hewlett-Packard Company.  All rights reserved. ",
 "THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
 " EXPRESSED OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.",
 "See source code for details." };
@@ -104,16 +108,29 @@
 extern signed_word GC_bytes_found; /* Number of reclaimed bytes		*/
 				  /* after garbage collection      	*/
 
-GC_bool GC_dont_expand = 0;
+#ifdef GC_DONT_EXPAND
+  GC_bool GC_dont_expand = TRUE;
+#else
+  GC_bool GC_dont_expand = FALSE;
+#endif
 
-word GC_free_space_divisor = 3;
+#ifndef GC_FREE_SPACE_DIVISOR
+# define GC_FREE_SPACE_DIVISOR 3 /* must be > 0 */
+#endif
+
+word GC_free_space_divisor = GC_FREE_SPACE_DIVISOR;
 
 extern GC_bool GC_collection_in_progress(void);
 		/* Collection is in progress, or was abandoned.	*/
 
 int GC_CALLBACK GC_never_stop_func (void) { return(0); }
 
-unsigned long GC_time_limit = TIME_LIMIT;
+#ifndef GC_TIME_LIMIT
+# define GC_TIME_LIMIT 50  /* We try to keep pause times from exceeding	 */
+			   /* this by much. In milliseconds.		 */
+#endif
+
+unsigned long GC_time_limit = GC_TIME_LIMIT;
 
 #ifndef NO_CLOCK
 STATIC CLOCK_TYPE GC_start_time;/* Time at which we stopped world.	*/
@@ -222,11 +239,13 @@
 /* stack clear of long-lived, client-generated garbage.			*/
 STATIC void GC_clear_a_few_frames(void)
 {
-#   define NWORDS 64
-    word frames[NWORDS];
+#   ifndef CLEAR_NWORDS
+#     define CLEAR_NWORDS 64
+#   endif
+    volatile word frames[CLEAR_NWORDS];
     int i;
     
-    for (i = 0; i < NWORDS; i++) frames[i] = 0;
+    for (i = 0; i < CLEAR_NWORDS; i++) frames[i] = 0;
 }
 
 /* Heap size at which we need a collection to avoid expanding past	*/
@@ -396,8 +415,12 @@
  * GC strategy, since otherwise we allocate too much during GC, and the
  * cleanup gets expensive.
  */
+#ifndef GC_RATE
 # define GC_RATE 10 
+#endif
+#ifndef MAX_PRIOR_ATTEMPTS
 # define MAX_PRIOR_ATTEMPTS 1
+#endif
  	/* Maximum number of prior attempts at world stop marking	*/
  	/* A value of 1 means that we finish the second time, no matter */
  	/* how long it takes.  Doesn't count the initial root scan	*/
@@ -955,7 +978,11 @@
     GC_max_heapsize = n;
 }
 
-GC_word GC_max_retries = 0;
+#ifndef GC_MAX_RETRIES
+# define GC_MAX_RETRIES 2
+#endif
+
+GC_word GC_max_retries = GC_MAX_RETRIES;
 
 /*
  * this explicitly increases the size of the heap.  It is used
diff -ru bdwgc/include/gc.h updated/bdwgc/include/gc.h
--- bdwgc/include/gc.h	2008-11-13 12:23:54.000000000 +0300
+++ updated/bdwgc/include/gc.h	2008-11-17 13:03:28.000000000 +0300
@@ -183,6 +183,7 @@
 			    /* blocks.  Values in the tens are now	*/
 			    /* perfectly reasonable, unlike for		*/
 			    /* earlier GC versions.			*/
+GC_API int GC_CALL GC_set_full_freq(int value);
 			
 GC_API GC_word GC_non_gc_bytes;
 			/* Bytes not considered candidates for collection. */
@@ -254,6 +255,7 @@
 				/* Setting GC_time_limit to this value	 */
 				/* will disable the "pause time exceeded"*/
 				/* tests.				 */
+GC_API unsigned long GC_CALL GC_set_time_limit(unsigned long value);
 
 /* Public procedures */
 
@@ -833,6 +835,10 @@
     /* Returns old warning procedure.			     */
     /* With 0 argument, current warn_proc remains unchanged. */
     /* (Only true for GC7.2+)				     */
+    /* GC_ignore_warn_proc may be used as an argument for    */
+    /* GC_set_warn_proc() to ignore all warnings (unless     */
+    /* statistics printing is turned on).		     */
+GC_API void GC_CALLBACK GC_ignore_warn_proc(char *msg, GC_word arg);
 
 GC_API GC_word GC_CALL GC_set_free_space_divisor(GC_word value);
     /* Set free_space_divisor.  See above for definition.	*/
@@ -1148,12 +1154,12 @@
   * defined and the initial allocation call is not to GC_malloc() or
   * GC_malloc_atomic().
   */
-#if defined(__CYGWIN32__) || defined (_AIX)
+
     /*
      * Similarly gnu-win32 DLLs need explicit initialization from
      * the main program, as does AIX.
      */
-#   ifdef __CYGWIN32__
+#ifdef __CYGWIN32__
       extern int _data_start__[];
       extern int _data_end__[];
       extern int _bss_start__[];
@@ -1162,20 +1168,80 @@
 #     define GC_MIN(x,y) ((x) < (y) ? (x) : (y))
 #     define GC_DATASTART ((void *) GC_MIN(_data_start__, _bss_start__))
 #     define GC_DATAEND	 ((void *) GC_MAX(_data_end__, _bss_end__))
-#     define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); \
-			   GC_gcollect(); /* For blacklisting. */}
+#     define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND); \
+				 GC_gcollect() /* For blacklisting. */
 	/* Required at least if GC is in dll.  And doesn't hurt. */
-#   endif
-#   if defined(_AIX)
+#elif defined(_AIX)
       extern int _data[], _end[];
 #     define GC_DATASTART ((void *)((ulong)_data))
 #     define GC_DATAEND ((void *)((ulong)_end))
-#     define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); }
-#   endif
+#     define GC_INIT_CONF_ROOTS GC_add_roots(GC_DATASTART, GC_DATAEND)
 #else
-#   define GC_INIT() { GC_init(); }
+#     define GC_INIT_CONF_ROOTS /* empty */
 #endif
 
+#ifdef GC_DONT_EXPAND
+  /* Set GC_dont_expand to TRUE at start-up */
+# define GC_INIT_CONF_DONT_EXPAND GC_set_dont_expand(1)
+#else
+# define GC_INIT_CONF_DONT_EXPAND /* empty */
+#endif
+
+#ifdef GC_MAX_RETRIES
+  /* Set GC_max_retries to the desired value at start-up */
+# define GC_INIT_CONF_MAX_RETRIES GC_set_max_retries(GC_MAX_RETRIES)
+#else
+# define GC_INIT_CONF_MAX_RETRIES /* empty */
+#endif
+
+#ifdef GC_FREE_SPACE_DIVISOR
+  /* Set GC_free_space_divisor to the desired value at start-up */
+# define GC_INIT_CONF_FREE_SPACE_DIVISOR \
+		GC_set_free_space_divisor(GC_FREE_SPACE_DIVISOR)
+#else
+# define GC_INIT_CONF_FREE_SPACE_DIVISOR /* empty */
+#endif
+
+#ifdef GC_FULL_FREQ
+  /* Set GC_full_freq to the desired value at start-up */
+# define GC_INIT_CONF_FULL_FREQ GC_set_full_freq(GC_FULL_FREQ)
+#else
+# define GC_INIT_CONF_FULL_FREQ /* empty */
+#endif
+
+#ifdef GC_TIME_LIMIT
+  /* Set GC_time_limit to the desired value at start-up */
+# define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT)
+#else
+# define GC_INIT_CONF_TIME_LIMIT /* empty */
+#endif
+
+#ifdef GC_IGNORE_WARN
+  /* Turn off all warnings at start-up (after GC initialization) */
+# define GC_INIT_CONF_IGNORE_WARN GC_set_warn_proc(GC_ignore_warn_proc)
+#else
+# define GC_INIT_CONF_IGNORE_WARN /* empty */
+#endif
+
+#ifdef GC_INITIAL_HEAP_SIZE
+  /* Set heap size to the desired value at start-up */
+# define GC_INIT_CONF_INITIAL_HEAP_SIZE \
+		{ size_t heap_size = GC_get_heap_size(); \
+		  if (heap_size < (GC_INITIAL_HEAP_SIZE)) \
+                    (void)GC_expand_hp((GC_INITIAL_HEAP_SIZE) - heap_size); }
+#else
+# define GC_INIT_CONF_INITIAL_HEAP_SIZE /* empty */
+#endif
+
+#define GC_INIT() { GC_INIT_CONF_DONT_EXPAND; \
+		    GC_INIT_CONF_MAX_RETRIES; \
+		    GC_INIT_CONF_FREE_SPACE_DIVISOR; \
+		    GC_INIT_CONF_FULL_FREQ; \
+		    GC_INIT_CONF_TIME_LIMIT; \
+		  GC_init(); GC_INIT_CONF_ROOTS; \
+		    GC_INIT_CONF_IGNORE_WARN; \
+		    GC_INIT_CONF_INITIAL_HEAP_SIZE; }
+
   /* win32S may not free all resources on process exit.  */
   /* This explicitly deallocates the heap.		 */
 GC_API void GC_CALL GC_win32_free_heap(void);
diff -ru bdwgc/include/private/gc_priv.h updated/bdwgc/include/private/gc_priv.h
--- bdwgc/include/private/gc_priv.h	2008-11-11 15:39:56.000000000 +0300
+++ updated/bdwgc/include/private/gc_priv.h	2008-11-17 13:22:32.000000000 +0300
@@ -179,9 +179,6 @@
 #   define MAXHINCR 4096
 # endif
 
-# define TIME_LIMIT 50	   /* We try to keep pause times from exceeding	 */
-			   /* this by much. In milliseconds.		 */
-
 # define BL_LIMIT GC_black_list_spacing
 			   /* If we need a block of N bytes, and we have */
 			   /* a block of N + BL_LIMIT bytes available, 	 */
diff -ru bdwgc/mark.c updated/bdwgc/mark.c
--- bdwgc/mark.c	2008-11-07 16:48:36.000000000 +0300
+++ updated/bdwgc/mark.c	2008-11-17 12:31:36.000000000 +0300
@@ -779,7 +779,9 @@
     credit -= limit - current_p;
     limit -= sizeof(word);
     {
-#     define PREF_DIST 4
+#     ifndef PREF_DIST
+#	define PREF_DIST 4
+#     endif
 
 #     ifndef SMALL_CONFIG
         word deferred;
@@ -944,7 +946,9 @@
 STATIC void GC_do_local_mark(mse *local_mark_stack, mse *local_top)
 {
     unsigned n;
-#   define N_LOCAL_ITERS 1
+#   ifndef N_LOCAL_ITERS
+#    define N_LOCAL_ITERS 1
+#   endif
 
 #   ifdef GC_ASSERTIONS
       /* Make sure we don't hold mark lock. */
@@ -982,7 +986,9 @@
     }
 }
 
-#define ENTRIES_TO_GET 5
+#ifndef ENTRIES_TO_GET
+# define ENTRIES_TO_GET 5
+#endif
 
 long GC_markers = 2;		/* Normally changed by thread-library-	*/
 				/* -specific code.			*/
diff -ru bdwgc/misc.c updated/bdwgc/misc.c
--- bdwgc/misc.c	2008-11-08 22:16:13.000000000 +0300
+++ updated/bdwgc/misc.c	2008-11-17 13:42:04.000000000 +0300
@@ -467,7 +467,12 @@
 #   if !defined(THREADS) && defined(GC_ASSERTIONS)
         word dummy;
 #   endif
-    word initial_heap_sz = (word)MINHINCR;
+
+#   ifdef GC_INITIAL_HEAP_SIZE
+	word initial_heap_sz = divHBLKSZ(GC_INITIAL_HEAP_SIZE);
+#   else
+	word initial_heap_sz = (word)MINHINCR;
+#   endif
     
     if (GC_is_initialized) return;
 
@@ -565,18 +570,28 @@
 #	endif
       }
     }
-    {
-      char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
-      if (0 != time_limit_string) {
-        long time_limit = atol(time_limit_string);
-        if (time_limit < 5) {
-	  WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
-	       "or bad syntax: Ignoring\n", 0);
-        } else {
-	  GC_time_limit = time_limit;
-        }
+#   ifndef SMALL_CONFIG
+      {
+	char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
+	if (0 != time_limit_string) {
+	  long time_limit = atol(time_limit_string);
+	  if (time_limit < 5) {
+	    WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
+		 "or bad syntax: Ignoring\n", 0);
+	  } else {
+	    GC_time_limit = time_limit;
+	  }
+	}
       }
-    }
+      {
+	char * full_freq_string = GETENV("GC_FULL_FREQUENCY");
+	if (full_freq_string != NULL) {
+	  int full_freq = atoi(full_freq_string);
+	  if (full_freq > 0)
+	    GC_full_freq = full_freq;
+	}
+      }
+#   endif
     {
       char * interval_string = GETENV("GC_LARGE_ALLOC_WARN_INTERVAL");
       if (0 != interval_string) {
@@ -699,7 +714,6 @@
 	    WARN("Bad maximum heap size %s - ignoring it.\n",
 		 sz_str);
 	  } 
-	  if (0 == GC_max_retries) GC_max_retries = 2;
 	  GC_set_max_heap_size(max_heap_sz);
 	}
     }
@@ -1037,18 +1051,23 @@
 
 GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
 
+/* This is recommended for production code (release). */
+GC_API void GC_CALLBACK GC_ignore_warn_proc(char *msg, GC_word arg)
+{
+    if (GC_print_stats) {
+      /* Don't ignore warnings if stats printing is on. */
+      GC_default_warn_proc(msg, arg);
+    }
+}
+
 GC_API GC_warn_proc GC_CALL GC_set_warn_proc(GC_warn_proc p)
 {
     GC_warn_proc result;
 
-#   ifdef GC_WIN32_THREADS
-      GC_ASSERT(GC_is_initialized);
-#   endif
-    LOCK();
     result = GC_current_warn_proc;
     if (p != (GC_warn_proc)0)
 	GC_current_warn_proc = p;
-    UNLOCK();
+
     return(result);
 }
 
@@ -1264,3 +1283,19 @@
 	GC_dont_precollect = value;
     return ovalue;
 }
+
+GC_API int GC_CALL GC_set_full_freq(int value)
+{
+    int ovalue = GC_full_freq;
+    if (value != -1)
+	GC_full_freq = value;
+    return ovalue;
+}
+
+GC_API unsigned long GC_CALL GC_set_time_limit(unsigned long value)
+{
+    unsigned long ovalue = GC_time_limit;
+    if (value != (unsigned long)-1L)
+	GC_time_limit = value;
+    return ovalue;
+}


More information about the Gc mailing list