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 trace.out
     18 Generate a pprof-like profile from the trace:
     19 	go tool trace -pprof=TYPE trace.out > TYPE.pprof
     20 
     21 Supported profile types are:
     22 	- net: network blocking profile
     23 	- sync: synchronization blocking profile
     24 	- syscall: syscall blocking profile
     25 	- sched: scheduler latency profile
     26 */
     27 package main
     28 
     29 import (
     30 	"bufio"
     31 	"cmd/internal/browser"
     32 	"flag"
     33 	"fmt"
     34 	"html/template"
     35 	"internal/trace"
     36 	"io"
     37 	"log"
     38 	"net"
     39 	"net/http"
     40 	"os"
     41 	"sync"
     42 )
     43 
     44 const usageMessage = "" +
     45 	`Usage of 'go tool trace':
     46 Given a trace file produced by 'go test':
     47 	go test -trace=trace.out pkg
     48 
     49 Open a web browser displaying trace:
     50 	go tool trace [flags] [pkg.test] trace.out
     51 
     52 Generate a pprof-like profile from the trace:
     53     go tool trace -pprof=TYPE [pkg.test] trace.out
     54 
     55 [pkg.test] argument is required for traces produced by Go 1.6 and below.
     56 Go 1.7 does not require the binary argument.
     57 
     58 Supported profile types are:
     59     - net: network blocking profile
     60     - sync: synchronization blocking profile
     61     - syscall: syscall blocking profile
     62     - sched: scheduler latency profile
     63 
     64 Flags:
     65 	-http=addr: HTTP service address (e.g., ':6060')
     66 	-pprof=type: print a pprof-like profile instead
     67 `
     68 
     69 var (
     70 	httpFlag  = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
     71 	pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead")
     72 
     73 	// The binary file name, left here for serveSVGProfile.
     74 	programBinary string
     75 	traceFile     string
     76 )
     77 
     78 func main() {
     79 	flag.Usage = func() {
     80 		fmt.Fprintln(os.Stderr, usageMessage)
     81 		os.Exit(2)
     82 	}
     83 	flag.Parse()
     84 
     85 	// Go 1.7 traces embed symbol info and does not require the binary.
     86 	// But we optionally accept binary as first arg for Go 1.5 traces.
     87 	switch flag.NArg() {
     88 	case 1:
     89 		traceFile = flag.Arg(0)
     90 	case 2:
     91 		programBinary = flag.Arg(0)
     92 		traceFile = flag.Arg(1)
     93 	default:
     94 		flag.Usage()
     95 	}
     96 
     97 	var pprofFunc func(io.Writer) error
     98 	switch *pprofFlag {
     99 	case "net":
    100 		pprofFunc = pprofIO
    101 	case "sync":
    102 		pprofFunc = pprofBlock
    103 	case "syscall":
    104 		pprofFunc = pprofSyscall
    105 	case "sched":
    106 		pprofFunc = pprofSched
    107 	}
    108 	if pprofFunc != nil {
    109 		if err := pprofFunc(os.Stdout); err != nil {
    110 			dief("failed to generate pprof: %v\n", err)
    111 		}
    112 		os.Exit(0)
    113 	}
    114 	if *pprofFlag != "" {
    115 		dief("unknown pprof type %s\n", *pprofFlag)
    116 	}
    117 
    118 	ln, err := net.Listen("tcp", *httpFlag)
    119 	if err != nil {
    120 		dief("failed to create server socket: %v\n", err)
    121 	}
    122 
    123 	log.Printf("Parsing trace...")
    124 	events, err := parseEvents()
    125 	if err != nil {
    126 		dief("%v\n", err)
    127 	}
    128 
    129 	log.Printf("Serializing trace...")
    130 	params := &traceParams{
    131 		events:  events,
    132 		endTime: int64(1<<63 - 1),
    133 	}
    134 	data, err := generateTrace(params)
    135 	if err != nil {
    136 		dief("%v\n", err)
    137 	}
    138 
    139 	log.Printf("Splitting trace...")
    140 	ranges = splitTrace(data)
    141 
    142 	log.Printf("Opening browser")
    143 	if !browser.Open("http://" + ln.Addr().String()) {
    144 		fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String())
    145 	}
    146 
    147 	// Start http server.
    148 	http.HandleFunc("/", httpMain)
    149 	err = http.Serve(ln, nil)
    150 	dief("failed to start http server: %v\n", err)
    151 }
    152 
    153 var ranges []Range
    154 
    155 var loader struct {
    156 	once   sync.Once
    157 	events []*trace.Event
    158 	err    error
    159 }
    160 
    161 func parseEvents() ([]*trace.Event, error) {
    162 	loader.once.Do(func() {
    163 		tracef, err := os.Open(traceFile)
    164 		if err != nil {
    165 			loader.err = fmt.Errorf("failed to open trace file: %v", err)
    166 			return
    167 		}
    168 		defer tracef.Close()
    169 
    170 		// Parse and symbolize.
    171 		events, err := trace.Parse(bufio.NewReader(tracef), programBinary)
    172 		if err != nil {
    173 			loader.err = fmt.Errorf("failed to parse trace: %v", err)
    174 			return
    175 		}
    176 		loader.events = events
    177 	})
    178 	return loader.events, loader.err
    179 }
    180 
    181 // httpMain serves the starting page.
    182 func httpMain(w http.ResponseWriter, r *http.Request) {
    183 	if err := templMain.Execute(w, ranges); err != nil {
    184 		http.Error(w, err.Error(), http.StatusInternalServerError)
    185 		return
    186 	}
    187 }
    188 
    189 var templMain = template.Must(template.New("").Parse(`
    190 <html>
    191 <body>
    192 {{if $}}
    193 	{{range $e := $}}
    194 		<a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br>
    195 	{{end}}
    196 	<br>
    197 {{else}}
    198 	<a href="/trace">View trace</a><br>
    199 {{end}}
    200 <a href="/goroutines">Goroutine analysis</a><br>
    201 <a href="/io">Network blocking profile</a><br>
    202 <a href="/block">Synchronization blocking profile</a><br>
    203 <a href="/syscall">Syscall blocking profile</a><br>
    204 <a href="/sched">Scheduler latency profile</a><br>
    205 </body>
    206 </html>
    207 `))
    208 
    209 func dief(msg string, args ...interface{}) {
    210 	fmt.Fprintf(os.Stderr, msg, args...)
    211 	os.Exit(1)
    212 }
    213