[svn:parrot] r49092 - in trunk: include/parrot src src/gc src/interp

nwellnhof at svn.parrot.org nwellnhof at svn.parrot.org
Fri Sep 17 22:17:25 UTC 2010


Author: nwellnhof
Date: Fri Sep 17 22:17:24 2010
New Revision: 49092
URL: https://trac.parrot.org/parrot/changeset/49092

Log:
[gc] Command line option for dynamic GC threshold

The dynamic threshold roughly limits the memory wasted by objects that
could be freed but are not yet collected to a percentage of total memory
that is actually needed. Default is 25, maximum is 1000. Increasing the
dynamic threshold results in fewer GC runs and more memory consumption.

Usage:

parrot --gc-threshold=50
parrot --gc-threshold=200

Modified:
   trunk/include/parrot/gc_api.h
   trunk/include/parrot/interpreter.h
   trunk/include/parrot/longopt.h
   trunk/src/gc/gc_ms.c
   trunk/src/gc/gc_private.h
   trunk/src/gc/string_gc.c
   trunk/src/interp/inter_create.c
   trunk/src/longopt.c
   trunk/src/main.c

Modified: trunk/include/parrot/gc_api.h
==============================================================================
--- trunk/include/parrot/gc_api.h	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/include/parrot/gc_api.h	Fri Sep 17 22:17:24 2010	(r49092)
@@ -33,6 +33,8 @@
 
 #define ALIGNED_STRING_SIZE(len) (((len) + sizeof (void*) + WORD_ALIGN_1) & WORD_ALIGN_MASK)
 
+#define GC_DYNAMIC_THRESHOLD_DEFAULT 25
+
 /* pool iteration */
 typedef enum {
     POOL_PMC    = 0x01,

Modified: trunk/include/parrot/interpreter.h
==============================================================================
--- trunk/include/parrot/interpreter.h	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/include/parrot/interpreter.h	Fri Sep 17 22:17:24 2010	(r49092)
@@ -172,6 +172,8 @@
 
     struct GC_Subsystem *gc_sys;              /*functions and data specific
                                                   to current GC subsystem*/
+    UINTVAL gc_threshold;                     /* maximum percentage of memory
+                                                 wasted by GC */
 
     PMC *gc_registry;                         /* root set of registered PMCs */
 

Modified: trunk/include/parrot/longopt.h
==============================================================================
--- trunk/include/parrot/longopt.h	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/include/parrot/longopt.h	Fri Sep 17 22:17:24 2010	(r49092)
@@ -46,6 +46,7 @@
 #define OPT_PBC_OUTPUT     131
 #define OPT_RUNTIME_PREFIX 132
 #define OPT_HASH_SEED      133
+#define OPT_GC_THRESHOLD   134
 
 /* HEADERIZER BEGIN: src/longopt.c */
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */

Modified: trunk/src/gc/gc_ms.c
==============================================================================
--- trunk/src/gc/gc_ms.c	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/src/gc/gc_ms.c	Fri Sep 17 22:17:24 2010	(r49092)
@@ -486,6 +486,46 @@
     Memory_Pools * const source_arena = source_interp->mem_pools;
     Parrot_gc_merge_memory_pools(dest_interp, dest_arena, source_arena);
 }
