Skip to content

Commit 28f8734

Browse files
mknyszekgopherbot
authored andcommitted
cmd/trace/v2: add support for the goroutine-oriented task view
This change adds support for a goroutine-oriented task view via the /trace?taskid=<taskid> endpoint. This works but it's missing regions. That will be implemented in a follow-up CL. For #60773. For #63960. Change-Id: I086694143e5c71596ac22fc551416868f0b80923 Reviewed-on: https://go-review.googlesource.com/c/go/+/543937 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Michael Knyszek <mknyszek@google.com> Reviewed-by: Michael Pratt <mpratt@google.com>
1 parent 971f593 commit 28f8734

File tree

1 file changed

+80
-28
lines changed

1 file changed

+80
-28
lines changed

src/cmd/trace/v2/jsontrace.go

+80-28
Original file line numberDiff line numberDiff line change
@@ -64,39 +64,54 @@ func JSONTraceHandler(parsed *parsedTrace) http.Handler {
6464
log.Printf("failed to find task with id %d", taskid)
6565
return
6666
}
67-
opts.mode = traceviewer.ModeTaskOriented
68-
if task.Start != nil {
69-
opts.startTime = task.Start.Time().Sub(parsed.startTime())
70-
} else { // The task started before the trace did.
71-
opts.startTime = 0
67+
opts.setTask(parsed, task)
68+
} else if taskids := r.FormValue("taskid"); taskids != "" {
69+
taskid, err := strconv.ParseUint(taskids, 10, 64)
70+
if err != nil {
71+
log.Printf("failed to parse taskid parameter %q: %v", taskids, err)
72+
return
7273
}
73-
if task.End != nil {
74-
opts.endTime = task.End.Time().Sub(parsed.startTime())
75-
} else { // The task didn't end.
76-
opts.endTime = parsed.endTime().Sub(parsed.startTime())
74+
task, ok := parsed.summary.Tasks[tracev2.TaskID(taskid)]
75+
if !ok {
76+
log.Printf("failed to find task with id %d", taskid)
77+
return
7778
}
78-
opts.tasks = task.Descendents()
79-
slices.SortStableFunc(opts.tasks, func(a, b *trace.UserTaskSummary) int {
80-
aStart, bStart := parsed.startTime(), parsed.startTime()
81-
if a.Start != nil {
82-
aStart = a.Start.Time()
83-
}
84-
if b.Start != nil {
85-
bStart = b.Start.Time()
86-
}
87-
if a.Start != b.Start {
88-
return cmp.Compare(aStart, bStart)
79+
// This mode is goroutine-oriented.
80+
opts.mode = traceviewer.ModeGoroutineOriented
81+
opts.setTask(parsed, task)
82+
83+
// Pick the goroutine to orient ourselves around by just
84+
// trying to pick the earliest event in the task that makes
85+
// any sense. Though, we always want the start if that's there.
86+
var firstEv *tracev2.Event
87+
if task.Start != nil {
88+
firstEv = task.Start
89+
} else {
90+
for _, logEv := range task.Logs {
91+
if firstEv == nil || logEv.Time() < firstEv.Time() {
92+
firstEv = logEv
93+
}
8994
}
90-
// Break ties with the end time.
91-
aEnd, bEnd := parsed.endTime(), parsed.endTime()
92-
if a.End != nil {
93-
aEnd = a.End.Time()
95+
if task.End != nil && (firstEv == nil || task.End.Time() < firstEv.Time()) {
96+
firstEv = task.End
9497
}
95-
if b.End != nil {
96-
bEnd = b.End.Time()
98+
}
99+
if firstEv == nil || firstEv.Goroutine() == tracev2.NoGoroutine {
100+
log.Printf("failed to find task with id %d", taskid)
101+
return
102+
}
103+
104+
// Set the goroutine filtering options.
105+
goid := firstEv.Goroutine()
106+
opts.focusGoroutine = goid
107+
goroutines := make(map[tracev2.GoID]struct{})
108+
for _, task := range opts.tasks {
109+
// Find only directly involved goroutines.
110+
for id := range task.Goroutines {
111+
goroutines[id] = struct{}{}
97112
}
98-
return cmp.Compare(aEnd, bEnd)
99-
})
113+
}
114+
opts.goroutines = goroutines
100115
}
101116

102117
// Parse start and end options. Both or none must be present.
@@ -149,6 +164,43 @@ type genOpts struct {
149164
tasks []*trace.UserTaskSummary
150165
}
151166

167+
// setTask sets a task to focus on.
168+
func (opts *genOpts) setTask(parsed *parsedTrace, task *trace.UserTaskSummary) {
169+
opts.mode |= traceviewer.ModeTaskOriented
170+
if task.Start != nil {
171+
opts.startTime = task.Start.Time().Sub(parsed.startTime())
172+
} else { // The task started before the trace did.
173+
opts.startTime = 0
174+
}
175+
if task.End != nil {
176+
opts.endTime = task.End.Time().Sub(parsed.startTime())
177+
} else { // The task didn't end.
178+
opts.endTime = parsed.endTime().Sub(parsed.startTime())
179+
}
180+
opts.tasks = task.Descendents()
181+
slices.SortStableFunc(opts.tasks, func(a, b *trace.UserTaskSummary) int {
182+
aStart, bStart := parsed.startTime(), parsed.startTime()
183+
if a.Start != nil {
184+
aStart = a.Start.Time()
185+
}
186+
if b.Start != nil {
187+
bStart = b.Start.Time()
188+
}
189+
if a.Start != b.Start {
190+
return cmp.Compare(aStart, bStart)
191+
}
192+
// Break ties with the end time.
193+
aEnd, bEnd := parsed.endTime(), parsed.endTime()
194+
if a.End != nil {
195+
aEnd = a.End.Time()
196+
}
197+
if b.End != nil {
198+
bEnd = b.End.Time()
199+
}
200+
return cmp.Compare(aEnd, bEnd)
201+
})
202+
}
203+
152204
func defaultGenOpts() *genOpts {
153205
return &genOpts{
154206
startTime: time.Duration(0),

0 commit comments

Comments
 (0)