1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-18 10:10:23 +02:00

Set fixed heap size, parallelism via explicit options

This commit is contained in:
Andy Wingo 2022-08-09 11:21:02 +02:00
parent 2e6dde66b3
commit 4ccb489869
8 changed files with 275 additions and 30 deletions

87
bdw.h
View file

@ -1,4 +1,5 @@
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include "conservative-roots.h" #include "conservative-roots.h"
@ -120,17 +121,89 @@ static inline struct heap *mutator_heap(struct mutator *mutator) {
return mutator->heap; return mutator->heap;
} }
static int initialize_gc(size_t heap_size, struct heap **heap, #define FOR_EACH_GC_OPTION(M) \
struct mutator **mutator) { 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_full_freq = 30;
// GC_free_space_divisor = 16; // GC_free_space_divisor = 16;
// GC_enable_incremental(); // 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(); size_t current_heap_size = GC_get_heap_size();
if (heap_size > current_heap_size) { if (options.fixed_heap_size > current_heap_size)
GC_set_max_heap_size (heap_size); GC_expand_hp(options.fixed_heap_size - current_heap_size);
GC_expand_hp(heap_size - current_heap_size);
}
GC_allow_register_threads(); GC_allow_register_threads();
*heap = GC_malloc(sizeof(struct heap)); *heap = GC_malloc(sizeof(struct heap));
pthread_mutex_init(&(*heap)->lock, NULL); pthread_mutex_init(&(*heap)->lock, NULL);

View file

@ -59,4 +59,27 @@ static inline void gc_edge_update(struct gc_edge edge, struct gc_ref ref) {
*edge.dst = 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_ #endif // GC_API_H_

View file

@ -380,13 +380,14 @@ int main(int argc, char *argv[]) {
tree_size(long_lived_tree_depth) * sizeof_node + tree_size(long_lived_tree_depth) * sizeof_node +
tree_size(max_tree_depth) * sizeof_node + tree_size(max_tree_depth) * sizeof_node +
sizeof_double_array + sizeof(double) * array_size; sizeof_double_array + sizeof(double) * array_size;
if (argc != 3) { if (argc != 4) {
fprintf(stderr, "usage: %s MULTIPLIER NTHREADS\n", argv[0]); fprintf(stderr, "usage: %s MULTIPLIER NTHREADS PARALLELISM\n", argv[0]);
return 1; return 1;
} }
double multiplier = atof(argv[1]); double multiplier = atof(argv[1]);
size_t nthreads = atol(argv[2]); size_t nthreads = atol(argv[2]);
size_t parallelism = atol(argv[3]);
if (!(0.1 < multiplier && multiplier < 100)) { if (!(0.1 < multiplier && multiplier < 100)) {
fprintf(stderr, "Failed to parse heap multiplier '%s'\n", argv[1]); 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]); (int)MAX_THREAD_COUNT, argv[2]);
return 1; 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; 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 heap *heap;
struct mutator *mut; 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", fprintf(stderr, "Failed to initialize GC with heap size %zu bytes\n",
heap_size); heap_size);
return 1; return 1;

View file

