Skip to content

Commit 08816cb

Browse files
committed
cmd/trace: use new traceparser to parse the raw trace files
Change-Id: I8b224ae48a2f8acd5a64c9ff283e97821479a9a8 Reviewed-on: https://go-review.googlesource.com/c/145457 Run-TryBot: Peter Weinberger <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
1 parent f570b54 commit 08816cb

File tree

8 files changed

+194
-177
lines changed

8 files changed

+194
-177
lines changed

src/cmd/trace/annotations.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"bytes"
99
"fmt"
1010
"html/template"
11-
"internal/trace"
1211
"log"
1312
"math"
1413
"net/http"
@@ -17,6 +16,8 @@ import (
1716
"strconv"
1817
"strings"
1918
"time"
19+
20+
trace "internal/traceparser"
2021
)
2122

2223
func init() {
@@ -308,7 +309,7 @@ func analyzeAnnotations() (annotationAnalysisResult, error) {
308309
}
309310
}
310311
// combine region info.
311-
analyzeGoroutines(events)
312+
analyzeGoroutines(res)
312313
for goid, stats := range gs {
313314
// gs is a global var defined in goroutines.go as a result
314315
// of analyzeGoroutines. TODO(hyangah): fix this not to depend
@@ -321,7 +322,7 @@ func analyzeAnnotations() (annotationAnalysisResult, error) {
321322
}
322323
var frame trace.Frame
323324
if s.Start != nil {
324-
frame = *s.Start.Stk[0]
325+
frame = *res.Stacks[s.Start.StkID][0]
325326
}
326327
id := regionTypeID{Frame: frame, Type: s.Name}
327328
regions[id] = append(regions[id], regionDesc{UserRegionDesc: s, G: goid})

src/cmd/trace/annotations_test.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"context"
1212
"flag"
1313
"fmt"
14-
traceparser "internal/trace"
14+
"internal/traceparser"
1515
"io/ioutil"
1616
"reflect"
1717
"runtime/debug"
@@ -338,10 +338,8 @@ func traceProgram(t *testing.T, f func(), name string) error {
338338
trace.Stop()
339339

340340
saveTrace(buf, name)
341-
res, err := traceparser.Parse(buf, name+".faketrace")
342-
if err == traceparser.ErrTimeOrder {
343-
t.Skipf("skipping due to golang.org/issue/16755: %v", err)
344-
} else if err != nil {
341+
res, err := traceparser.ParseBuffer(buf)
342+
if err != nil {
345343
return err
346344
}
347345

@@ -370,15 +368,15 @@ func childrenNames(task *taskDesc) (ret []string) {
370368
return ret
371369
}
372370

373-
func swapLoaderData(res traceparser.ParseResult, err error) {
371+
func swapLoaderData(res *traceparser.Parsed, err error) {
374372
// swap loader's data.
375373
parseTrace() // fool loader.once.
376374

377375
loader.res = res
378376
loader.err = err
379377

380-
analyzeGoroutines(nil) // fool gsInit once.
381-
gs = traceparser.GoroutineStats(res.Events)
378+
analyzeGoroutines(res) // fool gsInit once.
379+
gs = res.GoroutineStats()
382380

383381
}
384382

src/cmd/trace/goroutines.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@ package main
99
import (
1010
"fmt"
1111
"html/template"
12-
"internal/trace"
1312
"log"
1413
"net/http"
1514
"reflect"
1615
"sort"
1716
"strconv"
1817
"sync"
1918
"time"
19+
20+
trace "internal/traceparser"
2021
)
2122

2223
func init() {
@@ -38,15 +39,15 @@ var (
3839
)
3940

4041
// analyzeGoroutines generates statistics about execution of all goroutines and stores them in gs.
41-
func analyzeGoroutines(events []*trace.Event) {
42+
func analyzeGoroutines(res *trace.Parsed) {
4243
gsInit.Do(func() {
43-
gs = trace.GoroutineStats(events)
44+
gs = res.GoroutineStats()
4445
})
4546
}
4647

4748
// httpGoroutines serves list of goroutine groups.
4849
func httpGoroutines(w http.ResponseWriter, r *http.Request) {
49-
events, err := parseEvents()
50+
events, err := parseTrace()
5051
if err != nil {
5152
http.Error(w, err.Error(), http.StatusInternalServerError)
5253
return
@@ -89,7 +90,7 @@ Goroutines: <br>
8990
func httpGoroutine(w http.ResponseWriter, r *http.Request) {
9091
// TODO(hyangah): support format=csv (raw data)
9192

92-
events, err := parseEvents()
93+
events, err := parseTrace()
9394
if err != nil {
9495
http.Error(w, err.Error(), http.StatusInternalServerError)
9596
return

src/cmd/trace/main.go

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@
55
package main
66

77
import (
8-
"bufio"
8+
"bytes"
99
"cmd/internal/browser"
1010
"flag"
1111
"fmt"
1212
"html/template"
13-
"internal/trace"
13+
trace "internal/traceparser"
1414
"io"
1515
"log"
1616
"net"
@@ -115,8 +115,22 @@ func main() {
115115
dief("%v\n", err)
116116
}
117117

118-
if *debugFlag {
119-
trace.Print(res.Events)
118+
if *debugFlag { // match go tool trace -d (except for Offset and Seq)
119+
f := func(ev *trace.Event) {
120+
desc := trace.EventDescriptions[ev.Type]
121+
w := new(bytes.Buffer)
122+
fmt.Fprintf(w, "%v %v p=%v g=%v", ev.Ts, desc.Name, ev.P, ev.G)
123+
for i, a := range desc.Args {
124+
fmt.Fprintf(w, " %v=%v", a, ev.Args[i])
125+
}
126+
for i, a := range desc.SArgs {
127+
fmt.Fprintf(w, " %v=%v", a, ev.SArgs[i])
128+
}
129+
fmt.Println(w.String())
130+
}
131+
for i := 0; i < len(res.Events); i++ {
132+
f(res.Events[i])
133+
}
120134
os.Exit(0)
121135
}
122136
reportMemoryUsage("after parsing trace")
@@ -141,36 +155,23 @@ var ranges []Range
141155

142156
var loader struct {
143157
once sync.Once
144-
res trace.ParseResult
158+
res *trace.Parsed
145159
err error
146160
}
147161

148-
// parseEvents is a compatibility wrapper that returns only
149-
// the Events part of trace.ParseResult returned by parseTrace.
150-
func parseEvents() ([]*trace.Event, error) {
151-
res, err := parseTrace()
152-
if err != nil {
153-
return nil, err
154-
}
155-
return res.Events, err
156-
}
157-
158-
func parseTrace() (trace.ParseResult, error) {
162+
func parseTrace() (*trace.Parsed, error) {
159163
loader.once.Do(func() {
160-
tracef, err := os.Open(traceFile)
164+
x, err := trace.New(traceFile)
161165
if err != nil {
162-
loader.err = fmt.Errorf("failed to open trace file: %v", err)
166+
loader.err = err
163167
return
164168
}
165-
defer tracef.Close()
166-
167-
// Parse and symbolize.
168-
res, err := trace.Parse(bufio.NewReader(tracef), programBinary)
169+
err = x.Parse(0, x.MaxTs, nil)
169170
if err != nil {
170-
loader.err = fmt.Errorf("failed to parse trace: %v", err)
171+
loader.err = err
171172
return
172173
}
173-
loader.res = res
174+
loader.res = x
174175
})
175176
return loader.res, loader.err
176177
}

src/cmd/trace/pprof.go

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ package main
99
import (
1010
"bufio"
1111
"fmt"
12-
"internal/trace"
1312
"io"
1413
"io/ioutil"
1514
"net/http"
@@ -21,6 +20,8 @@ import (
2120
"strconv"
2221
"time"
2322

23+
trace "internal/traceparser"
24+
2425
"github.com/google/pprof/profile"
2526
)
2627

@@ -60,22 +61,22 @@ type interval struct {
6061
begin, end int64 // nanoseconds.
6162
}
6263

63-
func pprofByGoroutine(compute func(io.Writer, map[uint64][]interval, []*trace.Event) error) func(w io.Writer, r *http.Request) error {
64+
func pprofByGoroutine(compute func(io.Writer, map[uint64][]interval, *trace.Parsed) error) func(w io.Writer, r *http.Request) error {
6465
return func(w io.Writer, r *http.Request) error {
6566
id := r.FormValue("id")
66-
events, err := parseEvents()
67+
res, err := parseTrace()
6768
if err != nil {
6869
return err
6970
}
70-
gToIntervals, err := pprofMatchingGoroutines(id, events)
71+
gToIntervals, err := pprofMatchingGoroutines(id, res)
7172
if err != nil {
7273
return err
7374
}
74-
return compute(w, gToIntervals, events)
75+
return compute(w, gToIntervals, res)
7576
}
7677
}
7778

78-
func pprofByRegion(compute func(io.Writer, map[uint64][]interval, []*trace.Event) error) func(w io.Writer, r *http.Request) error {
79+
func pprofByRegion(compute func(io.Writer, map[uint64][]interval, *trace.Parsed) error) func(w io.Writer, r *http.Request) error {
7980
return func(w io.Writer, r *http.Request) error {
8081
filter, err := newRegionFilter(r)
8182
if err != nil {
@@ -85,7 +86,7 @@ func pprofByRegion(compute func(io.Writer, map[uint64][]interval, []*trace.Event
8586
if err != nil {
8687
return err
8788
}
88-
events, _ := parseEvents()
89+
events, _ := parseTrace()
8990

9091
return compute(w, gToIntervals, events)
9192
}
@@ -94,15 +95,15 @@ func pprofByRegion(compute func(io.Writer, map[uint64][]interval, []*trace.Event
9495
// pprofMatchingGoroutines parses the goroutine type id string (i.e. pc)
9596
// and returns the ids of goroutines of the matching type and its interval.
9697
// If the id string is empty, returns nil without an error.
97-
func pprofMatchingGoroutines(id string, events []*trace.Event) (map[uint64][]interval, error) {
98+
func pprofMatchingGoroutines(id string, p *trace.Parsed) (map[uint64][]interval, error) {
9899
if id == "" {
99100
return nil, nil
100101
}
101102
pc, err := strconv.ParseUint(id, 10, 64) // id is string
102103
if err != nil {
103104
return nil, fmt.Errorf("invalid goroutine type: %v", id)
104105
}
105-
analyzeGoroutines(events)
106+
analyzeGoroutines(p)
106107
var res map[uint64][]interval
107108
for _, g := range gs {
108109
if g.PC != pc {
@@ -171,17 +172,25 @@ func pprofMatchingRegions(filter *regionFilter) (map[uint64][]interval, error) {
171172
return gToIntervals, nil
172173
}
173174

175+
func stklen(p *trace.Parsed, ev *trace.Event) int {
176+
if ev.StkID == 0 {
177+
return 0
178+
}
179+
return len(p.Stacks[ev.StkID])
180+
}
181+
174182
// computePprofIO generates IO pprof-like profile (time spent in IO wait, currently only network blocking event).
175-
func computePprofIO(w io.Writer, gToIntervals map[uint64][]interval, events []*trace.Event) error {
176-
prof := make(map[uint64]Record)
183+
func computePprofIO(w io.Writer, gToIntervals map[uint64][]interval, res *trace.Parsed) error {
184+
events := res.Events
185+
prof := make(map[uint32]Record)
177186
for _, ev := range events {
178-
if ev.Type != trace.EvGoBlockNet || ev.Link == nil || ev.StkID == 0 || len(ev.Stk) == 0 {
187+
if ev.Type != trace.EvGoBlockNet || ev.Link == nil || ev.StkID == 0 || stklen(res, ev) == 0 {
179188
continue
180189
}
181190
overlapping := pprofOverlappingDuration(gToIntervals, ev)
182191
if overlapping > 0 {
183192
rec := prof[ev.StkID]
184-
rec.stk = ev.Stk
193+
rec.stk = res.Stacks[ev.StkID]
185194
rec.n++
186195
rec.time += overlapping.Nanoseconds()
187196
prof[ev.StkID] = rec
@@ -191,8 +200,9 @@ func computePprofIO(w io.Writer, gToIntervals map[uint64][]interval, events []*t
191200
}
192201

193202
// computePprofBlock generates blocking pprof-like profile (time spent blocked on synchronization primitives).
194-
func computePprofBlock(w io.Writer, gToIntervals map[uint64][]interval, events []*trace.Event) error {
195-
prof := make(map[uint64]Record)
203+
func computePprofBlock(w io.Writer, gToIntervals map[uint64][]interval, res *trace.Parsed) error {
204+
events := res.Events
205+
prof := make(map[uint32]Record)
196206
for _, ev := range events {
197207
switch ev.Type {
198208
case trace.EvGoBlockSend, trace.EvGoBlockRecv, trace.EvGoBlockSelect,
@@ -203,13 +213,13 @@ func computePprofBlock(w io.Writer, gToIntervals map[uint64][]interval, events [
203213
default:
204214
continue
205215
}
206-
if ev.Link == nil || ev.StkID == 0 || len(ev.Stk) == 0 {
216+
if ev.Link == nil || ev.StkID == 0 || stklen(res, ev) == 0 {
207217
continue
208218
}
209219
overlapping := pprofOverlappingDuration(gToIntervals, ev)
210220
if overlapping > 0 {
211221
rec := prof[ev.StkID]
212-
rec.stk = ev.Stk
222+
rec.stk = res.Stacks[ev.StkID]
213223
rec.n++
214224
rec.time += overlapping.Nanoseconds()
215225
prof[ev.StkID] = rec
@@ -219,16 +229,17 @@ func computePprofBlock(w io.Writer, gToIntervals map[uint64][]interval, events [
219229
}
220230

221231
// computePprofSyscall generates syscall pprof-like profile (time spent blocked in syscalls).
222-
func computePprofSyscall(w io.Writer, gToIntervals map[uint64][]interval, events []*trace.Event) error {
223-
prof := make(map[uint64]Record)
232+
func computePprofSyscall(w io.Writer, gToIntervals map[uint64][]interval, res *trace.Parsed) error {
233+
events := res.Events
234+
prof := make(map[uint32]Record)
224235
for _, ev := range events {
225-
if ev.Type != trace.EvGoSysCall || ev.Link == nil || ev.StkID == 0 || len(ev.Stk) == 0 {
236+
if ev.Type != trace.EvGoSysCall || ev.Link == nil || ev.StkID == 0 || stklen(res, ev) == 0 {
226237
continue
227238
}
228239
overlapping := pprofOverlappingDuration(gToIntervals, ev)
229240
if overlapping > 0 {
230241
rec := prof[ev.StkID]
231-
rec.stk = ev.Stk
242+
rec.stk = res.Stacks[ev.StkID]
232243
rec.n++
233244
rec.time += overlapping.Nanoseconds()
234245
prof[ev.StkID] = rec
@@ -239,17 +250,18 @@ func computePprofSyscall(w io.Writer, gToIntervals map[uint64][]interval, events
239250

240251
// computePprofSched generates scheduler latency pprof-like profile
241252
// (time between a goroutine become runnable and actually scheduled for execution).
242-
func computePprofSched(w io.Writer, gToIntervals map[uint64][]interval, events []*trace.Event) error {
243-
prof := make(map[uint64]Record)
253+
func computePprofSched(w io.Writer, gToIntervals map[uint64][]interval, res *trace.Parsed) error {
254+
events := res.Events
255+
prof := make(map[uint32]Record)
244256
for _, ev := range events {
245257
if (ev.Type != trace.EvGoUnblock && ev.Type != trace.EvGoCreate) ||
246-
ev.Link == nil || ev.StkID == 0 || len(ev.Stk) == 0 {
258+
ev.Link == nil || ev.StkID == 0 || stklen(res, ev) == 0 {
247259
continue
248260
}
249261
overlapping := pprofOverlappingDuration(gToIntervals, ev)
250262
if overlapping > 0 {
251263
rec := prof[ev.StkID]
252-
rec.stk = ev.Stk
264+
rec.stk = res.Stacks[ev.StkID]
253265
rec.n++
254266
rec.time += overlapping.Nanoseconds()
255267
prof[ev.StkID] = rec
@@ -327,7 +339,7 @@ func serveSVGProfile(prof func(w io.Writer, r *http.Request) error) http.Handler
327339
}
328340
}
329341

330-
func buildProfile(prof map[uint64]Record) *profile.Profile {
342+
func buildProfile(prof map[uint32]Record) *profile.Profile {
331343
p := &profile.Profile{
332344
PeriodType: &profile.ValueType{Type: "trace", Unit: "count"},
333345
Period: 1,

0 commit comments

Comments
 (0)