1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-09 13:30:26 +02:00

Add tracepoints to tracer itself

Also fix an issue whereby the main thread would spin, waiting for other
active threads to finish, doing no work itself.
This commit is contained in:
Andy Wingo 2025-02-11 16:14:27 +01:00
parent 461efa98a0
commit d675a9b8f1
2 changed files with 68 additions and 32 deletions

View file

@ -72,11 +72,30 @@ LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE( LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, mutator_removed, LTTNG_UST_TP_ARGS()) whippet, tracepoint, whippet, mutator_removed, LTTNG_UST_TP_ARGS())
/* LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
* Use LTTNG_UST_TRACEPOINT_EVENT(), LTTNG_UST_TRACEPOINT_EVENT_CLASS(), whippet, tracepoint, whippet, trace_unpark_all, LTTNG_UST_TP_ARGS())
* LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(), and LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
* LTTNG_UST_TRACEPOINT_LOGLEVEL() here. whippet, tracepoint, whippet, trace_share, LTTNG_UST_TP_ARGS())
*/ LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_check_termination_begin, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_check_termination_end, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_steal_begin, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_steal_end, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_roots_begin, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_roots_end, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_objects_begin, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_objects_end, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_worker_begin, LTTNG_UST_TP_ARGS())
LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
whippet, tracepoint, whippet, trace_worker_end, LTTNG_UST_TP_ARGS())
#endif /* _TP_H */ #endif /* _TP_H */

View file