@ -325,8 +325,6 @@ struct local_tracer {
struct context; struct context;
static inline struct tracer* heap_tracer(struct heap *heap); static inline struct tracer* heap_tracer(struct heap *heap);
static size_t number_of_current_processors(void) { return 1; }
static int static int
trace_worker_init(struct trace_worker *worker, struct heap *heap, trace_worker_init(struct trace_worker *worker, struct heap *heap,
struct tracer *tracer, size_t id) { struct tracer *tracer, size_t id) {
@ -416,18 +414,15 @@ trace_worker_request_stop(struct trace_worker *worker) {
} }
static int static int
tracer_init(struct heap *heap) { tracer_init(struct heap *heap, size_t parallelism) {
struct tracer *tracer = heap_tracer(heap); struct tracer *tracer = heap_tracer(heap);
atomic_init(&tracer->active_tracers, 0); atomic_init(&tracer->active_tracers, 0);
atomic_init(&tracer->running_tracers, 0); atomic_init(&tracer->running_tracers, 0);
tracer->count = 0; tracer->count = 0;
pthread_mutex_init(&tracer->lock, NULL); pthread_mutex_init(&tracer->lock, NULL);
pthread_cond_init(&tracer->cond, NULL); pthread_cond_init(&tracer->cond, NULL);
size_t desired_worker_count = 0; size_t desired_worker_count = parallelism;
if (getenv("GC_TRACERS")) ASSERT(desired_worker_count);
desired_worker_count = atoi(getenv("GC_TRACERS"));
if (desired_worker_count == 0)
desired_worker_count = number_of_current_processors();
if (desired_worker_count > TRACE_WORKERS_MAX_COUNT) if (desired_worker_count > TRACE_WORKERS_MAX_COUNT)
desired_worker_count = TRACE_WORKERS_MAX_COUNT; desired_worker_count = TRACE_WORKERS_MAX_COUNT;
for (size_t i = 0; i < desired_worker_count; i++) { for (size_t i = 0; i < desired_worker_count; i++) {

14
quads.c
View file

@ -103,20 +103,27 @@ static size_t tree_size(size_t depth) {
return nquads; return nquads;
} }
#define MAX_THREAD_COUNT 256
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
if (argc != 3) { if (argc != 3) {
fprintf(stderr, "usage: %s DEPTH MULTIPLIER\n", argv[0]); fprintf(stderr, "usage: %s DEPTH MULTIPLIER PARALLELISM\n", argv[0]);
return 1; return 1;
} }
size_t depth = parse_size(argv[1], "depth"); size_t depth = parse_size(argv[1], "depth");
double multiplier = atof(argv[2]); double multiplier = atof(argv[2]);
size_t parallelism = atol(argv[3]);
if (!(1.0 < multiplier && multiplier < 100)) { if (!(1.0 < multiplier && multiplier < 100)) {
fprintf(stderr, "Failed to parse heap multiplier '%s'\n", argv[2]); fprintf(stderr, "Failed to parse heap multiplier '%s'\n", argv[2]);
return 1; 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 // Compute byte size not counting any header word, so as to compute the same
// heap size whether a header word is there or not. // 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(); unsigned long gc_start = current_time();
printf("Allocating heap of %.3fGB (%.2f multiplier of live data).\n", printf("Allocating heap of %.3fGB (%.2f multiplier of live data).\n",
heap_size / 1e9, multiplier); heap_size / 1e9, multiplier);
struct gc_option options[] = { { GC_OPTION_FIXED_HEAP_SIZE, heap_size },
{ GC_OPTION_PARALLELISM, parallelism } };
struct heap *heap; struct heap *heap;
struct mutator *mut; 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", fprintf(stderr, "Failed to initialize GC with heap size %zu bytes\n",
heap_size); heap_size);
return 1; return 1;

74
semi.h
View file

@ -285,14 +285,82 @@ static int initialize_semi_space(struct semi_space *space, size_t size) {
return 1; return 1;
} }
static int initialize_gc(size_t heap_size, struct heap **heap, #define FOR_EACH_GC_OPTION(M) \
struct mutator **mut) { 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)); *mut = calloc(1, sizeof(struct mutator));
if (!*mut) abort(); if (!*mut) abort();
*heap = mutator_heap(*mut); *heap = mutator_heap(*mut);
struct semi_space *space = mutator_semi_space(*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; return 0;
if (!large_object_space_init(heap_large_object_space(*heap), *heap)) if (!large_object_space_init(heap_large_object_space(*heap), *heap))
return 0; return 0;

View file

@ -129,7 +129,7 @@ struct heap;
static inline struct tracer* heap_tracer(struct heap *heap); static inline struct tracer* heap_tracer(struct heap *heap);
static int static int
tracer_init(struct heap *heap) { tracer_init(struct heap *heap, size_t parallelism) {
return trace_queue_init(&heap_tracer(heap)->queue); return trace_queue_init(&heap_tracer(heap)->queue);
} }
static void tracer_prepare(struct heap *heap) {} static void tracer_prepare(struct heap *heap) {}

View file

@ -12,6 +12,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <string.h>
#include <unistd.h> #include <unistd.h>
#include "assert.h" #include "assert.h"
@ -1910,6 +1911,69 @@ static inline void set_field(void *obj, void **addr, void *val) {
*addr = 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) { static struct slab* allocate_slabs(size_t nslabs) {
size_t size = nslabs * SLAB_SIZE; size_t size = nslabs * SLAB_SIZE;
size_t extent = size + 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; 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. // *heap is already initialized to 0.
pthread_mutex_init(&heap->lock, NULL); pthread_mutex_init(&heap->lock, NULL);
pthread_cond_init(&heap->mutator_cond, NULL); pthread_cond_init(&heap->mutator_cond, NULL);
pthread_cond_init(&heap->collector_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(); abort();
heap->fragmentation_low_threshold = 0.05; heap->fragmentation_low_threshold = 0.05;
@ -1987,12 +2051,16 @@ static int mark_space_init(struct mark_space *space, struct heap *heap) {
return 1; return 1;
} }
static int initialize_gc(size_t size, struct heap **heap, static int gc_init(int argc, struct gc_option argv[],
struct mutator **mut) { struct heap **heap, struct mutator **mut) {
struct options options = { 0, };
if (!parse_options(argc, argv, &options))
return 0;
*heap = calloc(1, sizeof(struct heap)); *heap = calloc(1, sizeof(struct heap));
if (!*heap) abort(); if (!*heap) abort();
if (!heap_init(*heap, size)) if (!heap_init(*heap, &options))
abort(); abort();
struct mark_space *space = heap_mark_space(*heap); struct mark_space *space = heap_mark_space(*heap);