1
0
mirror of https://github.com/golang/go synced 2024-11-17 13:04:54 -07:00

cmd/trace/v2: emit regions in the goroutine-oriented task view

This change emits regions in the goroutine-oriented task view (the
/trace endpoint with the taskid query variable set) in the same way the
old cmd/trace does.

For #60773.
Fixes #63960.

Change-Id: If6c3e7072c694c84a7d2d6c34df668f48d3acc2a
Reviewed-on: https://go-review.googlesource.com/c/go/+/543995
Reviewed-by: Michael Pratt <mpratt@google.com>
Auto-Submit: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Michael Anthony Knyszek 2023-11-20 21:19:35 +00:00 committed by Gopher Robot
parent 28f873444d
commit 4e3ac99a33
2 changed files with 98 additions and 1 deletions

View File

@ -73,6 +73,11 @@ func runGenerator(ctx *traceContext, g generator, parsed *parsedTrace, opts *gen
}
for i, task := range opts.tasks {
emitTask(ctx, task, i)
if opts.mode&traceviewer.ModeGoroutineOriented != 0 {
for _, region := range task.Regions {
emitRegion(ctx, region)
}
}
}
g.Finish(ctx)
}
@ -130,6 +135,54 @@ func emitTask(ctx *traceContext, task *trace.UserTaskSummary, sortIndex int) {
}
}
// emitRegion emits goroutine-based slice events to the UI. The caller
// must be emitting for a goroutine-oriented trace.
//
// TODO(mknyszek): Make regions part of the regular generator loop and
// treat them like ranges so that we can emit regions in traces oriented
// by proc or thread.
func emitRegion(ctx *traceContext, region *trace.UserRegionSummary) {
if region.Name == "" {
return
}
// Collect information about the region.
var startStack, endStack tracev2.Stack
goroutine := tracev2.NoGoroutine
startTime, endTime := ctx.startTime, ctx.endTime
if region.Start != nil {
startStack = region.Start.Stack()
startTime = region.Start.Time()
goroutine = region.Start.Goroutine()
}
if region.End != nil {
endStack = region.End.Stack()
endTime = region.End.Time()
goroutine = region.End.Goroutine()
}
if goroutine == tracev2.NoGoroutine {
return
}
arg := struct {
TaskID uint64 `json:"taskid"`
}{
TaskID: uint64(region.TaskID),
}
ctx.AsyncSlice(traceviewer.AsyncSliceEvent{
SliceEvent: traceviewer.SliceEvent{
Name: region.Name,
Ts: ctx.elapsed(startTime),
Dur: endTime.Sub(startTime),
Resource: uint64(goroutine),
Stack: ctx.Stack(viewerFrames(startStack)),
EndStack: ctx.Stack(viewerFrames(endStack)),
Arg: arg,
},
Category: "Region",
Scope: fmt.Sprintf("%x", region.TaskID),
TaskColorIndex: uint64(region.TaskID),
})
}
// Building blocks for generators.
// stackSampleGenerator implements a generic handler for stack sample events.

View File

@ -317,6 +317,7 @@ type Emitter struct {
resources map[uint64]string
focusResource uint64
tasks map[uint64]task
asyncSliceSeq uint64
}
type task struct {
@ -376,7 +377,6 @@ func (e *Emitter) slice(s SliceEvent, sectionID uint64, cname string) {
Arg: s.Arg,
Cname: cname,
})
}
type SliceEvent struct {
@ -389,6 +389,50 @@ type SliceEvent struct {
Arg any
}
func (e *Emitter) AsyncSlice(s AsyncSliceEvent) {
if !e.tsWithinRange(s.Ts) && !e.tsWithinRange(s.Ts+s.Dur) {
return
}
if e.filter != nil && !e.filter(s.Resource) {
return
}
cname := ""
if s.TaskColorIndex != 0 {
cname = pickTaskColor(s.TaskColorIndex)
}
e.asyncSliceSeq++
e.OptionalEvent(&format.Event{
Category: s.Category,
Name: s.Name,
Phase: "b",
Time: viewerTime(s.Ts),
TID: s.Resource,
ID: e.asyncSliceSeq,
Scope: s.Scope,
Stack: s.Stack,
Cname: cname,
})
e.OptionalEvent(&format.Event{
Category: s.Category,
Name: s.Name,
Phase: "e",
Time: viewerTime(s.Ts + s.Dur),
TID: s.Resource,
ID: e.asyncSliceSeq,
Scope: s.Scope,
Stack: s.EndStack,
Arg: s.Arg,
Cname: cname,
})
}
type AsyncSliceEvent struct {
SliceEvent
Category string
Scope string
TaskColorIndex uint64 // Take on the same color as the task with this ID.
}
func (e *Emitter) Instant(i InstantEvent) {
if !e.tsWithinRange(i.Ts) {
return