wingo pushed a commit to branch wip-whippet
in repository guile.

commit d675a9b8f10ccfe49a0633475c6a72bd1876ad1f
Author: Andy Wingo <wi...@igalia.com>
AuthorDate: Tue Feb 11 16:14:27 2025 +0100

    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.
---
 api/gc-lttng.h        | 29 +++++++++++++++++----
 src/parallel-tracer.h | 71 +++++++++++++++++++++++++++++++--------------------
 2 files changed, 68 insertions(+), 32 deletions(-)

diff --git a/api/gc-lttng.h b/api/gc-lttng.h
index 630e7c543..9df639b7d 100644
--- a/api/gc-lttng.h
+++ b/api/gc-lttng.h
@@ -72,11 +72,30 @@ LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
 LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
   whippet, tracepoint, whippet, mutator_removed, LTTNG_UST_TP_ARGS())
 
-/*
- * Use LTTNG_UST_TRACEPOINT_EVENT(), LTTNG_UST_TRACEPOINT_EVENT_CLASS(),
- * LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(), and
- * LTTNG_UST_TRACEPOINT_LOGLEVEL() here.
- */
+LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
+  whippet, tracepoint, whippet, trace_unpark_all, LTTNG_UST_TP_ARGS())
+LTTNG_UST_TRACEPOINT_EVENT_INSTANCE(
+  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 */
 
diff --git a/src/parallel-tracer.h b/src/parallel-tracer.h
index 8115c369d..e368c36d6 100644
--- a/src/parallel-tracer.h
+++ b/src/parallel-tracer.h
@@ -9,6 +9,7 @@
 #include "assert.h"
 #include "debug.h"
 #include "gc-inline.h"
+#include "gc-tracepoint.h"
 #include "local-worklist.h"
 #include "root-worklist.h"
 #include "shared-worklist.h"
@@ -157,6 +158,7 @@ tracer_unpark_all_workers(struct gc_tracer *tracer) {
   long epoch = old_epoch + 1;
   DEBUG("starting trace; %zu workers; epoch=%ld\n", tracer->worker_count,
         epoch);
+  GC_TRACEPOINT(trace_unpark_all);
   pthread_cond_broadcast(&tracer->cond);
 }
 
@@ -171,6 +173,7 @@ tracer_maybe_unpark_workers(struct gc_tracer *tracer) {
 static inline void
 tracer_share(struct gc_trace_worker *worker) {
   DEBUG("tracer #%zu: sharing\n", worker->id);
+  GC_TRACEPOINT(trace_share);
   size_t to_share = LOCAL_WORKLIST_SHARE_AMOUNT;
   while (to_share) {
     struct gc_ref *objv;
@@ -235,40 +238,45 @@ trace_worker_can_steal_from_any(struct gc_trace_worker 
*worker,
   return 0;
 }
 
-static int
-trace_worker_should_continue(struct gc_trace_worker *worker) {
+static size_t
+trace_worker_should_continue(struct gc_trace_worker *worker, size_t 
spin_count) {
   // Helper workers should park themselves immediately if they have no work.
   if (worker->id != 0)
     return 0;
 
   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) {
-      // 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);
+  if (atomic_load_explicit(&tracer->active_tracers, memory_order_acquire) != 
1) {
+    LOG("checking for termination: tracers active, spinning #%zu\n", 
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
@@ -285,8 +293,10 @@ trace_worker_steal(struct gc_trace_worker *worker) {
       return obj;
   }
 
+  GC_TRACEPOINT(trace_steal_begin);
   LOG("tracer #%zu: trying to steal\n", worker->id);
   struct gc_ref obj = trace_worker_steal_from_any(worker, tracer);
+  GC_TRACEPOINT(trace_steal_end);
   if (!gc_ref_is_null(obj))
     return obj;
 
@@ -329,7 +339,9 @@ trace_with_data(struct gc_tracer *tracer,
     }
   } else {
     DEBUG("tracer #%zu: tracing objects\n", worker->id);
+    GC_TRACEPOINT(trace_objects_begin);
     size_t n = 0;
+    size_t spin_count = 0;
     do {
       while (1) {
         struct gc_ref ref;
@@ -343,7 +355,8 @@ trace_with_data(struct gc_tracer *tracer,
         trace_one(ref, heap, worker);
         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);
   }
@@ -354,8 +367,10 @@ trace_with_data(struct gc_tracer *tracer,
 
 static void
 trace_worker_trace(struct gc_trace_worker *worker) {
+  GC_TRACEPOINT(trace_worker_begin);
   gc_trace_worker_call_with_data(trace_with_data, worker->tracer,
                                  worker->heap, worker);
+  GC_TRACEPOINT(trace_worker_end);
 }
 
 static inline int
@@ -406,9 +421,11 @@ static inline void
 gc_tracer_trace_roots(struct gc_tracer *tracer) {
   DEBUG("starting roots-only trace\n");
 
+  GC_TRACEPOINT(trace_roots_begin);
   tracer->trace_roots_only = 1;
   gc_tracer_trace(tracer);
   tracer->trace_roots_only = 0;
+  GC_TRACEPOINT(trace_roots_end);
   
   GC_ASSERT_EQ(atomic_load(&tracer->active_tracers), 0);
   DEBUG("roots-only trace finished\n");

Reply via email to