github.com/sean-/go@v0.0.0-20151219100004-97f854cd7bb6/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  /*
     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  		fmt.Fprintf(os.Stderr, "Trace viewer is listening on http://%s\n", ln.Addr().String())
    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  }