github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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) 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  	events, err := parseEvents()
   110  	if err != nil {
   111  		dief("%v\n", err)
   112  	}
   113  
   114  	if *debugFlag {
   115  		trace.Print(events)
   116  		os.Exit(0)
   117  	}
   118  
   119  	log.Print("Serializing trace...")
   120  	params := &traceParams{
   121  		events:  events,
   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  	events []*trace.Event
   147  	err    error
   148  }
   149  
   150  func parseEvents() ([]*trace.Event, error) {
   151  	loader.once.Do(func() {
   152  		tracef, err := os.Open(traceFile)
   153  		if err != nil {
   154  			loader.err = fmt.Errorf("failed to open trace file: %v", err)
   155  			return
   156  		}
   157  		defer tracef.Close()
   158  
   159  		// Parse and symbolize.
   160  		events, err := trace.Parse(bufio.NewReader(tracef), programBinary)
   161  		if err != nil {
   162  			loader.err = fmt.Errorf("failed to parse trace: %v", err)
   163  			return
   164  		}
   165  		loader.events = events
   166  	})
   167  	return loader.events, loader.err
   168  }
   169  
   170  // httpMain serves the starting page.
   171  func httpMain(w http.ResponseWriter, r *http.Request) {
   172  	if err := templMain.Execute(w, ranges); err != nil {
   173  		http.Error(w, err.Error(), http.StatusInternalServerError)
   174  		return
   175  	}
   176  }
   177  
   178  var templMain = template.Must(template.New("").Parse(`
   179  <html>
   180  <body>
   181  {{if $}}
   182  	{{range $e := $}}
   183  		<a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br>
   184  	{{end}}
   185  	<br>
   186  {{else}}
   187  	<a href="/trace">View trace</a><br>
   188  {{end}}
   189  <a href="/goroutines">Goroutine analysis</a><br>
   190  <a href="/io">Network blocking profile</a><br>
   191  <a href="/block">Synchronization blocking profile</a><br>
   192  <a href="/syscall">Syscall blocking profile</a><br>
   193  <a href="/sched">Scheduler latency profile</a><br>
   194  </body>
   195  </html>
   196  `))
   197  
   198  func dief(msg string, args ...interface{}) {
   199  	fmt.Fprintf(os.Stderr, msg, args...)
   200  	os.Exit(1)
   201  }