+
+/*
+
+=item C<int Parrot_gc_ms_needed(PARROT_INTERP)>
+
+Determines whether a GC run is needed. The decision is based on the amount
+of memory used since the last GC run. This amount is compared to a static
+and a dynamic threshold. The dynamic threshold roughly limits the memory
+wasted by objects that could be freed but are not yet collected to a
+percentage of total memory that is actually needed.
+
+Increasing the dynamic threshold results in fewer GC runs and more memory
+consumption.
+
+=cut
+
+*/
+
+int
+Parrot_gc_ms_needed(PARROT_INTERP)
+{
+    const Memory_Pools * const mem_pools = interp->mem_pools;
+    size_t dynamic_threshold;
+
+    /* new_mem is the additional amount of memory used since the last GC */
+    size_t new_mem = mem_pools->memory_used
+                   - mem_pools->mem_used_last_collect;
+
+    /* Never run a GC if new_mem is below static GC_SIZE_THRESHOLD */
+    if (new_mem <= GC_SIZE_THRESHOLD)
+        return 0;
+
+    /* The dynamic threshold is a configurable percentage of the amount of
+       memory used after the last GC */
+    dynamic_threshold = (size_t)(mem_pools->mem_used_last_collect *
+                                 (0.01 * interp->gc_threshold));
+
+    return new_mem > dynamic_threshold;
+}
+
 /*
 
 =item C<static void gc_ms_mark_and_sweep(PARROT_INTERP, UINTVAL flags)>
@@ -1345,15 +1385,12 @@
         ARGMOD(Fixed_Size_Pool *pool))
 {
     ASSERT_ARGS(gc_ms_more_traceable_objects)
-    size_t new_mem = mem_pools->memory_used
-                   - mem_pools->mem_used_last_collect;
 
     if (pool->skip == GC_ONE_SKIP)
         pool->skip = GC_NO_SKIP;
     else if (pool->skip == GC_NEVER_SKIP
          || (pool->skip == GC_NO_SKIP
-         && (new_mem > (mem_pools->mem_used_last_collect >> 2)
-         &&  new_mem >= GC_SIZE_THRESHOLD)))
+         &&  Parrot_gc_ms_needed(interp)))
             Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG);
 
     /* requires that num_free_objects be updated in Parrot_gc_mark_and_sweep.

Modified: trunk/src/gc/gc_private.h
==============================================================================
--- trunk/src/gc/gc_private.h	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/src/gc/gc_private.h	Fri Sep 17 22:17:24 2010	(r49092)
@@ -612,6 +612,9 @@
 void Parrot_gc_ms_init(PARROT_INTERP)
         __attribute__nonnull__(1);
 
+int Parrot_gc_ms_needed(PARROT_INTERP)
+        __attribute__nonnull__(1);
+
 #define ASSERT_ARGS_gc_ms_allocate_buffer_storage __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp) \
     , PARROT_ASSERT_ARG(str))
@@ -643,6 +646,8 @@
     , PARROT_ASSERT_ARG(str))
 #define ASSERT_ARGS_Parrot_gc_ms_init __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(interp))
+#define ASSERT_ARGS_Parrot_gc_ms_needed __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(interp))
 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END.  Your changes will be lost. */
 /* HEADERIZER END: src/gc/gc_ms.c */
 

Modified: trunk/src/gc/string_gc.c
==============================================================================
--- trunk/src/gc/string_gc.c	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/src/gc/string_gc.c	Fri Sep 17 22:17:24 2010	(r49092)
@@ -662,11 +662,8 @@
          * TODO pass required allocation size to the GC system,
          *      so that collection can be skipped if needed
          */
