github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/cmd/trace/main.go (about)

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