Home | History | Annotate | Download | only in trace
      1 // Copyright 2014 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 /*
      6 Trace is a tool for viewing trace files.
      7 
      8 Trace files can be generated with:
      9 	- runtime/trace.Start
     10 	- net/http/pprof package
     11 	- go test -trace
     12 
     13 Example usage:
     14 Generate a trace file with 'go test':
     15 	go test -trace trace.out pkg
     16 View the trace in a web browser:
     17 	go tool trace pkg.test trace.out
     18 */
     19 package main
     20 
     21 import (
     22 	"bufio"
     23 	"flag"
     24 	"fmt"
     25 	"internal/trace"
     26 	"net"
     27 	"net/http"
     28 	"os"
     29 	"os/exec"
     30 	"runtime"
     31 	"sync"
     32 )
     33 
     34 const usageMessage = "" +
     35 	`Usage of 'go tool trace':
     36 Given a trace file produced by 'go test':
     37 	go test -trace=trace.out pkg
     38 
     39 Open a web browser displaying trace:
     40 	go tool trace [flags] pkg.test trace.out
     41 
     42 Flags:
     43 	-http=addr: HTTP service address (e.g., ':6060')
     44 `
     45 
     46 var (
     47 	httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
     48 
     49 	// The binary file name, left here for serveSVGProfile.
     50 	programBinary string
     51 	traceFile     string
     52 )
     53 
     54 func main() {
     55 	flag.Usage = func() {
     56 		fmt.Fprintln(os.Stderr, usageMessage)
     57 		os.Exit(2)
     58 	}
     59 	flag.Parse()
     60 
     61 	// Usage information when no arguments.
     62 	if flag.NArg() != 2 {
     63 		flag.Usage()
     64 	}
     65 	programBinary = flag.Arg(0)
     66 	traceFile = flag.Arg(1)
     67 
     68 	ln, err := net.Listen("tcp", *httpFlag)
     69 	if err != nil {
     70 		dief("failed to create server socket: %v\n", err)
     71 	}
     72 	// Open browser.
     73 	if !startBrowser("http://" + ln.Addr().String()) {
     74 		dief("failed to start browser\n")
     75 	}
     76 
     77 	// Parse and symbolize trace asynchronously while browser opens.
     78 	go parseEvents()
     79 
     80 	// Start http server.
     81 	http.HandleFunc("/", httpMain)
     82 	err = http.Serve(ln, nil)
     83 	dief("failed to start http server: %v\n", err)
     84 }
     85 
     86 var loader struct {
     87 	once   sync.Once
     88 	events []*trace.Event
     89 	err    error
     90 }
     91 
     92 func parseEvents() ([]*trace.Event, error) {
     93 	loader.once.Do(func() {
     94 		tracef, err := os.Open(flag.Arg(1))
     95 		if err != nil {
     96 			loader.err = fmt.Errorf("failed to open trace file: %v", err)
     97 			return
     98 		}
     99 		defer tracef.Close()
    100 
    101 		// Parse and symbolize.
    102 		events, err := trace.Parse(bufio.NewReader(tracef))
    103 		if err != nil {
    104 			loader.err = fmt.Errorf("failed to parse trace: %v", err)
    105 			return
    106 		}
    107 		err = trace.Symbolize(events, programBinary)
    108 		if err != nil {
    109 			loader.err = fmt.Errorf("failed to symbolize trace: %v", err)
    110 			return
    111 		}
    112 		loader.events = events
    113 	})
    114 	return loader.events, loader.err
    115 }
    116 
    117 // httpMain serves the starting page.
    118 func httpMain(w http.ResponseWriter, r *http.Request) {
    119 	w.Write(templMain)
    120 }
    121 
    122 var templMain = []byte(`
    123 <html>
    124 <body>
    125 <a href="/trace">View trace</a><br>
    126 <a href="/goroutines">Goroutine analysis</a><br>
    127 <a href="/io">Network blocking profile</a><br>
    128 <a href="/block">Synchronization blocking profile</a><br>
    129 <a href="/syscall">Syscall blocking profile</a><br>
    130 <a href="/sched">Scheduler latency profile</a><br>
    131 </body>
    132 </html>
    133 `)
    134 
    135 // startBrowser tries to open the URL in a browser
    136 // and reports whether it succeeds.
    137 // Note: copied from x/tools/cmd/cover/html.go
    138 func startBrowser(url string) bool {
    139 	// try to start the browser
    140 	var args []string
    141 	switch runtime.GOOS {
    142 	case "darwin":
    143 		args = []string{"open"}
    144 	case "windows":
    145 		args = []string{"cmd", "/c", "start"}
    146 	default:
    147 		args = []string{"xdg-open"}
    148 	}
    149 	cmd := exec.Command(args[0], append(args[1:], url)...)
    150 	return cmd.Start() == nil
    151 }
    152 
    153 func dief(msg string, args ...interface{}) {
    154 	fmt.Fprintf(os.Stderr, msg, args...)
    155 	os.Exit(1)
    156 }
    157