Permalink
Browse files

[sgen] Just warn, don't abort, on invalid MONO_GC_PARAM or MONO_GC_DE…

…BUG options.
  • Loading branch information...
1 parent d9ae8c5 commit 18d7a36fdd6e01fbc05bdb8eb0e3ee2a0ff7f9ce @schani schani committed Mar 6, 2013
Showing with 124 additions and 75 deletions.
  1. +112 −69 mono/metadata/sgen-gc.c
  2. +8 −2 mono/metadata/sgen-gc.h
  3. +4 −4 mono/metadata/sgen-memory-governor.c
View
@@ -4748,7 +4748,40 @@ is_critical_method (MonoMethod *method)
{
return mono_runtime_is_critical_method (method) || sgen_is_critical_method (method);
}
-
+
+void
+sgen_env_var_error (const char *env_var, const char *fallback, const char *description_format, ...)
+{
+ va_list ap;
+
+ va_start (ap, description_format);
+
+ fprintf (stderr, "Warning: In environment variable `%s': ", env_var);
+ vfprintf (stderr, description_format, ap);
+ if (fallback)
+ fprintf (stderr, " - %s", fallback);
+ fprintf (stderr, "\n");
+
+ va_end (ap);
+}
+
+static gboolean
+parse_double_in_interval (const char *env_var, const char *opt_name, const char *opt, double min, double max, double *result)
+{
+ char *endptr;
+ double val = strtod (opt, &endptr);
+ if (endptr == opt) {
+ sgen_env_var_error (env_var, "Using default value.", "`%s` must be a number.", opt_name);
+ return FALSE;
+ }
+ else if (val < min || val > max) {
+ sgen_env_var_error (env_var, "Using default value.", "`%s` must be between %.2f - %.2f.", opt_name, min, max);
+ return FALSE;
+ }
+ *result = val;
+ return TRUE;
+}
+
void
mono_gc_base_init (void)
{
@@ -4805,7 +4838,7 @@ mono_gc_base_init (void)
init_user_copy_or_mark_key ();
- if ((env = getenv ("MONO_GC_PARAMS"))) {
+ if ((env = getenv (MONO_GC_PARAMS_NAME))) {
opts = g_strsplit (env, ",", -1);
for (ptr = opts; *ptr; ++ptr) {
char *opt = *ptr;
@@ -4847,17 +4880,19 @@ mono_gc_base_init (void)
sgen_simple_nursery_init (&sgen_minor_collector);
} else {
if (!strcmp (minor_collector_opt, "simple")) {
+ use_simple_nursery:
sgen_simple_nursery_init (&sgen_minor_collector);
} else if (!strcmp (minor_collector_opt, "split")) {
sgen_split_nursery_init (&sgen_minor_collector);
have_split_nursery = TRUE;
} else {
- fprintf (stderr, "Unknown minor collector `%s'.\n", minor_collector_opt);
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using `simple` instead.", "Unknown minor collector `%s'.", minor_collector_opt);
+ goto use_simple_nursery;
}
}
if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep")) {
+ use_marksweep_major:
sgen_marksweep_init (&major_collector);
} else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-fixed")) {
sgen_marksweep_fixed_init (&major_collector);
@@ -4868,13 +4903,13 @@ mono_gc_base_init (void)
} else if (!major_collector_opt || !strcmp (major_collector_opt, "marksweep-conc")) {
sgen_marksweep_conc_init (&major_collector);
} else {
- fprintf (stderr, "Unknown major collector `%s'.\n", major_collector_opt);
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using `marksweep` instead.", "Unknown major collector `%s'.", major_collector_opt);
+ goto use_marksweep_major;
}
if (have_split_nursery && major_collector.is_parallel) {
- fprintf (stderr, "Split nursery is not supported with the parallel collector yet.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Disabling split minor collector.", "`minor=split` is not supported with the parallel collector yet.");
+ have_split_nursery = FALSE;
}
num_workers = mono_cpu_count ();
@@ -4889,6 +4924,8 @@ mono_gc_base_init (void)
sgen_nursery_size = DEFAULT_NURSERY_SIZE;
if (opts) {
+ gboolean usage_printed = FALSE;
+
for (ptr = opts; *ptr; ++ptr) {
char *opt = *ptr;
if (!strcmp (opt, ""))
@@ -4898,47 +4935,45 @@ mono_gc_base_init (void)
if (g_str_has_prefix (opt, "minor="))
continue;
if (g_str_has_prefix (opt, "max-heap-size=")) {
+ glong max_heap_candidate = 0;
opt = strchr (opt, '=') + 1;
- if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) {
- if ((max_heap & (mono_pagesize () - 1))) {
- fprintf (stderr, "max-heap-size size must be a multiple of %d.\n", mono_pagesize ());
- exit (1);
- }
+ if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap_candidate)) {
+ max_heap = (max_heap_candidate + mono_pagesize () - 1) & ~(glong)(mono_pagesize () - 1);
+ if (max_heap != max_heap_candidate)
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Rounding up.", "`max-heap-size` size must be a multiple of %d.", mono_pagesize ());
} else {
- fprintf (stderr, "max-heap-size must be an integer.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, NULL, "`max-heap-size` must be an integer.");
}
continue;
}
if (g_str_has_prefix (opt, "soft-heap-limit=")) {
opt = strchr (opt, '=') + 1;
if (*opt && mono_gc_parse_environment_string_extract_number (opt, &soft_limit)) {
if (soft_limit <= 0) {
- fprintf (stderr, "soft-heap-limit must be positive.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, NULL, "`soft-heap-limit` must be positive.");
+ soft_limit = 0;
}
} else {
- fprintf (stderr, "soft-heap-limit must be an integer.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, NULL, "`soft-heap-limit` must be an integer.");
}
continue;
}
if (g_str_has_prefix (opt, "workers=")) {
long val;
char *endptr;
if (!major_collector.is_parallel) {
- fprintf (stderr, "The workers= option can only be used for parallel collectors.");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "The `workers` option can only be used for parallel collectors.");
+ continue;
}
opt = strchr (opt, '=') + 1;
val = strtol (opt, &endptr, 10);
if (!*opt || *endptr) {
- fprintf (stderr, "Cannot parse the workers= option value.");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "Cannot parse the `workers` option value.");
+ continue;
}
if (val <= 0 || val > 16) {
- fprintf (stderr, "The number of workers must be in the range 1 to 16.");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.", "The number of `workers` must be in the range 1 to 16.");
+ continue;
}
num_workers = (int)val;
continue;
@@ -4950,8 +4985,8 @@ mono_gc_base_init (void)
} else if (!strcmp (opt, "conservative")) {
conservative_stack_mark = TRUE;
} else {
- fprintf (stderr, "Invalid value '%s' for stack-mark= option, possible values are: 'precise', 'conservative'.\n", opt);
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, conservative_stack_mark ? "Using `conservative`." : "Using `precise`.",
+ "Invalid value `%s` for `stack-mark` option, possible values are: `precise`, `conservative`.", opt);
}
continue;
}
@@ -4965,61 +5000,53 @@ mono_gc_base_init (void)
long val;
opt = strchr (opt, '=') + 1;
if (*opt && mono_gc_parse_environment_string_extract_number (opt, &val)) {
- sgen_nursery_size = val;
#ifdef SGEN_ALIGN_NURSERY
if ((val & (val - 1))) {
- fprintf (stderr, "The nursery size must be a power of two.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.", "`nursery-size` must be a power of two.");
+ continue;
}
if (val < SGEN_MAX_NURSERY_WASTE) {
- fprintf (stderr, "The nursery size must be at least %d bytes.\n", SGEN_MAX_NURSERY_WASTE);
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.",
+ "`nursery-size` must be at least %d bytes.\n", SGEN_MAX_NURSERY_WASTE);
+ continue;
}
+ sgen_nursery_size = val;
sgen_nursery_bits = 0;
while (1 << (++ sgen_nursery_bits) != sgen_nursery_size)
;
+#else
+ sgen_nursery_size = val;
#endif
} else {
- fprintf (stderr, "nursery-size must be an integer.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.", "`nursery-size` must be an integer.");
+ continue;
}
continue;
}
#endif
if (g_str_has_prefix (opt, "save-target-ratio=")) {
- char *endptr;
+ double val;
opt = strchr (opt, '=') + 1;
- save_target = strtod (opt, &endptr);
- if (endptr == opt) {
- fprintf (stderr, "save-target-ratio must be a number.");
- exit (1);
- }
- if (save_target < SGEN_MIN_SAVE_TARGET_RATIO || save_target > SGEN_MAX_SAVE_TARGET_RATIO) {
- fprintf (stderr, "save-target-ratio must be between %.2f - %.2f.", SGEN_MIN_SAVE_TARGET_RATIO, SGEN_MAX_SAVE_TARGET_RATIO);
- exit (1);
+ if (parse_double_in_interval (MONO_GC_PARAMS_NAME, "save-target-ratio", opt,
+ SGEN_MIN_SAVE_TARGET_RATIO, SGEN_MAX_SAVE_TARGET_RATIO, &val)) {
+ save_target = val;
}
continue;
}
if (g_str_has_prefix (opt, "default-allowance-ratio=")) {
- char *endptr;
+ double val;
opt = strchr (opt, '=') + 1;
-
- allowance_ratio = strtod (opt, &endptr);
- if (endptr == opt) {
- fprintf (stderr, "save-target-ratio must be a number.");
- exit (1);
- }
- if (allowance_ratio < SGEN_MIN_ALLOWANCE_NURSERY_SIZE_RATIO || allowance_ratio > SGEN_MIN_ALLOWANCE_NURSERY_SIZE_RATIO) {
- fprintf (stderr, "default-allowance-ratio must be between %.2f - %.2f.", SGEN_MIN_ALLOWANCE_NURSERY_SIZE_RATIO, SGEN_MIN_ALLOWANCE_NURSERY_SIZE_RATIO);
- exit (1);
+ if (parse_double_in_interval (MONO_GC_PARAMS_NAME, "default-allowance-ratio", opt,
+ SGEN_MIN_ALLOWANCE_NURSERY_SIZE_RATIO, SGEN_MIN_ALLOWANCE_NURSERY_SIZE_RATIO, &val)) {
+ allowance_ratio = val;
}
continue;
}
if (g_str_has_prefix (opt, "allow-synchronous-major=")) {
if (!major_collector.is_concurrent) {
- fprintf (stderr, "Warning: allow-synchronous-major has no effect because the major collector is not concurrent.\n");
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "`allow-synchronous-major` is only valid for the concurrent major collector.");
continue;
}
@@ -5030,8 +5057,8 @@ mono_gc_base_init (void)
} else if (!strcmp (opt, "no")) {
allow_synchronous_major = FALSE;
} else {
- fprintf (stderr, "allow-synchronous-major must be either `yes' or `no'.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Using default value.", "`allow-synchronous-major` must be either `yes' or `no'.");
+ continue;
}
}
@@ -5050,7 +5077,12 @@ mono_gc_base_init (void)
if (sgen_minor_collector.handle_gc_param && sgen_minor_collector.handle_gc_param (opt))
continue;
- fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n");
+ sgen_env_var_error (MONO_GC_PARAMS_NAME, "Ignoring.", "Unknown option `%s`.", opt);
+
+ if (usage_printed)
+ continue;
+
+ fprintf (stderr, "\n%s must be a comma-delimited list of one or more of the following:\n", MONO_GC_PARAMS_NAME);
fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
fprintf (stderr, " soft-heap-limit=n (where N is an integer, possibly with a k, m or a g suffix)\n");
fprintf (stderr, " nursery-size=N (where N is an integer, possibly with a k, m or a g suffix)\n");
@@ -5068,7 +5100,9 @@ mono_gc_base_init (void)
fprintf (stderr, " Experimental options:\n");
fprintf (stderr, " save-target-ratio=R (where R must be between %.2f - %.2f).\n", SGEN_MIN_SAVE_TARGET_RATIO, SGEN_MAX_SAVE_TARGET_RATIO);
fprintf (stderr, " default-allowance-ratio=R (where R must be between %.2f - %.2f).\n", SGEN_MIN_ALLOWANCE_NURSERY_SIZE_RATIO, SGEN_MAX_ALLOWANCE_NURSERY_SIZE_RATIO);
- exit (1);
+ fprintf (stderr, "\n");
+
+ usage_printed = TRUE;
}
g_strfreev (opts);
}
@@ -5088,7 +5122,9 @@ mono_gc_base_init (void)
sgen_cement_init (cement_enabled);
- if ((env = getenv ("MONO_GC_DEBUG"))) {
+ if ((env = getenv (MONO_GC_DEBUG_NAME))) {
+ gboolean usage_printed = FALSE;
+
opts = g_strsplit (env, ",", -1);
for (ptr = opts; ptr && *ptr; ptr ++) {
char *opt = *ptr;
@@ -5149,8 +5185,8 @@ mono_gc_base_init (void)
do_verify_nursery = TRUE;
} else if (!strcmp (opt, "check-concurrent")) {
if (!major_collector.is_concurrent) {
- fprintf (stderr, "Error: check-concurrent only world with concurrent major collectors.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_DEBUG_NAME, "Ignoring.", "`check-concurrent` only works with concurrent major collectors.");
+ continue;
}
do_concurrent_checks = TRUE;
} else if (!strcmp (opt, "dump-nursery-at-minor-gc")) {
@@ -5175,9 +5211,13 @@ mono_gc_base_init (void)
binary_protocol_init (filename);
#endif
} else {
- fprintf (stderr, "Invalid format for the MONO_GC_DEBUG env variable: '%s'\n", env);
- fprintf (stderr, "The format is: MONO_GC_DEBUG=[l[:filename]|<option>]+ where l is a debug level 0-9.\n");
- fprintf (stderr, "Valid options are:\n");
+ sgen_env_var_error (MONO_GC_DEBUG_NAME, "Ignoring.", "Unknown option `%s`.", opt);
+
+ if (usage_printed)
+ continue;
+
+ fprintf (stderr, "\n%s must be of the format [<l>[:<filename>]|<option>]+ where <l> is a debug level 0-9.\n", MONO_GC_DEBUG_NAME);
+ fprintf (stderr, "Valid <option>s are:\n");
fprintf (stderr, " collect-before-allocs[=<n>]\n");
fprintf (stderr, " verify-before-allocs[=<n>]\n");
fprintf (stderr, " check-at-minor-collections\n");
@@ -5200,20 +5240,23 @@ mono_gc_base_init (void)
#ifdef SGEN_BINARY_PROTOCOL
fprintf (stderr, " binary-protocol=<filename>\n");
#endif
- exit (1);
+ fprintf (stderr, "\n");
+
+ usage_printed = TRUE;
}
}
g_strfreev (opts);
}
if (major_collector.is_parallel) {
if (heap_dump_file) {
- fprintf (stderr, "Error: Cannot do heap dump with the parallel collector.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_DEBUG_NAME, "Disabling.", "Cannot do `heap-dump` with the parallel collector.");
+ fclose (heap_dump_file);
+ heap_dump_file = NULL;
}
if (do_pin_stats) {
- fprintf (stderr, "Error: Cannot gather pinning statistics with the parallel collector.\n");
- exit (1);
+ sgen_env_var_error (MONO_GC_DEBUG_NAME, "Disabling.", "`print-pinning` is not supported with the parallel collector.");
+ do_pin_stats = FALSE;
}
}
View
@@ -464,8 +464,6 @@ void sgen_free_internal (void *addr, int type) MONO_INTERNAL;
void* sgen_alloc_internal_dynamic (size_t size, int type, gboolean assert_on_failure) MONO_INTERNAL;
void sgen_free_internal_dynamic (void *addr, size_t size, int type) MONO_INTERNAL;
-gboolean sgen_parse_environment_string_extract_number (const char *str, glong *out) MONO_INTERNAL;
-
void** sgen_find_optimized_pin_queue_area (void *start, void *end, int *num) MONO_INTERNAL;
void sgen_find_section_pin_queue_start_end (GCMemSection *section) MONO_INTERNAL;
void sgen_pin_objects_in_section (GCMemSection *section, ScanCopyContext ctx) MONO_INTERNAL;
@@ -1023,6 +1021,14 @@ sgen_dummy_use (gpointer v) {
#endif
}
+/* Environment variable parsing */
+
+#define MONO_GC_PARAMS_NAME "MONO_GC_PARAMS"
+#define MONO_GC_DEBUG_NAME "MONO_GC_DEBUG"
+
+gboolean sgen_parse_environment_string_extract_number (const char *str, glong *out) MONO_INTERNAL;
+void sgen_env_var_error (const char *env_var, const char *fallback, const char *description_format, ...) MONO_INTERNAL;
+
#endif /* HAVE_SGEN_GC */
#endif /* __MONO_SGENGC_H__ */
Oops, something went wrong.

0 comments on commit 18d7a36

Please sign in to comment.