[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