-        size_t new_mem = mem_pools->memory_used -
-                         mem_pools->mem_used_last_collect;
         if (!mem_pools->gc_mark_block_level
-            && new_mem > (mem_pools->mem_used_last_collect >> 2)
-            && new_mem > GC_SIZE_THRESHOLD) {
+        &&  Parrot_gc_ms_needed(interp)) {
             Parrot_gc_mark_and_sweep(interp, GC_trace_stack_FLAG);
 
             if (interp->gc_sys->sys_type != INF) {

Modified: trunk/src/interp/inter_create.c
==============================================================================
--- trunk/src/interp/inter_create.c	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/src/interp/inter_create.c	Fri Sep 17 22:17:24 2010	(r49092)
@@ -165,6 +165,7 @@
     interp->gc_sys->sys_type = parent
                                     ? parent->gc_sys->sys_type
                                     : PARROT_GC_DEFAULT_TYPE;
+    interp->gc_threshold     = GC_DYNAMIC_THRESHOLD_DEFAULT;
 
     /* Done. Return and be done with it */
     return interp;

Modified: trunk/src/longopt.c
==============================================================================
--- trunk/src/longopt.c	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/src/longopt.c	Fri Sep 17 22:17:24 2010	(r49092)
@@ -92,6 +92,7 @@
         { 'O', 'O', OPTION_optional_FLAG, { "--optimize" } },
         { 'R', 'R', OPTION_required_FLAG, { "--runcore" } },
         { 'g', 'g', OPTION_required_FLAG, { "--gc" } },
+        { '\0', OPT_GC_THRESHOLD, OPTION_required_FLAG, { "--gc-threshold" } },
         { 'V', 'V', (OPTION_flags)0, { "--version" } },
         { 'X', 'X', OPTION_required_FLAG, { "--dynext" } },
         { '\0', OPT_DESTROY_FLAG, (OPTION_flags)0,

Modified: trunk/src/main.c
==============================================================================
--- trunk/src/main.c	Fri Sep 17 20:55:57 2010	(r49091)
+++ trunk/src/main.c	Fri Sep 17 22:17:24 2010	(r49092)
@@ -39,6 +39,11 @@
 static void help_debug(void);
 PARROT_WARN_UNUSED_RESULT
 PARROT_PURE_FUNCTION
+static int is_all_digits(ARGIN(const char *s))
+        __attribute__nonnull__(1);
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_PURE_FUNCTION
 static int is_all_hex_digits(ARGIN(const char *s))
         __attribute__nonnull__(1);
 
@@ -74,6 +79,8 @@
 
 #define ASSERT_ARGS_help __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
 #define ASSERT_ARGS_help_debug __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
+#define ASSERT_ARGS_is_all_digits __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
+       PARROT_ASSERT_ARG(s))
 #define ASSERT_ARGS_is_all_hex_digits __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
        PARROT_ASSERT_ARG(s))
 #define ASSERT_ARGS_Parrot_version __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
@@ -159,6 +166,29 @@
 
 /*
 
+=item C<static int is_all_digits(const char *s)>
+
+Tests all characters in a string are decimal digits.
+Returns 1 if true, 0 as soon as a non-decimal found
+
+=cut
+
+*/
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_PURE_FUNCTION
+static int
+is_all_digits(ARGIN(const char *s))
+{
+    ASSERT_ARGS(is_all_hex_digits)
+    for (; *s; ++s)
+        if (!isdigit(*s))
+            return 0;
+    return 1;
+}
+
+/*
+
 =item C<static int is_all_hex_digits(const char *s)>
 
 Tests all characters in a string are hexadecimal digits.
@@ -278,6 +308,7 @@
     printf(
     "    -w --warnings\n"
     "    -G --no-gc\n"
+    "       --gc-threshold=percentage    maximum memory wasted by GC\n"
     "       --gc-debug\n"
     "       --leak-test|--destroy-at-end\n"
     "    -g --gc ms|inf set GC type\n"
@@ -367,6 +398,29 @@
             }
             break;
         }
+        else if (!strncmp(arg, "--gc-threshold", 14)) {
+
+            if ((arg = strrchr(arg, '=')))
+                ++arg;
+            else
+                arg = argv[++pos];
+
+            if (is_all_digits(arg)) {
+                interp->gc_threshold = strtoul(arg, NULL, 10);
+
+                if (interp->gc_threshold > 1000) {
+                    fprintf(stderr, "error: maximum GC threshold is 1000\n");
+                    exit(EXIT_FAILURE);
+                }
+            }
+            else {
+                fprintf(stderr, "error: invalid GC threshold specified:"
+                        "'%s'\n", arg);
+                exit(EXIT_FAILURE);
+            }
+            ++pos;
+            arg = argv[pos];
+        }
         else if (!strncmp(arg, "--hash-seed", 11)) {
 
             if ((arg = strrchr(arg, '=')))
@@ -444,6 +498,9 @@
           case 'g':
             /* Handled in parseflags_minimal */
             break;
+          case OPT_GC_THRESHOLD:
+            /* handled in parseflags_minimal */
+            break;
           case 't':
             if (opt.opt_arg && is_all_hex_digits(opt.opt_arg)) {
                 const unsigned long _temp = strtoul(opt.opt_arg, NULL, 16);


More information about the parrot-commits mailing list