diff --git a/Makefile b/Makefile index 6f5652ad5..3cfc68013 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,9 @@ gc-platform.o: gc-platform.h gc-platform-$(PLATFORM).c gc-visibility.h gc-stack.o: gc-stack.c $(COMPILE) -o $@ -c $< +gc-options.o: gc-options.c gc-options.h gc-options-internal.h + $(COMPILE) -o $@ -c $< + gc-ephemeron-%.o: gc-ephemeron.c gc-ephemeron.h gc-ephemeron-internal.h %-embedder.h $(COMPILE) -include $*-embedder.h -o $@ -c $< @@ -51,98 +54,98 @@ bdw-%-gc.o: bdw.c %-embedder.h %.c $(COMPILE) -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 `pkg-config --cflags bdw-gc` -include $*-embedder.h -o $@ -c bdw.c bdw-%.o: bdw.c %.c $(COMPILE) -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -include bdw-attrs.h -o $@ -c $*.c -bdw-%: bdw-%.o bdw-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +bdw-%: bdw-%.o bdw-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) `pkg-config --libs bdw-gc` -o $@ $^ semi-%-gc.o: semi.c %-embedder.h large-object-space.h assert.h debug.h %.c $(COMPILE) -DGC_PRECISE_ROOTS=1 -include $*-embedder.h -o $@ -c semi.c semi-%.o: semi.c %.c $(COMPILE) -DGC_PRECISE_ROOTS=1 -include semi-attrs.h -o $@ -c $*.c -semi-%: semi-%.o semi-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +semi-%: semi-%.o semi-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_PRECISE_ROOTS=1 -include $*-embedder.h -o $@ -c whippet.c whippet-%.o: whippet.c %.c $(COMPILE) -DGC_PRECISE_ROOTS=1 -include whippet-attrs.h -o $@ -c $*.c -whippet-%: whippet-%.o whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +whippet-%: whippet-%.o whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ stack-conservative-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_CONSERVATIVE_ROOTS=1 -include $*-embedder.h -o $@ -c whippet.c stack-conservative-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_CONSERVATIVE_ROOTS=1 -include whippet-attrs.h -o $@ -c $*.c -stack-conservative-whippet-%: stack-conservative-whippet-%.o stack-conservative-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +stack-conservative-whippet-%: stack-conservative-whippet-%.o stack-conservative-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ heap-conservative-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -include $*-embedder.h -o $@ -c whippet.c heap-conservative-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -include whippet-attrs.h -o $@ -c $*.c -heap-conservative-whippet-%: heap-conservative-whippet-%.o heap-conservative-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +heap-conservative-whippet-%: heap-conservative-whippet-%.o heap-conservative-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ parallel-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h parallel-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_PRECISE_ROOTS=1 -include $*-embedder.h -o $@ -c whippet.c parallel-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_PRECISE_ROOTS=1 -include whippet-attrs.h -o $@ -c $*.c -parallel-whippet-%: parallel-whippet-%.o parallel-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +parallel-whippet-%: parallel-whippet-%.o parallel-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ stack-conservative-parallel-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_CONSERVATIVE_ROOTS=1 -include $*-embedder.h -o $@ -c whippet.c stack-conservative-parallel-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_CONSERVATIVE_ROOTS=1 -include whippet-attrs.h -o $@ -c $*.c -stack-conservative-parallel-whippet-%: stack-conservative-parallel-whippet-%.o stack-conservative-parallel-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +stack-conservative-parallel-whippet-%: stack-conservative-parallel-whippet-%.o stack-conservative-parallel-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ heap-conservative-parallel-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -include $*-embedder.h -o $@ -c whippet.c heap-conservative-parallel-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -DGC_FULLY_CONSERVATIVE=1 -include whippet-attrs.h -o $@ -c $*.c -heap-conservative-parallel-whippet-%: heap-conservative-parallel-whippet-%.o heap-conservative-parallel-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +heap-conservative-parallel-whippet-%: heap-conservative-parallel-whippet-%.o heap-conservative-parallel-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_GENERATIONAL=1 -DGC_PRECISE_ROOTS=1 -include $*-embedder.h -o $@ -c whippet.c generational-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_GENERATIONAL=1 -DGC_PRECISE_ROOTS=1 -include whippet-attrs.h -o $@ -c $*.c -generational-whippet-%: generational-whippet-%.o generational-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +generational-whippet-%: generational-whippet-%.o generational-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ stack-conservative-generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_GENERATIONAL=1 -DGC_CONSERVATIVE_ROOTS=1 -include $*-embedder.h -o $@ -c whippet.c stack-conservative-generational-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_GENERATIONAL=1 -DGC_CONSERVATIVE_ROOTS=1 -include whippet-attrs.h -o $@ -c $*.c -stack-conservative-generational-whippet-%: stack-conservative-generational-whippet-%.o stack-conservative-generational-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +stack-conservative-generational-whippet-%: stack-conservative-generational-whippet-%.o stack-conservative-generational-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ heap-conservative-generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h serial-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_GENERATIONAL=1 -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -include $*-embedder.h -o $@ -c whippet.c heap-conservative-generational-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_GENERATIONAL=1 -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -include whippet-attrs.h -o $@ -c $*.c -heap-conservative-generational-whippet-%: heap-conservative-generational-whippet-%.o heap-conservative-generational-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +heap-conservative-generational-whippet-%: heap-conservative-generational-whippet-%.o heap-conservative-generational-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ parallel-generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h parallel-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_PRECISE_ROOTS=1 -include $*-embedder.h -o $@ -c whippet.c parallel-generational-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_PRECISE_ROOTS=1 -include whippet-attrs.h -o $@ -c $*.c -parallel-generational-whippet-%: parallel-generational-whippet-%.o parallel-generational-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +parallel-generational-whippet-%: parallel-generational-whippet-%.o parallel-generational-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ stack-conservative-parallel-generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h parallel-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_CONSERVATIVE_ROOTS=1 -include $*-embedder.h -o $@ -c whippet.c stack-conservative-parallel-generational-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_CONSERVATIVE_ROOTS=1 -include whippet-attrs.h -o $@ -c $*.c -stack-conservative-parallel-generational-whippet-%: stack-conservative-parallel-generational-whippet-%.o stack-conservative-parallel-generational-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +stack-conservative-parallel-generational-whippet-%: stack-conservative-parallel-generational-whippet-%.o stack-conservative-parallel-generational-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ heap-conservative-parallel-generational-whippet-%-gc.o: whippet.c %-embedder.h large-object-space.h parallel-tracer.h assert.h debug.h heap-objects.h %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -include $*-embedder.h -o $@ -c whippet.c heap-conservative-parallel-generational-whippet-%.o: whippet.c %.c $(COMPILE) -DGC_PARALLEL=1 -DGC_GENERATIONAL=1 -DGC_CONSERVATIVE_ROOTS=1 -DGC_CONSERVATIVE_TRACE=1 -include whippet-attrs.h -o $@ -c $*.c -heap-conservative-parallel-generational-whippet-%: heap-conservative-parallel-generational-whippet-%.o heap-conservative-parallel-generational-whippet-%-gc.o gc-stack.o gc-platform.o gc-ephemeron-%.o +heap-conservative-parallel-generational-whippet-%: heap-conservative-parallel-generational-whippet-%.o heap-conservative-parallel-generational-whippet-%-gc.o gc-stack.o gc-options.o gc-platform.o gc-ephemeron-%.o $(CC) $(LDFLAGS) -o $@ $^ .PRECIOUS: $(ALL_TESTS) diff --git a/bdw.c b/bdw.c index eb05c1b44..b77847612 100644 --- a/bdw.c +++ b/bdw.c @@ -213,79 +213,40 @@ static inline struct gc_heap *mutator_heap(struct gc_mutator *mutator) { return mutator->heap; } -#define FOR_EACH_GC_OPTION(M) \ - M(GC_OPTION_FIXED_HEAP_SIZE, "fixed-heap-size") \ - M(GC_OPTION_PARALLELISM, "parallelism") - -static void dump_available_gc_options(void) { - fprintf(stderr, "available gc options:"); -#define PRINT_OPTION(option, name) fprintf(stderr, " %s", name); - FOR_EACH_GC_OPTION(PRINT_OPTION) -#undef PRINT_OPTION - fprintf(stderr, "\n"); -} - -int gc_option_from_string(const char *str) { -#define PARSE_OPTION(option, name) if (strcmp(str, name) == 0) return option; - FOR_EACH_GC_OPTION(PARSE_OPTION) -#undef PARSE_OPTION - if (strcmp(str, "fixed-heap-size") == 0) - return GC_OPTION_FIXED_HEAP_SIZE; - if (strcmp(str, "parallelism") == 0) - return GC_OPTION_PARALLELISM; - fprintf(stderr, "bad gc option: '%s'\n", str); - dump_available_gc_options(); - return -1; -} - -struct options { - size_t fixed_heap_size; - size_t parallelism; +struct gc_options { + struct gc_common_options common; }; - -static size_t parse_size_t(double value) { - GC_ASSERT(value >= 0); - GC_ASSERT(value <= (size_t) -1); - return value; +int gc_option_from_string(const char *str) { + return gc_common_option_from_string(str); +} +struct gc_options* gc_allocate_options(void) { + struct gc_options *ret = malloc(sizeof(struct gc_options)); + gc_init_common_options(&ret->common); + return ret; +} +int gc_options_set_int(struct gc_options *options, int option, int value) { + return gc_common_options_set_int(&options->common, option, value); +} +int gc_options_set_size(struct gc_options *options, int option, + size_t value) { + return gc_common_options_set_size(&options->common, option, value); +} +int gc_options_set_double(struct gc_options *options, int option, + double value) { + return gc_common_options_set_double(&options->common, option, value); +} +int gc_options_parse_and_set(struct gc_options *options, int option, + const char *value) { + return gc_common_options_parse_and_set(&options->common, option, value); } -static size_t number_of_current_processors(void) { return 1; } - -static int parse_options(int argc, struct gc_option argv[], - struct options *options) { - for (int i = 0; i < argc; i++) { - switch (argv[i].option) { - case GC_OPTION_FIXED_HEAP_SIZE: - options->fixed_heap_size = parse_size_t(argv[i].value); - break; - case GC_OPTION_PARALLELISM: - options->parallelism = parse_size_t(argv[i].value); - break; - default: - GC_CRASH(); - } - } - - if (!options->fixed_heap_size) { - fprintf(stderr, "fixed heap size is currently required\n"); - return 0; - } - if (!options->parallelism) - options->parallelism = number_of_current_processors(); - - return 1; -} - -int gc_init(int argc, struct gc_option argv[], - struct gc_stack_addr *stack_base, struct gc_heap **heap, - struct gc_mutator **mutator) { +int gc_init(struct gc_options *options, struct gc_stack_addr *stack_base, + struct gc_heap **heap, struct gc_mutator **mutator) { GC_ASSERT_EQ(gc_allocator_small_granule_size(), GC_INLINE_GRANULE_BYTES); GC_ASSERT_EQ(gc_allocator_large_threshold(), GC_INLINE_FREELIST_COUNT * GC_INLINE_GRANULE_BYTES); - struct options options = { 0, }; - if (!parse_options(argc, argv, &options)) - return 0; + if (!options) options = gc_allocate_options(); // GC_full_freq = 30; // GC_free_space_divisor = 16; @@ -293,16 +254,16 @@ int gc_init(int argc, struct gc_option argv[], // Ignore stack base for main thread. - GC_set_max_heap_size(options.fixed_heap_size); + GC_set_max_heap_size(options->common.heap_size); // Not part of 7.3, sigh. Have to set an env var. - // GC_set_markers_count(options.parallelism); + // GC_set_markers_count(options->common.parallelism); char markers[21] = {0,}; // 21 bytes enough for 2**64 in decimal + NUL. - snprintf(markers, sizeof(markers), "%zu", options.parallelism); + snprintf(markers, sizeof(markers), "%d", options->common.parallelism); setenv("GC_MARKERS", markers, 1); GC_init(); size_t current_heap_size = GC_get_heap_size(); - if (options.fixed_heap_size > current_heap_size) - GC_expand_hp(options.fixed_heap_size - current_heap_size); + if (options->common.heap_size > current_heap_size) + GC_expand_hp(options->common.heap_size - current_heap_size); GC_allow_register_threads(); *heap = GC_malloc(sizeof(struct gc_heap)); pthread_mutex_init(&(*heap)->lock, NULL); diff --git a/ephemerons.c b/ephemerons.c index 84fc308f2..40779d741 100644 --- a/ephemerons.c +++ b/ephemerons.c @@ -225,12 +225,14 @@ int main(int argc, char *argv[]) { printf("Allocating heap of %.3fGB (%.2f multiplier of live data).\n", heap_size / 1e9, heap_multiplier); - struct gc_option options[] = { { GC_OPTION_FIXED_HEAP_SIZE, (size_t) heap_size }, - { GC_OPTION_PARALLELISM, parallelism } }; + struct gc_options *options = gc_allocate_options(); + gc_options_set_int(options, GC_OPTION_HEAP_SIZE_POLICY, GC_HEAP_SIZE_FIXED); + gc_options_set_size(options, GC_OPTION_HEAP_SIZE, heap_size); + gc_options_set_int(options, GC_OPTION_PARALLELISM, parallelism); + struct gc_heap *heap; struct gc_mutator *mut; - if (!gc_init(sizeof options / sizeof options[0], options, NULL, &heap, - &mut)) { + if (!gc_init(options, NULL, &heap, &mut)) { fprintf(stderr, "Failed to initialize GC with heap size %zu bytes\n", (size_t)heap_size); return 1; diff --git a/gc-api.h b/gc-api.h index 4ffee3fc7..183603338 100644 --- a/gc-api.h +++ b/gc-api.h @@ -4,9 +4,10 @@ #include "gc-config.h" #include "gc-assert.h" #include "gc-attrs.h" -#include "gc-inline.h" -#include "gc-ref.h" #include "gc-edge.h" +#include "gc-inline.h" +#include "gc-options.h" +#include "gc-ref.h" #include "gc-visibility.h" #include @@ -16,26 +17,13 @@ struct gc_heap; struct gc_mutator; -enum { - GC_OPTION_FIXED_HEAP_SIZE, - GC_OPTION_PARALLELISM -}; - -struct gc_option { - int option; - double value; -}; - -GC_API_ int gc_option_from_string(const char *str); - struct gc_stack_addr; GC_API_ void* gc_call_with_stack_addr(void* (*f)(struct gc_stack_addr *, void *), void *data) GC_NEVER_INLINE; -GC_API_ int gc_init(int argc, struct gc_option argv[], - struct gc_stack_addr *base, struct gc_heap **heap, - struct gc_mutator **mutator); +GC_API_ int gc_init(struct gc_options *options, struct gc_stack_addr *base, + struct gc_heap **heap, struct gc_mutator **mutator); struct gc_mutator_roots; GC_API_ void gc_mutator_set_roots(struct gc_mutator *mut, diff --git a/gc-internal.h b/gc-internal.h index f74336dc9..abc9bd83a 100644 --- a/gc-internal.h +++ b/gc-internal.h @@ -6,5 +6,6 @@ #endif #include "gc-ephemeron-internal.h" +#include "gc-options-internal.h" #endif // GC_INTERNAL_H diff --git a/gc-options-internal.h b/gc-options-internal.h new file mode 100644 index 000000000..4190cb841 --- /dev/null +++ b/gc-options-internal.h @@ -0,0 +1,32 @@ +#ifndef GC_OPTIONS_INTERNAL_H +#define GC_OPTIONS_INTERNAL_H + +#ifndef GC_IMPL +#error internal header file, not part of API +#endif + +#include "gc-options.h" + +struct gc_common_options { + enum gc_heap_size_policy heap_size_policy; + size_t heap_size; + size_t maximum_heap_size; + double heap_size_multiplier; + double heap_frugality; + int parallelism; +}; + +GC_INTERNAL void gc_init_common_options(struct gc_common_options *options); + +GC_INTERNAL int gc_common_option_from_string(const char *str); + +GC_INTERNAL int gc_common_options_set_int(struct gc_common_options *options, + int option, int value); +GC_INTERNAL int gc_common_options_set_size(struct gc_common_options *options, + int option, size_t value); +GC_INTERNAL int gc_common_options_set_double(struct gc_common_options *options, + int option, double value); +GC_INTERNAL int gc_common_options_parse_and_set(struct gc_common_options *options, + int option, const char *value); + +#endif // GC_OPTIONS_INTERNAL_H diff --git a/gc-options.c b/gc-options.c new file mode 100644 index 000000000..77373b170 --- /dev/null +++ b/gc-options.c @@ -0,0 +1,181 @@ +#include +#include +#include +#include + +#define GC_IMPL 1 + +#include "gc-options-internal.h" +#include "gc-platform.h" + +// M(UPPER, lower, repr, parser, default, min, max) +#define FOR_EACH_INT_GC_OPTION(M) \ + M(HEAP_SIZE_POLICY, heap_size_policy, "heap-size-policy", \ + int, GC_HEAP_SIZE_FIXED, GC_HEAP_SIZE_FIXED, GC_HEAP_SIZE_ADAPTIVE) \ + M(PARALLELISM, parallelism, "parallelism", \ + int, default_parallelism(), 1, 64) + +#define FOR_EACH_SIZE_GC_OPTION(M) \ + M(HEAP_SIZE, heap_size, "heap-size", \ + size, 6 * 1024 * 1024, 0, -1) \ + M(MAXIMUM_HEAP_SIZE, maximum_heap_size, "maximum-heap-size", \ + size, 0, 0, -1) + +#define FOR_EACH_DOUBLE_GC_OPTION(M) \ + M(HEAP_SIZE_MULTIPLIER, heap_size_multiplier, "heap-size-multiplier", \ + double, 1.75, 1.0, 1e6) \ + M(HEAP_FRUGALITY, heap_frugality, "heap-frugality", \ + double, 1e-1, 1e-6, 1e6) + +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, 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, 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, parser, default, min, max) \ + case GC_OPTION_##UPPER: \ + if (value != clamp_##parser(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_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, parser, default, min, max) \ + case GC_OPTION_##UPPER: { \ + gc_option_##parser v; \ + if (!parse_##parser(value, &v)) return 0; \ + return gc_common_options_set_##parser(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); 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; +} diff --git a/gc-options.h b/gc-options.h new file mode 100644 index 000000000..35cb7aacf --- /dev/null +++ b/gc-options.h @@ -0,0 +1,39 @@ +#ifndef GC_OPTIONS_H +#define GC_OPTIONS_H + +#include "gc-visibility.h" + +enum gc_heap_size_policy { + GC_HEAP_SIZE_FIXED, + GC_HEAP_SIZE_GROWABLE, + GC_HEAP_SIZE_ADAPTIVE, +}; + +enum { + GC_OPTION_HEAP_SIZE_POLICY, + GC_OPTION_HEAP_SIZE, + GC_OPTION_MAXIMUM_HEAP_SIZE, + GC_OPTION_HEAP_SIZE_MULTIPLIER, + GC_OPTION_HEAP_FRUGALITY, + GC_OPTION_PARALLELISM +}; + +struct gc_options; + +GC_API_ int gc_option_from_string(const char *str); + +GC_API_ struct gc_options* gc_allocate_options(void); + +GC_API_ int gc_options_set_int(struct gc_options *options, int option, + int value); +GC_API_ int gc_options_set_size(struct gc_options *options, int option, + size_t value); +GC_API_ int gc_options_set_double(struct gc_options *options, int option, + double value); + +GC_API_ int gc_options_parse_and_set(struct gc_options *options, + int option, const char *value); +GC_API_ int gc_options_parse_and_set_many(struct gc_options *options, + const char *str); + +#endif // GC_OPTIONS_H diff --git a/gc-platform-gnu-linux.c b/gc-platform-gnu-linux.c index 66e2a73df..82390d445 100644 --- a/gc-platform-gnu-linux.c +++ b/gc-platform-gnu-linux.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -102,3 +103,10 @@ void gc_platform_visit_global_conservative_roots(void (*f)(uintptr_t start, struct visit_data visit_data = { f, heap, data }; dl_iterate_phdr(visit_roots, &visit_data); } + +int gc_platform_processor_count(void) { + cpu_set_t set; + if (sched_getaffinity(0, sizeof (set), &set) != 0) + return 1; + return CPU_COUNT(&set); +} diff --git a/gc-platform.h b/gc-platform.h index b22787d19..ea6a6aa18 100644 --- a/gc-platform.h +++ b/gc-platform.h @@ -20,5 +20,6 @@ void gc_platform_visit_global_conservative_roots(void (*f)(uintptr_t start, void *data), struct gc_heap *heap, void *data); +GC_INTERNAL int gc_platform_processor_count(void); #endif // GC_PLATFORM_H diff --git a/mt-gcbench.c b/mt-gcbench.c index ac0eb1ff9..1ab50a4e0 100644 --- a/mt-gcbench.c +++ b/mt-gcbench.c @@ -355,12 +355,15 @@ int main(int argc, char *argv[]) { } size_t heap_size = heap_max_live * multiplier * nthreads; - struct gc_option options[] = { { GC_OPTION_FIXED_HEAP_SIZE, heap_size }, - { GC_OPTION_PARALLELISM, parallelism } }; + + struct gc_options *options = gc_allocate_options(); + gc_options_set_int(options, GC_OPTION_HEAP_SIZE_POLICY, GC_HEAP_SIZE_FIXED); + gc_options_set_size(options, GC_OPTION_HEAP_SIZE, heap_size); + gc_options_set_int(options, GC_OPTION_PARALLELISM, parallelism); + struct gc_heap *heap; struct gc_mutator *mut; - if (!gc_init(sizeof options / sizeof options[0], options, NULL, &heap, - &mut)) { + if (!gc_init(options, NULL, &heap, &mut)) { fprintf(stderr, "Failed to initialize GC with heap size %zu bytes\n", heap_size); return 1; diff --git a/quads.c b/quads.c index 27923f1f7..097735fad 100644 --- a/quads.c +++ b/quads.c @@ -128,12 +128,14 @@ int main(int argc, char *argv[]) { printf("Allocating heap of %.3fGB (%.2f multiplier of live data).\n", heap_size / 1e9, multiplier); - struct gc_option options[] = { { GC_OPTION_FIXED_HEAP_SIZE, heap_size }, - { GC_OPTION_PARALLELISM, parallelism } }; + struct gc_options *options = gc_allocate_options(); + gc_options_set_int(options, GC_OPTION_HEAP_SIZE_POLICY, GC_HEAP_SIZE_FIXED); + gc_options_set_size(options, GC_OPTION_HEAP_SIZE, heap_size); + gc_options_set_int(options, GC_OPTION_PARALLELISM, 1); + struct gc_heap *heap; struct gc_mutator *mut; - if (!gc_init(sizeof options / sizeof options[0], options, NULL, &heap, - &mut)) { + if (!gc_init(options, NULL, &heap, &mut)) { fprintf(stderr, "Failed to initialize GC with heap size %zu bytes\n", heap_size); return 1; diff --git a/semi.c b/semi.c index e7c2b59cd..5f3db5473 100644 --- a/semi.c +++ b/semi.c @@ -303,70 +303,6 @@ static int initialize_semi_space(struct semi_space *space, size_t size) { return 1; } -#define FOR_EACH_GC_OPTION(M) \ - M(GC_OPTION_FIXED_HEAP_SIZE, "fixed-heap-size") \ - M(GC_OPTION_PARALLELISM, "parallelism") - -static void dump_available_gc_options(void) { - fprintf(stderr, "available gc options:"); -#define PRINT_OPTION(option, name) fprintf(stderr, " %s", name); - FOR_EACH_GC_OPTION(PRINT_OPTION) -#undef PRINT_OPTION - fprintf(stderr, "\n"); -} - -int gc_option_from_string(const char *str) { -#define PARSE_OPTION(option, name) if (strcmp(str, name) == 0) return option; - FOR_EACH_GC_OPTION(PARSE_OPTION) -#undef PARSE_OPTION - if (strcmp(str, "fixed-heap-size") == 0) - return GC_OPTION_FIXED_HEAP_SIZE; - if (strcmp(str, "parallelism") == 0) - return GC_OPTION_PARALLELISM; - fprintf(stderr, "bad gc option: '%s'\n", str); - dump_available_gc_options(); - return -1; -} - -struct options { - size_t fixed_heap_size; - size_t parallelism; -}; - -static size_t parse_size_t(double value) { - GC_ASSERT(value >= 0); - GC_ASSERT(value <= (size_t) -1); - return value; -} - -static int parse_options(int argc, struct gc_option argv[], - struct options *options) { - options->parallelism = 1; - for (int i = 0; i < argc; i++) { - switch (argv[i].option) { - case GC_OPTION_FIXED_HEAP_SIZE: - options->fixed_heap_size = parse_size_t(argv[i].value); - break; - case GC_OPTION_PARALLELISM: - options->parallelism = parse_size_t(argv[i].value); - break; - default: - GC_CRASH(); - } - } - - if (!options->fixed_heap_size) { - fprintf(stderr, "fixed heap size is currently required\n"); - return 0; - } - if (options->parallelism != 1) { - fprintf(stderr, "parallelism unimplemented in semispace copying collector\n"); - return 0; - } - - return 1; -} - static int heap_prepare_pending_ephemerons(struct gc_heap *heap) { struct gc_pending_ephemerons *cur = heap->pending_ephemerons; size_t target = heap->size * heap->pending_ephemerons_size_factor; @@ -390,27 +326,60 @@ static int heap_init(struct gc_heap *heap, size_t size) { return heap_prepare_pending_ephemerons(heap); } -int gc_init(int argc, struct gc_option argv[], - struct gc_stack_addr *stack_base, struct gc_heap **heap, - struct gc_mutator **mut) { +struct gc_options { + struct gc_common_options common; +}; +int gc_option_from_string(const char *str) { + return gc_common_option_from_string(str); +} +struct gc_options* gc_allocate_options(void) { + struct gc_options *ret = malloc(sizeof(struct gc_options)); + gc_init_common_options(&ret->common); + return ret; +} +int gc_options_set_int(struct gc_options *options, int option, int value) { + return gc_common_options_set_int(&options->common, option, value); +} +int gc_options_set_size(struct gc_options *options, int option, + size_t value) { + return gc_common_options_set_size(&options->common, option, value); +} +int gc_options_set_double(struct gc_options *options, int option, + double value) { + return gc_common_options_set_double(&options->common, option, value); +} +int gc_options_parse_and_set(struct gc_options *options, int option, + const char *value) { + return gc_common_options_parse_and_set(&options->common, option, value); +} + +int gc_init(struct gc_options *options, struct gc_stack_addr *stack_base, + struct gc_heap **heap, struct gc_mutator **mut) { GC_ASSERT_EQ(gc_allocator_allocation_pointer_offset(), offsetof(struct semi_space, hp)); GC_ASSERT_EQ(gc_allocator_allocation_limit_offset(), offsetof(struct semi_space, limit)); - struct options options = { 0, }; - if (!parse_options(argc, argv, &options)) + if (!options) options = gc_allocate_options(); + + if (options->common.heap_size_policy != GC_HEAP_SIZE_FIXED) { + fprintf(stderr, "fixed heap size is currently required\n"); return 0; + } + if (options->common.parallelism != 1) { + fprintf(stderr, "parallelism unimplemented in semispace copying collector\n"); + return 0; + } *mut = calloc(1, sizeof(struct gc_mutator)); if (!*mut) GC_CRASH(); *heap = mutator_heap(*mut); - if (!heap_init(*heap, options.fixed_heap_size)) + if (!heap_init(*heap, options->common.heap_size)) return 0; struct semi_space *space = mutator_semi_space(*mut); - if (!initialize_semi_space(space, options.fixed_heap_size)) + if (!initialize_semi_space(space, options->common.heap_size)) return 0; if (!large_object_space_init(heap_large_object_space(*heap), *heap)) return 0; diff --git a/whippet.c b/whippet.c index 9f81948a7..aee9086fd 100644 --- a/whippet.c +++ b/whippet.c @@ -2197,69 +2197,6 @@ unsigned gc_heap_ephemeron_trace_epoch(struct gc_heap *heap) { return heap->count; } -#define FOR_EACH_GC_OPTION(M) \ - M(GC_OPTION_FIXED_HEAP_SIZE, "fixed-heap-size") \ - M(GC_OPTION_PARALLELISM, "parallelism") - -static void dump_available_gc_options(void) { - fprintf(stderr, "available gc options:"); -#define PRINT_OPTION(option, name) fprintf(stderr, " %s", name); - FOR_EACH_GC_OPTION(PRINT_OPTION) -#undef PRINT_OPTION - fprintf(stderr, "\n"); -} - -int gc_option_from_string(const char *str) { -#define PARSE_OPTION(option, name) if (strcmp(str, name) == 0) return option; - FOR_EACH_GC_OPTION(PARSE_OPTION) -#undef PARSE_OPTION - if (strcmp(str, "fixed-heap-size") == 0) - return GC_OPTION_FIXED_HEAP_SIZE; - if (strcmp(str, "parallelism") == 0) - return GC_OPTION_PARALLELISM; - fprintf(stderr, "bad gc option: '%s'\n", str); - dump_available_gc_options(); - return -1; -} - -struct options { - size_t fixed_heap_size; - size_t parallelism; -}; - -static size_t parse_size_t(double value) { - GC_ASSERT(value >= 0); - GC_ASSERT(value <= (size_t) -1); - return value; -} - -static size_t number_of_current_processors(void) { return 1; } - -static int parse_options(int argc, struct gc_option argv[], - struct options *options) { - for (int i = 0; i < argc; i++) { - switch (argv[i].option) { - case GC_OPTION_FIXED_HEAP_SIZE: - options->fixed_heap_size = parse_size_t(argv[i].value); - break; - case GC_OPTION_PARALLELISM: - options->parallelism = parse_size_t(argv[i].value); - break; - default: - GC_CRASH(); - } - } - - if (!options->fixed_heap_size) { - fprintf(stderr, "fixed heap size is currently required\n"); - return 0; - } - if (!options->parallelism) - options->parallelism = number_of_current_processors(); - - return 1; -} - static struct slab* allocate_slabs(size_t nslabs) { size_t size = nslabs * SLAB_SIZE; size_t extent = size + SLAB_SIZE; @@ -2294,15 +2231,42 @@ static int heap_prepare_pending_ephemerons(struct gc_heap *heap) { return !!heap->pending_ephemerons; } -static int heap_init(struct gc_heap *heap, struct options *options) { +struct gc_options { + struct gc_common_options common; +}; +int gc_option_from_string(const char *str) { + return gc_common_option_from_string(str); +} +struct gc_options* gc_allocate_options(void) { + struct gc_options *ret = malloc(sizeof(struct gc_options)); + gc_init_common_options(&ret->common); + return ret; +} +int gc_options_set_int(struct gc_options *options, int option, int value) { + return gc_common_options_set_int(&options->common, option, value); +} +int gc_options_set_size(struct gc_options *options, int option, + size_t value) { + return gc_common_options_set_size(&options->common, option, value); +} +int gc_options_set_double(struct gc_options *options, int option, + double value) { + return gc_common_options_set_double(&options->common, option, value); +} +int gc_options_parse_and_set(struct gc_options *options, int option, + const char *value) { + return gc_common_options_parse_and_set(&options->common, option, value); +} + +static int heap_init(struct gc_heap *heap, struct gc_options *options) { // *heap is already initialized to 0. pthread_mutex_init(&heap->lock, NULL); pthread_cond_init(&heap->mutator_cond, NULL); pthread_cond_init(&heap->collector_cond, NULL); - heap->size = options->fixed_heap_size; + heap->size = options->common.heap_size; - if (!tracer_init(heap, options->parallelism)) + if (!tracer_init(heap, options->common.parallelism)) GC_CRASH(); heap->pending_ephemerons_size_factor = 0.005; @@ -2352,9 +2316,8 @@ static int mark_space_init(struct mark_space *space, struct gc_heap *heap) { return 1; } -int gc_init(int argc, struct gc_option argv[], - struct gc_stack_addr *stack_base, struct gc_heap **heap, - struct gc_mutator **mut) { +int gc_init(struct gc_options *options, struct gc_stack_addr *stack_base, + struct gc_heap **heap, struct gc_mutator **mut) { GC_ASSERT_EQ(gc_allocator_small_granule_size(), GRANULE_SIZE); GC_ASSERT_EQ(gc_allocator_large_threshold(), LARGE_OBJECT_THRESHOLD); GC_ASSERT_EQ(gc_allocator_allocation_pointer_offset(), @@ -2370,14 +2333,15 @@ int gc_init(int argc, struct gc_option argv[], BLOCK_SIZE / REMSET_BYTES_PER_BLOCK); } - struct options options = { 0, }; - if (!parse_options(argc, argv, &options)) + if (options->common.heap_size_policy != GC_HEAP_SIZE_FIXED) { + fprintf(stderr, "fixed heap size is currently required\n"); return 0; + } *heap = calloc(1, sizeof(struct gc_heap)); if (!*heap) GC_CRASH(); - if (!heap_init(*heap, &options)) + if (!heap_init(*heap, options)) GC_CRASH(); struct mark_space *space = heap_mark_space(*heap);