aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorMichael Anthony Knyszek <mknyszek@google.com>2023-11-20 19:29:42 +0000
committerGopher Robot <gobot@golang.org>2023-11-21 21:29:55 +0000
commit28f873444d4e7fdfef9c07108002cd6347a8da0f (patch)
tree3f57f641c8600c77e268809d7c6e84806345bad3 /src/cmd
parent971f59399fd7a53dc0744a949084080c85b3c62b (diff)
downloadgo-28f873444d4e7fdfef9c07108002cd6347a8da0f.tar.xz
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>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/trace/v2/jsontrace.go108
1 files changed, 80 insertions, 28 deletions
diff --git a/src/cmd/trace/v2/jsontrace.go b/src/cmd/trace/v2/jsontrace.go
index 85ee52e47e..e4ca613678 100644
--- a/src/cmd/trace/v2/jsontrace.go
+++ b/src/cmd/trace/v2/jsontrace.go
@@ -64,39 +64,54 @@ func JSONTraceHandler(parsed *parsedTrace) http.Handler {
log.Printf("failed to find task with id %d", taskid)
return
}
- opts.mode = traceviewer.ModeTaskOriented
- if task.Start != nil {
- opts.startTime = task.Start.Time().Sub(parsed.startTime())
- } else { // The task started before the trace did.
- opts.startTime = 0
+ opts.setTask(parsed, task)
+ } else if taskids := r.FormValue("taskid"); taskids != "" {
+ taskid, err := strconv.ParseUint(taskids, 10, 64)
+ if err != nil {
+ log.Printf("failed to parse taskid parameter %q: %v", taskids, err)
+ return
}
- if task.End != nil {
- opts.endTime = task.End.Time().Sub(parsed.startTime())
- } else { // The task didn't end.
- opts.endTime = parsed.endTime().Sub(parsed.startTime())
+ task, ok := parsed.summary.Tasks[tracev2.TaskID(taskid)]
+ if !ok {
+ log.Printf("failed to find task with id %d", taskid)
+ return
}
- opts.tasks = task.Descendents()
- slices.SortStableFunc(opts.tasks, func(a, b *trace.UserTaskSummary) int {
- aStart, bStart := parsed.startTime(), parsed.startTime()
- if a.Start != nil {
- aStart = a.Start.Time()
- }
- if b.Start != nil {
- bStart = b.Start.Time()
- }
- if a.Start != b.Start {
- return cmp.Compare(aStart, bStart)
+ // This mode is goroutine-oriented.
+ opts.mode = traceviewer.ModeGoroutineOriented
+ opts.setTask(parsed, task)
+
+ // Pick the goroutine to orient ourselves around by just
+ // trying to pick the earliest event in the task that makes
+ // any sense. Though, we always want the start if that's there.
+ var firstEv *tracev2.Event
+ if task.Start != nil {
+ firstEv = task.Start
+ } else {
+ for _, logEv := range task.Logs {
+ if firstEv == nil || logEv.Time() < firstEv.Time() {
+ firstEv = logEv
+ }
}
- // Break ties with the end time.
- aEnd, bEnd := parsed.endTime(), parsed.endTime()
- if a.End != nil {
- aEnd = a.End.Time()
+ if task.End != nil && (firstEv == nil || task.End.Time() < firstEv.Time()) {
+ firstEv = task.End
}
- if b.End != nil {
- bEnd = b.End.Time()
+ }
+ if firstEv == nil || firstEv.Goroutine() == tracev2.NoGoroutine {
+ log.Printf("failed to find task with id %d", taskid)
+ return
+ }
+
+ // Set the goroutine filtering options.
+ goid := firstEv.Goroutine()
+ opts.focusGoroutine = goid
+ goroutines := make(map[tracev2.GoID]struct{})
+ for _, task := range opts.tasks {
+ // Find only directly involved goroutines.
+ for id := range task.Goroutines {
+ goroutines[id] = struct{}{}
}
- return cmp.Compare(aEnd, bEnd)
- })
+ }
+ opts.goroutines = goroutines
}
// Parse start and end options. Both or none must be present.
@@ -149,6 +164,43 @@ type genOpts struct {
tasks []*trace.UserTaskSummary
}
+// setTask sets a task to focus on.
+func (opts *genOpts) setTask(parsed *parsedTrace, task *trace.UserTaskSummary) {
+ opts.mode |= traceviewer.ModeTaskOriented
+ if task.Start != nil {
+ opts.startTime = task.Start.Time().Sub(parsed.startTime())
+ } else { // The task started before the trace did.
+ opts.startTime = 0
+ }
+ if task.End != nil {
+ opts.endTime = task.End.Time().Sub(parsed.startTime())
+ } else { // The task didn't end.
+ opts.endTime = parsed.endTime().Sub(parsed.startTime())
+ }
+ opts.tasks = task.Descendents()
+ slices.SortStableFunc(opts.tasks, func(a, b *trace.UserTaskSummary) int {
+ aStart, bStart := parsed.startTime(), parsed.startTime()
+ if a.Start != nil {
+ aStart = a.Start.Time()
+ }
+ if b.Start != nil {
+ bStart = b.Start.Time()
+ }
+ if a.Start != b.Start {
+ return cmp.Compare(aStart, bStart)
+ }
+ // Break ties with the end time.
+ aEnd, bEnd := parsed.endTime(), parsed.endTime()
+ if a.End != nil {
+ aEnd = a.End.Time()
+ }
+ if b.End != nil {
+ bEnd = b.End.Time()
+ }
+ return cmp.Compare(aEnd, bEnd)
+ })
+}
+
func defaultGenOpts() *genOpts {
return &genOpts{
startTime: time.Duration(0),