diff options
Diffstat (limited to 'libguile/whippet/src/gc-options.c')
-rw-r--r-- | libguile/whippet/src/gc-options.c | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/libguile/whippet/src/gc-options.c b/libguile/whippet/src/gc-options.c new file mode 100644 index 000000000..31de02745 --- /dev/null +++ b/libguile/whippet/src/gc-options.c @@ -0,0 +1,198 @@ +#include <limits.h> +#include <malloc.h> +#include <stdlib.h> +#include <string.h> + +#define GC_IMPL 1 + +#include "gc-options-internal.h" +#include "gc-platform.h" + +// M(UPPER, lower, repr, type, parser, default, min, max) +#define FOR_EACH_INT_GC_OPTION(M) \ + M(HEAP_SIZE_POLICY, heap_size_policy, "heap-size-policy", \ + int, heap_size_policy, GC_HEAP_SIZE_FIXED, GC_HEAP_SIZE_FIXED, \ + GC_HEAP_SIZE_ADAPTIVE) \ + M(PARALLELISM, parallelism, "parallelism", \ + int, int, default_parallelism(), 1, 64) + +#define FOR_EACH_SIZE_GC_OPTION(M) \ + M(HEAP_SIZE, heap_size, "heap-size", \ + size, size, 6 * 1024 * 1024, 0, -1) \ + M(MAXIMUM_HEAP_SIZE, maximum_heap_size, "maximum-heap-size", \ + size, size, 0, 0, -1) + +#define FOR_EACH_DOUBLE_GC_OPTION(M) \ + M(HEAP_SIZE_MULTIPLIER, heap_size_multiplier, "heap-size-multiplier", \ + double, double, 1.75, 1.0, 1e6) \ + M(HEAP_EXPANSIVENESS, heap_expansiveness, "heap-expansiveness", \ + double, double, 1.0, 0.0, 50.0) + +typedef int gc_option_int; +typedef size_t gc_option_size; +typedef double gc_option_double; + +#define FOR_EACH_COMMON_GC_OPTION(M) \ + FOR_EACH_INT_GC_OPTION(M) \ + FOR_EACH_SIZE_GC_OPTION(M) \ + FOR_EACH_DOUBLE_GC_OPTION(M) + +static int clamp_int(int n, int lo, int hi) { + return n < lo ? lo : n > hi ? hi : n; +} +static size_t clamp_size(size_t n, size_t lo, size_t hi) { + return n < lo ? lo : n > hi ? hi : n; +} +static double clamp_double(double n, double lo, double hi) { + return n < lo ? lo : n > hi ? hi : n; +} + +static int default_parallelism(void) { + return clamp_int(gc_platform_processor_count(), 1, 8); +} + +void gc_init_common_options(struct gc_common_options *options) { +#define INIT(UPPER, lower, repr, type, parser, default, min, max) \ + options->lower = default; + FOR_EACH_COMMON_GC_OPTION(INIT) +#undef INIT +} + +int gc_common_option_from_string(const char *str) { +#define GET_OPTION(UPPER, lower, repr, type, parser, default, min, max) \ + if (strcmp(str, repr) == 0) return GC_OPTION_##UPPER; + FOR_EACH_COMMON_GC_OPTION(GET_OPTION) +#undef GET_OPTION + return -1; +} + +#define SET_OPTION(UPPER, lower, repr, type, parser, default, min, max) \ + case GC_OPTION_##UPPER: \ + if (value != clamp_##type(value, min, max)) return 0; \ + options->lower = value; \ + return 1; +#define DEFINE_SETTER(STEM, stem, type) \ + int gc_common_options_set_##stem(struct gc_common_options *options, \ + int option, type value) { \ + switch (option) { \ + FOR_EACH_##STEM##_GC_OPTION(SET_OPTION) \ + default: return 0; \ + } \ + } +DEFINE_SETTER(INT, int, int) +DEFINE_SETTER(SIZE, size, size_t) +DEFINE_SETTER(DOUBLE, double, double) +#undef SET_OPTION +#undef DEFINE_SETTER + +static int parse_size(const char *arg, size_t *val) { + char *end; + long i = strtol(arg, &end, 0); + if (i < 0 || i == LONG_MAX) return 0; + if (end == arg) return 0; + char delim = *end; + if (delim == 'k' || delim == 'K') + ++end, i *= 1024L; + else if (delim == 'm' || delim == 'M') + ++end, i *= 1024L * 1024L; + else if (delim == 'g' || delim == 'G') + ++end, i *= 1024L * 1024L * 1024L; + else if (delim == 't' || delim == 'T') + ++end, i *= 1024L * 1024L * 1024L * 1024L; + + if (*end != '\0') return 0; + *val = i; + return 1; +} + +static int parse_int(const char *arg, int *val) { + char *end; + long i = strtol(arg, &end, 0); + if (i == LONG_MIN || i == LONG_MAX || end == arg || *end) + return 0; + *val = i; + return 1; +} + +static int parse_heap_size_policy(const char *arg, int *val) { + if (strcmp(arg, "fixed") == 0) { + *val = GC_HEAP_SIZE_FIXED; + return 1; + } + if (strcmp(arg, "growable") == 0) { + *val = GC_HEAP_SIZE_GROWABLE; + return 1; + } + if (strcmp(arg, "adaptive") == 0) { + *val = GC_HEAP_SIZE_ADAPTIVE; + return 1; + } + return parse_int(arg, val); +} + +static int parse_double(const char *arg, double *val) { + char *end; + double d = strtod(arg, &end); + if (end == arg || *end) + return 0; + *val = d; + return 1; +} + +int gc_common_options_parse_and_set(struct gc_common_options *options, + int option, const char *value) { + switch (option) { +#define SET_OPTION(UPPER, lower, repr, type, parser, default, min, max) \ + case GC_OPTION_##UPPER: { \ + gc_option_##type v; \ + if (!parse_##parser(value, &v)) return 0; \ + return gc_common_options_set_##type(options, option, v); \ + } + FOR_EACH_COMMON_GC_OPTION(SET_OPTION) + default: return 0; + } +} + +static int is_lower(char c) { return 'a' <= c && c <= 'z'; } +static int is_digit(char c) { return '0' <= c && c <= '9'; } +static int is_option(char c) { return is_lower(c) || c == '-'; } +static int is_option_end(char c) { return c == '='; } +static int is_value(char c) { + return is_lower(c) || is_digit(c) || c == '-' || c == '+' || c == '.'; +} +static int is_value_end(char c) { return c == '\0' || c == ','; } +static char* read_token(char *p, int (*is_tok)(char c), int (*is_end)(char c), + char *delim) { + char c; + for (c = *p; is_tok(c); c = *++p); + if (!is_end(c)) return NULL; + *delim = c; + *p = '\0'; + return p + 1; +} +int gc_options_parse_and_set_many(struct gc_options *options, + const char *str) { + if (!*str) return 1; + char *copy = strdup(str); + char *cur = copy; + int ret = 0; + while (1) { + char delim; + char *next = read_token(cur, is_option, is_option_end, &delim); + if (!next) break; + int option = gc_option_from_string(cur); + if (option < 0) break; + + cur = next; + next = read_token(cur, is_value, is_value_end, &delim); + if (!next) break; + if (!gc_options_parse_and_set(options, option, cur)) break; + cur = next; + if (delim == '\0') { + ret = 1; + break; + } + } + free(copy); + return ret; +} |