wingo pushed a commit to branch wip-whippet
in repository guile.

commit 4ccb489869268dfd6f05b452f39bbcaa2b5ddb9b
Author: Andy Wingo <wi...@igalia.com>
AuthorDate: Tue Aug 9 11:21:02 2022 +0200

    Set fixed heap size, parallelism via explicit options
---
 bdw.h             | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 gc-api.h          | 23 +++++++++++++++
 mt-gcbench.c      | 14 +++++++--
 parallel-tracer.h | 11 ++-----
 quads.c           | 14 +++++++--
 semi.h            | 74 ++++++++++++++++++++++++++++++++++++++++++++--
 serial-tracer.h   |  2 +-
 whippet.h         | 80 ++++++++++++++++++++++++++++++++++++++++++++++----
 8 files changed, 275 insertions(+), 30 deletions(-)

diff --git a/bdw.h b/bdw.h
index 69a147b56..2d30fb3b6 100644
--- a/bdw.h
+++ b/bdw.h
@@ -1,4 +1,5 @@
 #include <stdint.h>
+#include <string.h>
 
 #include "conservative-roots.h"
 
@@ -120,17 +121,89 @@ static inline struct heap *mutator_heap(struct mutator 
*mutator) {
   return mutator->heap;
 }
 
-static int initialize_gc(size_t heap_size, struct heap **heap,
-                         struct mutator **mutator) {
+#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");
+}
+
+static 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) {
+  ASSERT(value >= 0);
+  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:
+      abort();
+    }
+  }
+
+  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 int gc_init(int argc, struct gc_option argv[],
+                   struct heap **heap, struct mutator **mutator) {
+  struct options options = { 0, };
+  if (!parse_options(argc, argv, &options))
+    return 0;
+
   // GC_full_freq = 30;
   // GC_free_space_divisor = 16;
   // GC_enable_incremental();
-  GC_INIT();
+  
+  GC_set_max_heap_size(options.fixed_heap_size);
+  // Not part of 7.3, sigh.  Have to set an env var.
+  // GC_set_markers_count(options.parallelism);
+  char markers[21] = {0,}; // 21 bytes enough for 2**64 in decimal + NUL.
+  snprintf(markers, sizeof(markers), "%zu", options.parallelism);
+  setenv("GC_MARKERS", markers, 1);
+  GC_init();
   size_t current_heap_size = GC_get_heap_size();
-  if (heap_size > current_heap_size) {
-    GC_set_max_heap_size (heap_size);
-    GC_expand_hp(heap_size - current_heap_size);
-  }
+  if (options.fixed_heap_size > current_heap_size)
+    GC_expand_hp(options.fixed_heap_size - current_heap_size);
   GC_allow_register_threads();
   *heap = GC_malloc(sizeof(struct heap));
   pthread_mutex_init(&(*heap)->lock, NULL);
diff --git a/gc-api.h b/gc-api.h
index 6c072bc31..7d6eead51 100644
--- a/gc-api.h
+++ b/gc-api.h
@@ -59,4 +59,27 @@ static inline void gc_edge_update(struct gc_edge edge, 
struct gc_ref ref) {
   *edge.dst = ref;
 }
 
+// FIXME: prefix with gc_
+struct heap;
+struct mutator;
+
+enum {
+  GC_OPTION_FIXED_HEAP_SIZE,
+  GC_OPTION_PARALLELISM
+};
+
+struct gc_option {
+  int option;
+  double value;
+};
+
+// FIXME: Conflict with bdw-gc GC_API.  Switch prefix?
+#ifndef GC_API_
+#define GC_API_ static
+#endif
+
+GC_API_ int gc_option_from_string(const char *str);
+GC_API_ int gc_init(int argc, struct gc_option argv[],
+                    struct heap **heap, struct mutator **mutator);
+
 #endif // GC_API_H_
diff --git a/mt-gcbench.c b/mt-gcbench.c
index 4d1c92255..23fb235c2 100644
--- a/mt-gcbench.c
+++ b/mt-gcbench.c
@@ -380,13 +380,14 @@ int main(int argc, char *argv[]) {
     tree_size(long_lived_tree_depth) * sizeof_node +
     tree_size(max_tree_depth) * sizeof_node +
     sizeof_double_array + sizeof(double) * array_size;
-  if (argc != 3) {
-    fprintf(stderr, "usage: %s MULTIPLIER NTHREADS\n", argv[0]);
+  if (argc != 4) {
+    fprintf(stderr, "usage: %s MULTIPLIER NTHREADS PARALLELISM\n", argv[0]);
     return 1;
   }
 
   double multiplier = atof(argv[1]);
   size_t nthreads = atol(argv[2]);
+  size_t parallelism = atol(argv[3]);
 
   if (!(0.1 < multiplier && multiplier < 100)) {
     fprintf(stderr, "Failed to parse heap multiplier '%s'\n", argv[1]);
@@ -397,11 +398,18 @@ int main(int argc, char *argv[]) {
             (int)MAX_THREAD_COUNT, argv[2]);
     return 1;
   }
+  if (parallelism < 1 || parallelism > MAX_THREAD_COUNT) {
+    fprintf(stderr, "Expected integer between 1 and %d for parallelism, got 
'%s'\n",
+            (int)MAX_THREAD_COUNT, argv[3]);
+    return 1;
+  }
 
   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 heap *heap;
   struct mutator *mut;
-  if (!initialize_gc(heap_size, &heap, &mut)) {
+  if (!gc_init(sizeof options / sizeof options[0], options, &heap, &mut)) {
     fprintf(stderr, "Failed to initialize GC with heap size %zu bytes\n",
             heap_size);
     return 1;
diff --git a/parallel-tracer.h b/parallel-tracer.h
index 92c0a86d4..0634c91ec 100644
--- a/parallel-tracer.h
+++ b/parallel-tracer.h
@@ -325,8 +325,6 @@ struct local_tracer {
 struct context;
 static inline struct tracer* heap_tracer(struct heap *heap);
 
-static size_t number_of_current_processors(void) { return 1; }
-
 static int
 trace_worker_init(struct trace_worker *worker, struct heap *heap,
                  struct tracer *tracer, size_t id) {
@@ -416,18 +414,15 @@ trace_worker_request_stop(struct trace_worker *worker) {
 }  
 
 static int
-tracer_init(struct heap *heap) {
+tracer_init(struct heap *heap, size_t parallelism) {
   struct tracer *tracer = heap_tracer(heap);
   atomic_init(&tracer->active_tracers, 0);
   atomic_init(&tracer->running_tracers, 0);
   tracer->count = 0;
   pthread_mutex_init(&tracer->lock, NULL);
   pthread_cond_init(&tracer->cond, NULL);
-  size_t desired_worker_count = 0;
-  if (getenv("GC_TRACERS"))
-    desired_worker_count = atoi(getenv("GC_TRACERS"));
-  if (desired_worker_count == 0)
-    desired_worker_count = number_of_current_processors();
+  size_t desired_worker_count = parallelism;
+  ASSERT(desired_worker_count);
   if (desired_worker_count > TRACE_WORKERS_MAX_COUNT)
     desired_worker_count = TRACE_WORKERS_MAX_COUNT;
   for (size_t i = 0; i < desired_worker_count; i++) {
diff --git a/quads.c b/quads.c
index d2cba2bf0..9c6dedfaf 100644
--- a/quads.c
+++ b/quads.c
@@ -103,20 +103,27 @@ static size_t tree_size(size_t depth) {
   return nquads;
 }
 
+#define MAX_THREAD_COUNT 256
 
 int main(int argc, char *argv[]) {
   if (argc != 3) {
-    fprintf(stderr, "usage: %s DEPTH MULTIPLIER\n", argv[0]);
+    fprintf(stderr, "usage: %s DEPTH MULTIPLIER PARALLELISM\n", argv[0]);
     return 1;
   }
 
   size_t depth = parse_size(argv[1], "depth");
   double multiplier = atof(argv[2]);
+  size_t parallelism = atol(argv[3]);
 
   if (!(1.0 < multiplier && multiplier < 100)) {
     fprintf(stderr, "Failed to parse heap multiplier '%s'\n", argv[2]);
     return 1;
   }
+  if (parallelism < 1 || parallelism > MAX_THREAD_COUNT) {
+    fprintf(stderr, "Expected integer between 1 and %d for parallelism, got 
'%s'\n",
+            (int)MAX_THREAD_COUNT, argv[3]);
+    return 1;
+  }
 
   // Compute byte size not counting any header word, so as to compute the same
   // heap size whether a header word is there or not.
@@ -127,9 +134,12 @@ int main(int argc, char *argv[]) {
   unsigned long gc_start = current_time();
   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 heap *heap;
   struct mutator *mut;
-  if (!initialize_gc(heap_size, &heap, &mut)) {
+  if (!gc_init(sizeof options / sizeof options[0], options, &heap, &mut)) {
     fprintf(stderr, "Failed to initialize GC with heap size %zu bytes\n",
             heap_size);
     return 1;
diff --git a/semi.h b/semi.h
index 7cd776398..0f6071266 100644
--- a/semi.h
+++ b/semi.h
@@ -285,14 +285,82 @@ static int initialize_semi_space(struct semi_space 
*space, size_t size) {
   return 1;
 }
   
-static int initialize_gc(size_t heap_size, struct heap **heap,
-                         struct mutator **mut) {
+#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");
+}
+
+static 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) {
+  ASSERT(value >= 0);
+  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:
+      abort();
+    }
+  }
+
+  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 gc_init(int argc, struct gc_option argv[],
+                   struct heap **heap, struct mutator **mut) {
+  struct options options = { 0, };
+  if (!parse_options(argc, argv, &options))
+    return 0;
+
   *mut = calloc(1, sizeof(struct mutator));
   if (!*mut) abort();
   *heap = mutator_heap(*mut);
 
   struct semi_space *space = mutator_semi_space(*mut);
-  if (!initialize_semi_space(space, heap_size))
+  if (!initialize_semi_space(space, options.fixed_heap_size))
     return 0;
   if (!large_object_space_init(heap_large_object_space(*heap), *heap))
     return 0;
diff --git a/serial-tracer.h b/serial-tracer.h
index 3376d9608..474de34d7 100644
--- a/serial-tracer.h
+++ b/serial-tracer.h
@@ -129,7 +129,7 @@ struct heap;
 static inline struct tracer* heap_tracer(struct heap *heap);
 
 static int
-tracer_init(struct heap *heap) {
+tracer_init(struct heap *heap, size_t parallelism) {
   return trace_queue_init(&heap_tracer(heap)->queue);
 }
 static void tracer_prepare(struct heap *heap) {}
diff --git a/whippet.h b/whippet.h
index 93936aaae..b100ca04f 100644
--- a/whippet.h
+++ b/whippet.h
@@ -12,6 +12,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <string.h>
 #include <unistd.h>
 
 #include "assert.h"
@@ -1910,6 +1911,69 @@ static inline void set_field(void *obj, void **addr, 
void *val) {
   *addr = val;
 }
 
+#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");
+}
+
+static 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) {
+  ASSERT(value >= 0);
+  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:
+      abort();
+    }
+  }
+
+  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;
@@ -1934,15 +1998,15 @@ static struct slab* allocate_slabs(size_t nslabs) {
   return (struct slab*) aligned_base;
 }
 
-static int heap_init(struct heap *heap, size_t size) {
+static int heap_init(struct heap *heap, struct 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 = size;
+  heap->size = options->fixed_heap_size;
 
-  if (!tracer_init(heap))
+  if (!tracer_init(heap, options->parallelism))
     abort();
 
   heap->fragmentation_low_threshold = 0.05;
@@ -1987,12 +2051,16 @@ static int mark_space_init(struct mark_space *space, 
struct heap *heap) {
   return 1;
 }
 
-static int initialize_gc(size_t size, struct heap **heap,
-                         struct mutator **mut) {
+static int gc_init(int argc, struct gc_option argv[],
+                   struct heap **heap, struct mutator **mut) {
+  struct options options = { 0, };
+  if (!parse_options(argc, argv, &options))
+    return 0;
+
   *heap = calloc(1, sizeof(struct heap));
   if (!*heap) abort();
 
-  if (!heap_init(*heap, size))
+  if (!heap_init(*heap, &options))
     abort();
 
   struct mark_space *space = heap_mark_space(*heap);

Reply via email to