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 <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);

View file

@ -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_

View file

@ -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;

View file

@ -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++) {

14
quads.c
View file

@ -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;

74
semi.h
View file

@ -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;

View file

@ -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) {}

View file

@ -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);