mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
Rework tracer API to pass tracer to all functions
This commit is contained in:
parent
921c012b51
commit
ba9459ce56
4 changed files with 46 additions and 48 deletions
|
@ -36,6 +36,7 @@ struct trace_worker {
|
||||||
#define TRACE_WORKERS_MAX_COUNT 8
|
#define TRACE_WORKERS_MAX_COUNT 8
|
||||||
|
|
||||||
struct gc_tracer {
|
struct gc_tracer {
|
||||||
|
struct gc_heap *heap;
|
||||||
atomic_size_t active_tracers;
|
atomic_size_t active_tracers;
|
||||||
size_t worker_count;
|
size_t worker_count;
|
||||||
long epoch;
|
long epoch;
|
||||||
|
@ -92,8 +93,9 @@ trace_worker_spawn(struct trace_worker *worker) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gc_tracer_init(struct gc_heap *heap, size_t parallelism) {
|
gc_tracer_init(struct gc_tracer *tracer, struct gc_heap *heap,
|
||||||
struct gc_tracer *tracer = heap_tracer(heap);
|
size_t parallelism) {
|
||||||
|
tracer->heap = heap;
|
||||||
atomic_init(&tracer->active_tracers, 0);
|
atomic_init(&tracer->active_tracers, 0);
|
||||||
tracer->epoch = 0;
|
tracer->epoch = 0;
|
||||||
pthread_mutex_init(&tracer->lock, NULL);
|
pthread_mutex_init(&tracer->lock, NULL);
|
||||||
|
@ -116,13 +118,11 @@ gc_tracer_init(struct gc_heap *heap, size_t parallelism) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gc_tracer_prepare(struct gc_heap *heap) {
|
static void gc_tracer_prepare(struct gc_tracer *tracer) {
|
||||||
struct gc_tracer *tracer = heap_tracer(heap);
|
|
||||||
for (size_t i = 0; i < tracer->worker_count; i++)
|
for (size_t i = 0; i < tracer->worker_count; i++)
|
||||||
tracer->workers[i].steal_id = 0;
|
tracer->workers[i].steal_id = 0;
|
||||||
}
|
}
|
||||||
static void gc_tracer_release(struct gc_heap *heap) {
|
static void gc_tracer_release(struct gc_tracer *tracer) {
|
||||||
struct gc_tracer *tracer = heap_tracer(heap);
|
|
||||||
for (size_t i = 0; i < tracer->worker_count; i++)
|
for (size_t i = 0; i < tracer->worker_count; i++)
|
||||||
shared_worklist_release(&tracer->workers[i].deque);
|
shared_worklist_release(&tracer->workers[i].deque);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,8 @@ tracer_share(struct local_tracer *trace) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
gc_tracer_enqueue(struct gc_ref ref, struct gc_heap *heap, void *trace_data) {
|
gc_tracer_enqueue(struct gc_tracer *tracer, struct gc_ref ref,
|
||||||
|
void *trace_data) {
|
||||||
struct local_tracer *trace = trace_data;
|
struct local_tracer *trace = trace_data;
|
||||||
if (local_worklist_full(&trace->local))
|
if (local_worklist_full(&trace->local))
|
||||||
tracer_share(trace);
|
tracer_share(trace);
|
||||||
|
@ -316,9 +317,7 @@ gc_tracer_enqueue_roots(struct gc_tracer *tracer, struct gc_ref *objv,
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
gc_tracer_trace(struct gc_heap *heap) {
|
gc_tracer_trace(struct gc_tracer *tracer) {
|
||||||
struct gc_tracer *tracer = heap_tracer(heap);
|
|
||||||
|
|
||||||
DEBUG("starting trace; %zu workers\n", tracer->worker_count);
|
DEBUG("starting trace; %zu workers\n", tracer->worker_count);
|
||||||
|
|
||||||
ssize_t parallel_threshold =
|
ssize_t parallel_threshold =
|
||||||
|
|
|
@ -10,16 +10,19 @@
|
||||||
#include "tracer.h"
|
#include "tracer.h"
|
||||||
|
|
||||||
struct gc_tracer {
|
struct gc_tracer {
|
||||||
|
struct gc_heap *heap;
|
||||||
struct simple_worklist worklist;
|
struct simple_worklist worklist;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
gc_tracer_init(struct gc_heap *heap, size_t parallelism) {
|
gc_tracer_init(struct gc_tracer *tracer, struct gc_heap *heap,
|
||||||
|
size_t parallelism) {
|
||||||
|
tracer->heap = heap;
|
||||||
return simple_worklist_init(&heap_tracer(heap)->worklist);
|
return simple_worklist_init(&heap_tracer(heap)->worklist);
|
||||||
}
|
}
|
||||||
static void gc_tracer_prepare(struct gc_heap *heap) {}
|
static void gc_tracer_prepare(struct gc_tracer *tracer) {}
|
||||||
static void gc_tracer_release(struct gc_heap *heap) {
|
static void gc_tracer_release(struct gc_tracer *tracer) {
|
||||||
simple_worklist_release(&heap_tracer(heap)->worklist);
|
simple_worklist_release(&tracer->worklist);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -32,16 +35,17 @@ gc_tracer_enqueue_roots(struct gc_tracer *tracer, struct gc_ref *objs,
|
||||||
simple_worklist_push_many(&tracer->worklist, objs, count);
|
simple_worklist_push_many(&tracer->worklist, objs, count);
|
||||||
}
|
}
|
||||||
static inline void
|
static inline void
|
||||||
gc_tracer_enqueue(struct gc_ref ref, struct gc_heap *heap, void *trace_data) {
|
gc_tracer_enqueue(struct gc_tracer *tracer, struct gc_ref ref,
|
||||||
gc_tracer_enqueue_root(heap_tracer(heap), ref);
|
void *trace_data) {
|
||||||
|
gc_tracer_enqueue_root(tracer, ref);
|
||||||
}
|
}
|
||||||
static inline void
|
static inline void
|
||||||
gc_tracer_trace(struct gc_heap *heap) {
|
gc_tracer_trace(struct gc_tracer *tracer) {
|
||||||
do {
|
do {
|
||||||
struct gc_ref obj = simple_worklist_pop(&heap_tracer(heap)->worklist);
|
struct gc_ref obj = simple_worklist_pop(&tracer->worklist);
|
||||||
if (!gc_ref_is_heap_object(obj))
|
if (!gc_ref_is_heap_object(obj))
|
||||||
break;
|
break;
|
||||||
trace_one(obj, heap, NULL);
|
trace_one(obj, tracer->heap, NULL);
|
||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
30
src/tracer.h
30
src/tracer.h
|
@ -17,10 +17,6 @@ static inline struct gc_tracer* heap_tracer(struct gc_heap *heap);
|
||||||
static inline void trace_one(struct gc_ref ref, struct gc_heap *heap,
|
static inline void trace_one(struct gc_ref ref, struct gc_heap *heap,
|
||||||
void *trace_data) GC_ALWAYS_INLINE;
|
void *trace_data) GC_ALWAYS_INLINE;
|
||||||
|
|
||||||
// Visit one edge. Return nonzero if this call shaded the object grey.
|
|
||||||
static inline int trace_edge(struct gc_heap *heap,
|
|
||||||
struct gc_edge edge) GC_ALWAYS_INLINE;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
/// To be implemented by tracer.
|
/// To be implemented by tracer.
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -30,13 +26,14 @@ static inline int trace_edge(struct gc_heap *heap,
|
||||||
struct gc_tracer;
|
struct gc_tracer;
|
||||||
|
|
||||||
// Initialize the tracer when the heap is created.
|
// Initialize the tracer when the heap is created.
|
||||||
static int gc_tracer_init(struct gc_heap *heap, size_t parallelism);
|
static int gc_tracer_init(struct gc_tracer *tracer, struct gc_heap *heap,
|
||||||
|
size_t parallelism);
|
||||||
|
|
||||||
// Initialize the tracer for a new GC cycle.
|
// Initialize the tracer for a new GC cycle.
|
||||||
static void gc_tracer_prepare(struct gc_heap *heap);
|
static void gc_tracer_prepare(struct gc_tracer *tracer);
|
||||||
|
|
||||||
// Release any resources allocated during the trace.
|
// Release any resources allocated during the trace.
|
||||||
static void gc_tracer_release(struct gc_heap *heap);
|
static void gc_tracer_release(struct gc_tracer *tracer);
|
||||||
|
|
||||||
// Add root objects to the trace. Call before tracer_trace.
|
// Add root objects to the trace. Call before tracer_trace.
|
||||||
static inline void gc_tracer_enqueue_root(struct gc_tracer *tracer,
|
static inline void gc_tracer_enqueue_root(struct gc_tracer *tracer,
|
||||||
|
@ -46,24 +43,11 @@ static inline void gc_tracer_enqueue_roots(struct gc_tracer *tracer,
|
||||||
size_t count);
|
size_t count);
|
||||||
|
|
||||||
// Given that an object has been shaded grey, enqueue for tracing.
|
// Given that an object has been shaded grey, enqueue for tracing.
|
||||||
static inline void gc_tracer_enqueue(struct gc_ref ref, struct gc_heap *heap,
|
static inline void gc_tracer_enqueue(struct gc_tracer *tracer,
|
||||||
|
struct gc_ref ref,
|
||||||
void *trace_data) GC_ALWAYS_INLINE;
|
void *trace_data) GC_ALWAYS_INLINE;
|
||||||
|
|
||||||
// Run the full trace.
|
// Run the full trace.
|
||||||
static inline void gc_tracer_trace(struct gc_heap *heap);
|
static inline void gc_tracer_trace(struct gc_tracer *tracer);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
/// Procedures that work with any tracer.
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// Visit one edge. If we shade the edge target grey, enqueue it for
|
|
||||||
// tracing.
|
|
||||||
static inline void tracer_visit(struct gc_edge edge, struct gc_heap *heap,
|
|
||||||
void *trace_data) GC_ALWAYS_INLINE;
|
|
||||||
static inline void
|
|
||||||
tracer_visit(struct gc_edge edge, struct gc_heap *heap, void *trace_data) {
|
|
||||||
if (trace_edge(heap, edge))
|
|
||||||
gc_tracer_enqueue(gc_edge_ref(edge), heap, trace_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // TRACER_H
|
#endif // TRACER_H
|
||||||
|
|
|
@ -674,6 +674,9 @@ static inline int do_trace(struct gc_heap *heap, struct gc_edge edge,
|
||||||
return gc_extern_space_visit(heap_extern_space(heap), edge, ref);
|
return gc_extern_space_visit(heap_extern_space(heap), edge, ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int trace_edge(struct gc_heap *heap,
|
||||||
|
struct gc_edge edge) GC_ALWAYS_INLINE;
|
||||||
|
|
||||||
static inline int trace_edge(struct gc_heap *heap, struct gc_edge edge) {
|
static inline int trace_edge(struct gc_heap *heap, struct gc_edge edge) {
|
||||||
struct gc_ref ref = gc_edge_ref(edge);
|
struct gc_ref ref = gc_edge_ref(edge);
|
||||||
int is_new = do_trace(heap, edge, ref);
|
int is_new = do_trace(heap, edge, ref);
|
||||||
|
@ -1094,6 +1097,14 @@ void gc_heap_set_extern_space(struct gc_heap *heap,
|
||||||
heap->extern_space = space;
|
heap->extern_space = space;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void tracer_visit(struct gc_edge edge, struct gc_heap *heap,
|
||||||
|
void *trace_data) GC_ALWAYS_INLINE;
|
||||||
|
static inline void
|
||||||
|
tracer_visit(struct gc_edge edge, struct gc_heap *heap, void *trace_data) {
|
||||||
|
if (trace_edge(heap, edge))
|
||||||
|
gc_tracer_enqueue(&heap->tracer, gc_edge_ref(edge), trace_data);
|
||||||
|
}
|
||||||
|
|
||||||
static void trace_and_enqueue_locally(struct gc_edge edge,
|
static void trace_and_enqueue_locally(struct gc_edge edge,
|
||||||
struct gc_heap *heap,
|
struct gc_heap *heap,
|
||||||
void *data) {
|
void *data) {
|
||||||
|
@ -1177,7 +1188,7 @@ static inline void tracer_trace_conservative_ref(struct gc_conservative_ref ref,
|
||||||
int possibly_interior = 0;
|
int possibly_interior = 0;
|
||||||
struct gc_ref resolved = trace_conservative_ref(heap, ref, possibly_interior);
|
struct gc_ref resolved = trace_conservative_ref(heap, ref, possibly_interior);
|
||||||
if (gc_ref_is_heap_object(resolved))
|
if (gc_ref_is_heap_object(resolved))
|
||||||
gc_tracer_enqueue(resolved, heap, data);
|
gc_tracer_enqueue(&heap->tracer, resolved, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void trace_one_conservatively(struct gc_ref ref,
|
static inline void trace_one_conservatively(struct gc_ref ref,
|
||||||
|
@ -1889,7 +1900,7 @@ static void collect(struct gc_mutator *mut,
|
||||||
large_object_space_start_gc(lospace, is_minor);
|
large_object_space_start_gc(lospace, is_minor);
|
||||||
gc_extern_space_start_gc(exspace, is_minor);
|
gc_extern_space_start_gc(exspace, is_minor);
|
||||||
resolve_ephemerons_lazily(heap);
|
resolve_ephemerons_lazily(heap);
|
||||||
gc_tracer_prepare(heap);
|
gc_tracer_prepare(&heap->tracer);
|
||||||
HEAP_EVENT(heap, requesting_stop);
|
HEAP_EVENT(heap, requesting_stop);
|
||||||
request_mutators_to_stop(heap);
|
request_mutators_to_stop(heap);
|
||||||
trace_mutator_roots_with_lock_before_stop(mut);
|
trace_mutator_roots_with_lock_before_stop(mut);
|
||||||
|
@ -1906,14 +1917,14 @@ static void collect(struct gc_mutator *mut,
|
||||||
prepare_for_evacuation(heap);
|
prepare_for_evacuation(heap);
|
||||||
trace_roots_after_stop(heap);
|
trace_roots_after_stop(heap);
|
||||||
HEAP_EVENT(heap, roots_traced);
|
HEAP_EVENT(heap, roots_traced);
|
||||||
gc_tracer_trace(heap);
|
gc_tracer_trace(&heap->tracer);
|
||||||
HEAP_EVENT(heap, heap_traced);
|
HEAP_EVENT(heap, heap_traced);
|
||||||
resolve_ephemerons_eagerly(heap);
|
resolve_ephemerons_eagerly(heap);
|
||||||
while (enqueue_resolved_ephemerons(heap))
|
while (enqueue_resolved_ephemerons(heap))
|
||||||
gc_tracer_trace(heap);
|
gc_tracer_trace(&heap->tracer);
|
||||||
HEAP_EVENT(heap, ephemerons_traced);
|
HEAP_EVENT(heap, ephemerons_traced);
|
||||||
sweep_ephemerons(heap);
|
sweep_ephemerons(heap);
|
||||||
gc_tracer_release(heap);
|
gc_tracer_release(&heap->tracer);
|
||||||
mark_space_finish_gc(space, gc_kind);
|
mark_space_finish_gc(space, gc_kind);
|
||||||
large_object_space_finish_gc(lospace, is_minor);
|
large_object_space_finish_gc(lospace, is_minor);
|
||||||
gc_extern_space_finish_gc(exspace, is_minor);
|
gc_extern_space_finish_gc(exspace, is_minor);
|
||||||
|
@ -2366,7 +2377,7 @@ static int heap_init(struct gc_heap *heap, const struct gc_options *options) {
|
||||||
pthread_cond_init(&heap->collector_cond, NULL);
|
pthread_cond_init(&heap->collector_cond, NULL);
|
||||||
heap->size = options->common.heap_size;
|
heap->size = options->common.heap_size;
|
||||||
|
|
||||||
if (!gc_tracer_init(heap, options->common.parallelism))
|
if (!gc_tracer_init(&heap->tracer, heap, options->common.parallelism))
|
||||||
GC_CRASH();
|
GC_CRASH();
|
||||||
|
|
||||||
heap->pending_ephemerons_size_factor = 0.005;
|
heap->pending_ephemerons_size_factor = 0.005;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue