Skip to content

Commit

Permalink
cmd/trace/v2: add support for pprof endpoints
Browse files Browse the repository at this point in the history
This change adds support for the pprof endpoints to cmd/trace/v2.

In the process, I realized we need to pass the goroutine summaries to
more places, and previous CLs had already done the goroutine analysis
during cmd/trace startup. This change thus refactors the goroutine
analysis API once again to operate in a streaming manner, and to run
at the same time as the initial trace parsing. Now we can include it in
the parsedTrace type and pass that around as the de-facto global trace
context.

Note: for simplicity, this change redefines "syscall" profiles to
capture *all* syscalls, not just syscalls that block. IIUC, this choice
was partly the result of a limitation in the previous trace format that
syscalls don't all have complete durations and many short syscalls are
treated as instant. To this end, this change modifies the text on the
main trace webpage to reflect this change.

For #60773.
For #63960.

Change-Id: I601d9250ab0849a0bfaef233fd9b1e81aca9a22a
Reviewed-on: https://go-review.googlesource.com/c/go/+/541999
Auto-Submit: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
  • Loading branch information
mknyszek committed Nov 21, 2023
1 parent b839348 commit d1dcffd
Show file tree
Hide file tree
Showing 6 changed files with 532 additions and 71 deletions.
2 changes: 1 addition & 1 deletion src/cmd/trace/v2/goroutines.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ Table of contents
<td> <a href="/block?id={{.PC}}">graph</a> <a href="/block?id={{.PC}}&raw=1" download="block.profile">(download)</a></td>
</tr>
<tr>
<td>Syscall block profile:</td>
<td>Syscall profile:</td>
<td> <a href="/syscall?id={{.PC}}">graph</a> <a href="/syscall?id={{.PC}}&raw=1" download="syscall.profile">(download)</a></td>
</tr>
<tr>
Expand Down
48 changes: 39 additions & 9 deletions src/cmd/trace/v2/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ func Main(traceFile, httpAddr, pprof string, debug int) error {
if err != nil {
return err
}
log.Printf("Analyzing goroutines...")
gSummaries := trace.SummarizeGoroutines(parsed.events)

log.Printf("Opening browser. Trace viewer is listening on %s", addr)
browser.Open(addr)
Expand All @@ -67,28 +65,50 @@ func Main(traceFile, httpAddr, pprof string, debug int) error {
}

mux := http.NewServeMux()

// Main endpoint.
mux.Handle("/", traceviewer.MainHandler(ranges))

// Catapult handlers.
mux.Handle("/trace", traceviewer.TraceHandler())
mux.Handle("/jsontrace", JSONTraceHandler(parsed))
mux.Handle("/static/", traceviewer.StaticHandler())
mux.HandleFunc("/goroutines", GoroutinesHandlerFunc(gSummaries))
mux.HandleFunc("/goroutine", GoroutineHandler(gSummaries))

// Goroutines handlers.
mux.HandleFunc("/goroutines", GoroutinesHandlerFunc(parsed.gSummaries))
mux.HandleFunc("/goroutine", GoroutineHandler(parsed.gSummaries))

// MMU handler.
mux.HandleFunc("/mmu", traceviewer.MMUHandlerFunc(ranges, mutatorUtil))

// Basic pprof endpoints.
mux.HandleFunc("/io", traceviewer.SVGProfileHandlerFunc(pprofByGoroutine(computePprofIO(), parsed)))
mux.HandleFunc("/block", traceviewer.SVGProfileHandlerFunc(pprofByGoroutine(computePprofBlock(), parsed)))
mux.HandleFunc("/syscall", traceviewer.SVGProfileHandlerFunc(pprofByGoroutine(computePprofSyscall(), parsed)))
mux.HandleFunc("/sched", traceviewer.SVGProfileHandlerFunc(pprofByGoroutine(computePprofSched(), parsed)))

// Region-based pprof endpoints.
mux.HandleFunc("/regionio", traceviewer.SVGProfileHandlerFunc(pprofByRegion(computePprofIO(), parsed)))
mux.HandleFunc("/regionblock", traceviewer.SVGProfileHandlerFunc(pprofByRegion(computePprofBlock(), parsed)))
mux.HandleFunc("/regionsyscall", traceviewer.SVGProfileHandlerFunc(pprofByRegion(computePprofSyscall(), parsed)))
mux.HandleFunc("/regionsched", traceviewer.SVGProfileHandlerFunc(pprofByRegion(computePprofSched(), parsed)))

err = http.Serve(ln, mux)
return fmt.Errorf("failed to start http server: %w", err)
}

type parsedTrace struct {
events []tracev2.Event
events []tracev2.Event
gSummaries map[tracev2.GoID]*trace.GoroutineSummary
}

func parseTrace(trace io.Reader) (*parsedTrace, error) {
r, err := tracev2.NewReader(trace)
func parseTrace(tr io.Reader) (*parsedTrace, error) {
r, err := tracev2.NewReader(tr)
if err != nil {
return nil, fmt.Errorf("failed to create trace reader: %w", err)
}
var t parsedTrace
s := trace.NewGoroutineSummarizer()
t := new(parsedTrace)
for {
ev, err := r.ReadEvent()
if err == io.EOF {
Expand All @@ -97,8 +117,18 @@ func parseTrace(trace io.Reader) (*parsedTrace, error) {
return nil, fmt.Errorf("failed to read event: %w", err)
}
t.events = append(t.events, ev)
s.Event(&t.events[len(t.events)-1])
}
return &t, nil
t.gSummaries = s.Finalize()
return t, nil
}

func (t *parsedTrace) startTime() tracev2.Time {
return t.events[0].Time()
}

func (t *parsedTrace) endTime() tracev2.Time {
return t.events[len(t.events)-1].Time()
}

// splitTrace splits the trace into a number of ranges, each resulting in approx 100 MiB of
Expand Down
Loading

0 comments on commit d1dcffd

Please sign in to comment.