Skip to content

Commit eeaf857

Browse files
authored
parcagpu: replace TraceInterceptor with a wrap'd TraceReporter (#3194)
parcagpu: replace TraceInterceptor with a Wrap'd TraceReporter Drop the processmanager.TraceInterceptor extension point in favor of wrapping the upstream reporter.TraceReporter (Decorator pattern). The new parcagpu.Wrap returns a cudaReporter whose ReportTraceEvent diverts TraceOriginCuda traces into gpu.InterceptTrace and reports the resulting completed traces to the inner reporter; non-CUDA traces flow through unchanged. parcagpu.Start no longer returns an interceptor — it just spawns the cupti_events ringbuf reader. This removes the only consumer of the TraceInterceptor hook (per upstream PR open-telemetry/opentelemetry-ebpf-profiler#1383 feedback from fabled and florianl); the corresponding hook can now be removed from the ebpf-profiler fork.
1 parent 873f4e3 commit eeaf857

2 files changed

Lines changed: 45 additions & 35 deletions

File tree

main.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import (
4444

4545
"go.opentelemetry.io/otel"
4646

47-
"go.opentelemetry.io/ebpf-profiler/processmanager"
47+
otelreporter "go.opentelemetry.io/ebpf-profiler/reporter"
4848
"go.opentelemetry.io/ebpf-profiler/times"
4949
"go.opentelemetry.io/ebpf-profiler/tracer"
5050
tracertypes "go.opentelemetry.io/ebpf-profiler/tracer/types"
@@ -456,10 +456,14 @@ func mainWithExitCode() flags.ExitCode {
456456
// GPU profiling generates high trace volume, increase buffer
457457
traceBufferMultiplier = 50
458458
}
459+
var traceReporter otelreporter.TraceReporter = parcaReporter
460+
if includeTracers.Has(tracertypes.CUDATracer) {
461+
traceReporter = parcagpu.Wrap(parcaReporter)
462+
}
459463
trc, err := tracer.NewTracer(mainCtx, &tracer.Config{
460464
VerboseMode: f.BPF.VerboseLogging,
461465
ExecutableReporter: parcaReporter,
462-
TraceReporter: parcaReporter,
466+
TraceReporter: traceReporter,
463467
Intervals: intervals,
464468
IncludeTracers: includeTracers,
465469
SamplesPerSecond: f.Profiling.CPUSamplingFrequency,
@@ -551,10 +555,8 @@ func mainWithExitCode() flags.ExitCode {
551555
return flags.Failure("Failed to start map monitors: %v", err)
552556
}
553557

554-
var interceptor processmanager.TraceInterceptor
555558
if includeTracers.Has(tracertypes.CUDATracer) {
556-
interceptor = parcagpu.Start(ctx, trc, parcaReporter, parcaReporter)
557-
trc.SetInterceptor(interceptor)
559+
parcagpu.Start(ctx, trc, parcaReporter, parcaReporter)
558560
}
559561

560562
go func() {

parcagpu/parcagpu.go

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// Package parcagpu reads GPU events from the eBPF profiler's cupti_events
22
// ringbuf, marries them with symbolized CUDA stack traces from the profiler's
33
// interpreter/gpu package, and reports the completed traces directly via a
4-
// TraceReporter. It is wired into the profiler through
5-
// processmanager.TraceInterceptor.
4+
// TraceReporter. CUDA stack traces from the profiler are diverted into the
5+
// GPU fixer via a Wrap'd reporter that the tracer is configured with as its
6+
// TraceReporter.
67
//
78
// Every event in the ringbuf begins with a u32 event_type discriminator at
89
// offset 0; the reader loop dispatches by tag to handlers for kernel timing,
@@ -26,27 +27,52 @@ import (
2627
"go.opentelemetry.io/ebpf-profiler/libpf"
2728
"go.opentelemetry.io/ebpf-profiler/metrics"
2829
"go.opentelemetry.io/ebpf-profiler/process"
29-
"go.opentelemetry.io/ebpf-profiler/processmanager"
3030
"go.opentelemetry.io/ebpf-profiler/reporter"
3131
"go.opentelemetry.io/ebpf-profiler/reporter/samples"
3232
"go.opentelemetry.io/ebpf-profiler/support"
3333
"go.opentelemetry.io/ebpf-profiler/tracer"
3434
)
3535

36-
// Start starts a goroutine that reads GPU events from the cupti_events ringbuf
37-
// and returns a TraceInterceptor that diverts CUDA traces (post-symbolization)
38-
// into the GPU fixer. Completed CUDA traces are reported directly via rep.
39-
// Cubin-loaded events are forwarded to exeRep for debug-file upload; if exeRep
40-
// is nil the cubin is still cached locally for PC-sample symbolization.
36+
// Wrap returns a TraceReporter that intercepts CUDA-origin traces, runs them
37+
// through the GPU fixer, and forwards the resulting completed traces (zero or
38+
// more per input) to inner. Non-CUDA traces are forwarded to inner unchanged.
39+
// Pair with Start to drain the cupti_events ringbuf for kernel-timing,
40+
// cubin-loaded, PC-sample, and stall-reason events.
41+
func Wrap(inner reporter.TraceReporter) reporter.TraceReporter {
42+
return &cudaReporter{inner: inner}
43+
}
44+
45+
type cudaReporter struct {
46+
inner reporter.TraceReporter
47+
}
48+
49+
// ReportTraceEvent diverts CUDA traces post-symbolization. Any traces
50+
// InterceptTrace returns as already-complete (graph launches, or single
51+
// launches whose timing arrived early) are reported here directly; traces
52+
// awaiting timing are retained in the fixer and emitted later from
53+
// Start's processBatch via AddTimes.
54+
func (c *cudaReporter) ReportTraceEvent(trace *libpf.Trace,
55+
meta *samples.TraceEventMeta,
56+
) error {
57+
if meta.Origin != support.TraceOriginCuda {
58+
return c.inner.ReportTraceEvent(trace, meta)
59+
}
60+
outputs := gpu.InterceptTrace(trace, meta)
61+
for i := range outputs {
62+
if err := c.inner.ReportTraceEvent(outputs[i].Trace, outputs[i].Meta); err != nil {
63+
log.Errorf("[parcagpu] failed to report CUDA trace: %v", err)
64+
}
65+
}
66+
return nil
67+
}
68+
4169
func Start(ctx context.Context, tr *tracer.Tracer,
4270
rep reporter.TraceReporter, exeRep reporter.ExecutableReporter,
43-
) processmanager.TraceInterceptor {
71+
) {
4472
cuptiEvents := tr.GetEbpfMaps()["cupti_events"]
4573
if cuptiEvents == nil {
4674
log.Warn("[cuda] cupti_events map not present; GPU profiling disabled")
47-
return func(_ *libpf.Trace, _ *samples.TraceEventMeta) bool {
48-
return false
49-
}
75+
return
5076
}
5177

5278
eventReader, err := ringbuf.NewReader(cuptiEvents)
@@ -188,24 +214,6 @@ func Start(ctx context.Context, tr *tracer.Tracer,
188214
}
189215
}
190216
}()
191-
192-
// Return the interceptor function that diverts CUDA traces post-symbolization.
193-
// Any traces InterceptTrace returns as already-complete (graph launches, or
194-
// single launches whose timing arrived early) are reported here directly;
195-
// traces awaiting timing are retained in the fixer and emitted later from
196-
// processBatch via AddTimes.
197-
return func(trace *libpf.Trace, meta *samples.TraceEventMeta) bool {
198-
if meta.Origin != support.TraceOriginCuda {
199-
return false
200-
}
201-
outputs := gpu.InterceptTrace(trace, meta)
202-
for i := range outputs {
203-
if err := rep.ReportTraceEvent(outputs[i].Trace, outputs[i].Meta); err != nil {
204-
log.Errorf("[parcagpu] failed to report CUDA trace: %v", err)
205-
}
206-
}
207-
return true
208-
}
209217
}
210218

211219
func nullTerm(b []byte) string {

0 commit comments

Comments
 (0)