@ -9,6 +9,7 @@
#include "assert.h" #include "assert.h"
#include "debug.h" #include "debug.h"
#include "gc-inline.h" #include "gc-inline.h"
#include "gc-tracepoint.h"
#include "local-worklist.h" #include "local-worklist.h"
#include "root-worklist.h" #include "root-worklist.h"
#include "shared-worklist.h" #include "shared-worklist.h"
@ -157,6 +158,7 @@ tracer_unpark_all_workers(struct gc_tracer *tracer) {
long epoch = old_epoch + 1; long epoch = old_epoch + 1;
DEBUG("starting trace; %zu workers; epoch=%ld\n", tracer->worker_count, DEBUG("starting trace; %zu workers; epoch=%ld\n", tracer->worker_count,
epoch); epoch);
GC_TRACEPOINT(trace_unpark_all);
pthread_cond_broadcast(&tracer->cond); pthread_cond_broadcast(&tracer->cond);
} }
@ -171,6 +173,7 @@ tracer_maybe_unpark_workers(struct gc_tracer *tracer) {
static inline void static inline void
tracer_share(struct gc_trace_worker *worker) { tracer_share(struct gc_trace_worker *worker) {
DEBUG("tracer #%zu: sharing\n", worker->id); DEBUG("tracer #%zu: sharing\n", worker->id);
GC_TRACEPOINT(trace_share);
size_t to_share = LOCAL_WORKLIST_SHARE_AMOUNT; size_t to_share = LOCAL_WORKLIST_SHARE_AMOUNT;
while (to_share) { while (to_share) {
struct gc_ref *objv; struct gc_ref *objv;
@ -235,40 +238,45 @@ trace_worker_can_steal_from_any(struct gc_trace_worker *worker,
return 0; return 0;
} }
static int static size_t
trace_worker_should_continue(struct gc_trace_worker *worker) { trace_worker_should_continue(struct gc_trace_worker *worker, size_t spin_count) {
// Helper workers should park themselves immediately if they have no work. // Helper workers should park themselves immediately if they have no work.
if (worker->id != 0) if (worker->id != 0)
return 0; return 0;
struct gc_tracer *tracer = worker->tracer; struct gc_tracer *tracer = worker->tracer;
for (size_t spin_count = 0;; spin_count++) { if (atomic_load_explicit(&tracer->active_tracers, memory_order_acquire) != 1) {
if (atomic_load_explicit(&tracer->active_tracers, LOG("checking for termination: tracers active, spinning #%zu\n", spin_count);
memory_order_acquire) == 1) {
// All trace workers have exited except us, the main worker. We are
// probably done, but we need to synchronize to be sure that there is no
// work pending, for example if a worker had a spurious wakeup. Skip
// worker 0 (the main worker).
size_t locked = 1;
while (locked < tracer->worker_count) {
if (pthread_mutex_trylock(&tracer->workers[locked].lock) == 0)
locked++;
else
break;
}
int done = (locked == tracer->worker_count) &&
!trace_worker_can_steal_from_any(worker, tracer);
if (done)
return 0;
while (locked > 1)
pthread_mutex_unlock(&tracer->workers[--locked].lock);
return 1;
}
// spin
LOG("checking for termination: spinning #%zu\n", spin_count);
yield_for_spin(spin_count); yield_for_spin(spin_count);
return 1;
} }
// All trace workers have exited except us, the main worker. We are
// probably done, but we need to synchronize to be sure that there is no
// work pending, for example if a worker had a spurious wakeup. Skip
// worker 0 (the main worker).
GC_TRACEPOINT(trace_check_termination_begin);
size_t locked = 1;
while (locked < tracer->worker_count) {
if (pthread_mutex_trylock(&tracer->workers[locked].lock) == 0)
locked++;
else
break;
}
int done = (locked == tracer->worker_count) &&
!trace_worker_can_steal_from_any(worker, tracer);
GC_TRACEPOINT(trace_check_termination_end);
if (done)
return 0;
while (locked > 1)
pthread_mutex_unlock(&tracer->workers[--locked].lock);
LOG("checking for termination: failed to lock, spinning #%zu\n", spin_count);
yield_for_spin(spin_count);
return 1;
} }
static struct gc_ref static struct gc_ref
@ -285,8 +293,10 @@ trace_worker_steal(struct gc_trace_worker *worker) {
return obj; return obj;
} }
GC_TRACEPOINT(trace_steal_begin);
LOG("tracer #%zu: trying to steal\n", worker->id); LOG("tracer #%zu: trying to steal\n", worker->id);
struct gc_ref obj = trace_worker_steal_from_any(worker, tracer); struct gc_ref obj = trace_worker_steal_from_any(worker, tracer);
GC_TRACEPOINT(trace_steal_end);
if (!gc_ref_is_null(obj)) if (!gc_ref_is_null(obj))
return obj; return obj;
@ -329,7 +339,9 @@ trace_with_data(struct gc_tracer *tracer,
} }
} else { } else {
DEBUG("tracer #%zu: tracing objects\n", worker->id); DEBUG("tracer #%zu: tracing objects\n", worker->id);
GC_TRACEPOINT(trace_objects_begin);
size_t n = 0; size_t n = 0;
size_t spin_count = 0;
do { do {
while (1) { while (1) {
struct gc_ref ref; struct gc_ref ref;
@ -343,7 +355,8 @@ trace_with_data(struct gc_tracer *tracer,
trace_one(ref, heap, worker); trace_one(ref, heap, worker);
n++; n++;
} }
} while (trace_worker_should_continue(worker)); } while (trace_worker_should_continue(worker, spin_count++));
GC_TRACEPOINT(trace_objects_end);
DEBUG("tracer #%zu: done tracing, %zu objects traced\n", worker->id, n); DEBUG("tracer #%zu: done tracing, %zu objects traced\n", worker->id, n);
} }
@ -354,8 +367,10 @@ trace_with_data(struct gc_tracer *tracer,
static void static void
trace_worker_trace(struct gc_trace_worker *worker) { trace_worker_trace(struct gc_trace_worker *worker) {
GC_TRACEPOINT(trace_worker_begin);
gc_trace_worker_call_with_data(trace_with_data, worker->tracer, gc_trace_worker_call_with_data(trace_with_data, worker->tracer,
worker->heap, worker); worker->heap, worker);
GC_TRACEPOINT(trace_worker_end);
} }
static inline int static inline int
@ -406,9 +421,11 @@ static inline void
gc_tracer_trace_roots(struct gc_tracer *tracer) { gc_tracer_trace_roots(struct gc_tracer *tracer) {
DEBUG("starting roots-only trace\n"); DEBUG("starting roots-only trace\n");
GC_TRACEPOINT(trace_roots_begin);
tracer->trace_roots_only = 1; tracer->trace_roots_only = 1;
gc_tracer_trace(tracer); gc_tracer_trace(tracer);
tracer->trace_roots_only = 0; tracer->trace_roots_only = 0;
GC_TRACEPOINT(trace_roots_end);
GC_ASSERT_EQ(atomic_load(&tracer->active_tracers), 0); GC_ASSERT_EQ(atomic_load(&tracer->active_tracers), 0);
DEBUG("roots-only trace finished\n"); DEBUG("roots-only trace finished\n");