mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-18 18:40:22 +02:00
Set fixed heap size, parallelism via explicit options
This commit is contained in:
parent
2e6dde66b3
commit
4ccb489869
8 changed files with 275 additions and 30 deletions
87
bdw.h
87
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);
|
||||
|
|
23
gc-api.h
23
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_
|
||||
|
|
14
mt-gcbench.c
14
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;
|
||||
|
|
|
@ -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
14
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;
|
||||
|
|
74
semi.h
74
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;
|
||||
|
|
|
@ -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) {}
|
||||
|
|
80
whippet.h
80
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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue