Skip to content

Commit 4e3ac99

Browse files
mknyszekgopherbot
authored andcommitted
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 <[email protected]> Auto-Submit: Michael Knyszek <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 28f8734 commit 4e3ac99

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed

src/cmd/trace/v2/gen.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ func runGenerator(ctx *traceContext, g generator, parsed *parsedTrace, opts *gen
7373
}
7474
for i, task := range opts.tasks {
7575
emitTask(ctx, task, i)
76+
if opts.mode&traceviewer.ModeGoroutineOriented != 0 {
77+
for _, region := range task.Regions {
78+
emitRegion(ctx, region)
79+
}
80+
}
7681
}
7782
g.Finish(ctx)
7883
}
@@ -130,6 +135,54 @@ func emitTask(ctx *traceContext, task *trace.UserTaskSummary, sortIndex int) {
130135
}
131136
}
132137

138+
// emitRegion emits goroutine-based slice events to the UI. The caller
139+
// must be emitting for a goroutine-oriented trace.
140+
//
141+
// TODO(mknyszek): Make regions part of the regular generator loop and
142+
// treat them like ranges so that we can emit regions in traces oriented
143+
// by proc or thread.
144+
func emitRegion(ctx *traceContext, region *trace.UserRegionSummary) {
145+
if region.Name == "" {
146+
return
147+
}
148+
// Collect information about the region.
149+
var startStack, endStack tracev2.Stack
150+
goroutine := tracev2.NoGoroutine
151+
startTime, endTime := ctx.startTime, ctx.endTime
152+
if region.Start != nil {
153+
startStack = region.Start.Stack()
154+
startTime = region.Start.Time()
155+
goroutine = region.Start.Goroutine()
156+
}
157+
if region.End != nil {
158+
endStack = region.End.Stack()
159+
endTime = region.End.Time()
160+
goroutine = region.End.Goroutine()
161+
}
162+
if goroutine == tracev2.NoGoroutine {
163+
return
164+
}
165+
arg := struct {
166+
TaskID uint64 `json:"taskid"`
167+
}{
168+
TaskID: uint64(region.TaskID),
169+
}
170+
ctx.AsyncSlice(traceviewer.AsyncSliceEvent{
171+
SliceEvent: traceviewer.SliceEvent{
172+
Name: region.Name,
173+
Ts: ctx.elapsed(startTime),
174+
Dur: endTime.Sub(startTime),
175+
Resource: uint64(goroutine),
176+
Stack: ctx.Stack(viewerFrames(startStack)),
177+
EndStack: ctx.Stack(viewerFrames(endStack)),
178+
Arg: arg,
179+
},
180+
Category: "Region",
181+
Scope: fmt.Sprintf("%x", region.TaskID),
182+
TaskColorIndex: uint64(region.TaskID),
183+
})
184+
}
185+
133186
// Building blocks for generators.
134187

135188
// stackSampleGenerator implements a generic handler for stack sample events.

src/internal/trace/traceviewer/emitter.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ type Emitter struct {
317317
resources map[uint64]string
318318
focusResource uint64
319319
tasks map[uint64]task
320+
asyncSliceSeq uint64
320321
}
321322

322323
type task struct {
@@ -376,7 +377,6 @@ func (e *Emitter) slice(s SliceEvent, sectionID uint64, cname string) {
376377
Arg: s.Arg,
377378
Cname: cname,
378379
})
379-
380380
}
381381

382382
type SliceEvent struct {
@@ -389,6 +389,50 @@ type SliceEvent struct {
389389
Arg any
390390
}
391391

392+
func (e *Emitter) AsyncSlice(s AsyncSliceEvent) {
393+
if !e.tsWithinRange(s.Ts) && !e.tsWithinRange(s.Ts+s.Dur) {
394+
return
395+
}
396+
if e.filter != nil && !e.filter(s.Resource) {
397+
return
398+
}
399+
cname := ""
400+
if s.TaskColorIndex != 0 {
401+
cname = pickTaskColor(s.TaskColorIndex)
402+
}
403+
e.asyncSliceSeq++
404+
e.OptionalEvent(&format.Event{
405+
Category: s.Category,
406+
Name: s.Name,
407+
Phase: "b",
408+
Time: viewerTime(s.Ts),
409+
TID: s.Resource,
410+
ID: e.asyncSliceSeq,
411+
Scope: s.Scope,
412+
Stack: s.Stack,
413+
Cname: cname,
414+
})
415+
e.OptionalEvent(&format.Event{
416+
Category: s.Category,
417+
Name: s.Name,
418+
Phase: "e",
419+
Time: viewerTime(s.Ts + s.Dur),
420+
TID: s.Resource,
421+
ID: e.asyncSliceSeq,
422+
Scope: s.Scope,
423+
Stack: s.EndStack,
424+
Arg: s.Arg,
425+
Cname: cname,
426+
})
427+
}
428+
429+
type AsyncSliceEvent struct {
430+
SliceEvent
431+
Category string
432+
Scope string
433+
TaskColorIndex uint64 // Take on the same color as the task with this ID.
434+
}
435+
392436
func (e *Emitter) Instant(i InstantEvent) {
393437
if !e.tsWithinRange(i.Ts) {
394438
return

0 commit comments

Comments
 (0)