github.com/MangoDowner/go-gm@v0.0.0-20180818020936-8baa2bd4408c/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  
    46  Note that while the various profiles available when launching
    47  'go tool trace' work on every browser, the trace viewer itself
    48  (the 'view trace' page) comes from the Chrome/Chromium project
    49  and is only actively tested on that browser.
    50  `
    51  
    52  var (
    53  	httpFlag  = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
    54  	pprofFlag = flag.String("pprof", "", "print a pprof-like profile instead")
    55  
    56  	// The binary file name, left here for serveSVGProfile.
    57  	programBinary string
    58  	traceFile     string
    59  )
    60  
    61  func main() {
    62  	flag.Usage = func() {
    63  		fmt.Fprintln(os.Stderr, usageMessage)
    64  		os.Exit(2)
    65  	}
    66  	flag.Parse()
    67  
    68  	// Go 1.7 traces embed symbol info and does not require the binary.
    69  	// But we optionally accept binary as first arg for Go 1.5 traces.
    70  	switch flag.NArg() {
    71  	case 1:
    72  		traceFile = flag.Arg(0)
    73  	case 2:
    74  		programBinary = flag.Arg(0)
    75  		traceFile = flag.Arg(1)
    76  	default:
    77  		flag.Usage()
    78  	}
    79  
    80  	var pprofFunc func(io.Writer) error
    81  	switch *pprofFlag {
    82  	case "net":
    83  		pprofFunc = pprofIO
    84  	case "sync":
    85  		pprofFunc = pprofBlock
    86  	case "syscall":
    87  		pprofFunc = pprofSyscall
    88  	case "sched":
    89  		pprofFunc = pprofSched
    90  	}
    91  	if pprofFunc != nil {
    92  		if err := pprofFunc(os.Stdout); err != nil {
    93  			dief("failed to generate pprof: %v\n", err)
    94  		}
    95  		os.Exit(0)
    96  	}
    97  	if *pprofFlag != "" {
    98  		dief("unknown pprof type %s\n", *pprofFlag)
    99  	}
   100  
   101  	ln, err := net.Listen("tcp", *httpFlag)
   102  	if err != nil {
   103  		dief("failed to create server socket: %v\n", err)
   104  	}
   105  
   106  	log.Printf("Parsing trace...")
   107  	events, err := parseEvents()
   108  	if err != nil {
   109  		dief("%v\n", err)
   110  	}
   111  
   112  	log.Printf("Serializing trace...")
   113  	params := &traceParams{
   114  		events:  events,
   115  		endTime: int64(1<<63 - 1),
   116  	}
   117  	data, err := generateTrace(params)
   118  	if err != nil {
   119  		dief("%v\n", err)
   120  	}
   121  
   122  	log.Printf("Splitting trace...")
   123  	ranges = splitTrace(data)
   124  
   125  	log.Printf("Opening browser")
   126  	if !browser.Open("http://" + ln.Addr().String()) {
   127  		fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String())
   128  	}
   129  
   130  	// Start http server.
   131  	http.HandleFunc("/", httpMain)
   132  	err = http.Serve(ln, nil)
   133  	dief("failed to start http server: %v\n", err)
   134  }
   135  
   136  var ranges []Range
   137  
   138  var loader struct {
   139  	once   sync.Once
   140  	events []*trace.Event
   141  	err    error
   142  }
   143  
   144  func parseEvents() ([]*trace.Event, error) {
   145  	loader.once.Do(func() {
   146  		tracef, err := os.Open(traceFile)
   147  		if err != nil {
   148  			loader.err = fmt.Errorf("failed to open trace file: %v", err)
   149  			return
   150  		}
   151  		defer tracef.Close()
   152  
   153  		// Parse and symbolize.
   154  		events, err := trace.Parse(bufio.NewReader(tracef), programBinary)
   155  		if err != nil {
   156  			loader.err = fmt.Errorf("failed to parse trace: %v", err)
   157  			return
   158  		}
   159  		loader.events = events
   160  	})
   161  	return loader.events, loader.err
   162  }
   163  
   164  // httpMain serves the starting page.
   165  func httpMain(w http.ResponseWriter, r *http.Request) {
   166  	if err := templMain.Execute(w, ranges); err != nil {
   167  		http.Error(w, err.Error(), http.StatusInternalServerError)
   168  		return
   169  	}
   170  }
   171  
   172  var templMain = template.Must(template.New("").Parse(`
   173  <html>
   174  <body>
   175  {{if $}}
   176  	{{range $e := $}}
   177  		<a href="/trace?start={{$e.Start}}&end={{$e.End}}">View trace ({{$e.Name}})</a><br>
   178  	{{end}}
   179  	<br>
   180  {{else}}
   181  	<a href="/trace">View trace</a><br>
   182  {{end}}
   183  <a href="/goroutines">Goroutine analysis</a><br>
   184  <a href="/io">Network blocking profile</a><br>
   185  <a href="/block">Synchronization blocking profile</a><br>
   186  <a href="/syscall">Syscall blocking profile</a><br>
   187  <a href="/sched">Scheduler latency profile</a><br>
   188  </body>
   189  </html>
   190  `))
   191  
   192  func dief(msg string, args ...interface{}) {
   193  	fmt.Fprintf(os.Stderr, msg, args...)
   194  	os.Exit(1)
   195  }