// Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. /* Trace is a tool for viewing trace files. Trace files can be generated with: - runtime/trace.Start - net/http/pprof package - go test -trace Example usage: Generate a trace file with 'go test': go test -trace trace.out pkg View the trace in a web browser: go tool trace trace.out */ package main import ( "bufio" "cmd/internal/browser" "flag" "fmt" "html/template" "internal/trace" "log" "net" "net/http" "os" "sync" ) const usageMessage = "" + `Usage of 'go tool trace': Given a trace file produced by 'go test': go test -trace=trace.out pkg Open a web browser displaying trace: go tool trace [flags] [pkg.test] trace.out [pkg.test] argument is required for traces produced by Go 1.6 and below. Go 1.7 does not require the binary argument. Flags: -http=addr: HTTP service address (e.g., ':6060') ` var ( httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')") // The binary file name, left here for serveSVGProfile. programBinary string traceFile string ) func main() { flag.Usage = func() { fmt.Fprintln(os.Stderr, usageMessage) os.Exit(2) } flag.Parse() // Go 1.7 traces embed symbol info and does not require the binary. // But we optionally accept binary as first arg for Go 1.5 traces. switch flag.NArg() { case 1: traceFile = flag.Arg(0) case 2: programBinary = flag.Arg(0) traceFile = flag.Arg(1) default: flag.Usage() } ln, err := net.Listen("tcp", *httpFlag) if err != nil { dief("failed to create server socket: %v\n", err) } log.Printf("Parsing trace...") events, err := parseEvents() if err != nil { dief("%v\n", err) } log.Printf("Serializing trace...") params := &traceParams{ events: events, endTime: int64(1<<63 - 1), } data, err := generateTrace(params) if err != nil { dief("%v\n", err) } log.Printf("Splitting trace...") ranges = splitTrace(data) log.Printf("Opening browser") if !browser.Open("http://" + ln.Addr().String()) { fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String()) } // Start http server. http.HandleFunc("/", httpMain) err = http.Serve(ln, nil) dief("failed to start http server: %v\n", err) } var ranges []Range var loader struct { once sync.Once events []*trace.Event err error } func parseEvents() ([]*trace.Event, error) { loader.once.Do(func() { tracef, err := os.Open(traceFile) if err != nil { loader.err = fmt.Errorf("failed to open trace file: %v", err) return } defer tracef.Close() // Parse and symbolize. events, err := trace.Parse(bufio.NewReader(tracef), programBinary) if err != nil { loader.err = fmt.Errorf("failed to parse trace: %v", err) return } loader.events = events }) return loader.events, loader.err } // httpMain serves the starting page. func httpMain(w http.ResponseWriter, r *http.Request) { if err := templMain.Execute(w, ranges); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } } var templMain = template.Must(template.New("").Parse(`
{{if $}} {{range $e := $}} View trace ({{$e.Name}})