@@ -64,39 +64,54 @@ func JSONTraceHandler(parsed *parsedTrace) http.Handler {
64
64
log .Printf ("failed to find task with id %d" , taskid )
65
65
return
66
66
}
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
72
73
}
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
77
78
}
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
+ }
89
94
}
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
94
97
}
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 {}{}
97
112
}
98
- return cmp . Compare ( aEnd , bEnd )
99
- })
113
+ }
114
+ opts . goroutines = goroutines
100
115
}
101
116
102
117
// Parse start and end options. Both or none must be present.
@@ -149,6 +164,43 @@ type genOpts struct {
149
164
tasks []* trace.UserTaskSummary
150
165
}
151
166
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
+
152
204
func defaultGenOpts () * genOpts {
153
205
return & genOpts {
154
206
startTime : time .Duration (0 ),
0 commit comments