...
Run Format

Source file src/cmd/trace/goroutines.go

Documentation: cmd/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  // Goroutine-related profiles.
     6  
     7  package main
     8  
     9  import (
    10  	"fmt"
    11  	"html/template"
    12  	"internal/trace"
    13  	"net/http"
    14  	"sort"
    15  	"strconv"
    16  	"sync"
    17  )
    18  
    19  func init() {
    20  	http.HandleFunc("/goroutines", httpGoroutines)
    21  	http.HandleFunc("/goroutine", httpGoroutine)
    22  }
    23  
    24  // gtype describes a group of goroutines grouped by start PC.
    25  type gtype struct {
    26  	ID       uint64 // Unique identifier (PC).
    27  	Name     string // Start function.
    28  	N        int    // Total number of goroutines in this group.
    29  	ExecTime int64  // Total execution time of all goroutines in this group.
    30  }
    31  
    32  type gtypeList []gtype
    33  
    34  func (l gtypeList) Len() int {
    35  	return len(l)
    36  }
    37  
    38  func (l gtypeList) Less(i, j int) bool {
    39  	return l[i].ExecTime > l[j].ExecTime
    40  }
    41  
    42  func (l gtypeList) Swap(i, j int) {
    43  	l[i], l[j] = l[j], l[i]
    44  }
    45  
    46  type gdescList []*trace.GDesc
    47  
    48  func (l gdescList) Len() int {
    49  	return len(l)
    50  }
    51  
    52  func (l gdescList) Less(i, j int) bool {
    53  	return l[i].TotalTime > l[j].TotalTime
    54  }
    55  
    56  func (l gdescList) Swap(i, j int) {
    57  	l[i], l[j] = l[j], l[i]
    58  }
    59  
    60  var (
    61  	gsInit sync.Once
    62  	gs     map[uint64]*trace.GDesc
    63  )
    64  
    65  // analyzeGoroutines generates statistics about execution of all goroutines and stores them in gs.
    66  func analyzeGoroutines(events []*trace.Event) {
    67  	gsInit.Do(func() {
    68  		gs = trace.GoroutineStats(events)
    69  	})
    70  }
    71  
    72  // httpGoroutines serves list of goroutine groups.
    73  func httpGoroutines(w http.ResponseWriter, r *http.Request) {
    74  	events, err := parseEvents()
    75  	if err != nil {
    76  		http.Error(w, err.Error(), http.StatusInternalServerError)
    77  		return
    78  	}
    79  	analyzeGoroutines(events)
    80  	gss := make(map[uint64]gtype)
    81  	for _, g := range gs {
    82  		gs1 := gss[g.PC]
    83  		gs1.ID = g.PC
    84  		gs1.Name = g.Name
    85  		gs1.N++
    86  		gs1.ExecTime += g.ExecTime
    87  		gss[g.PC] = gs1
    88  	}
    89  	var glist gtypeList
    90  	for k, v := range gss {
    91  		v.ID = k
    92  		glist = append(glist, v)
    93  	}
    94  	sort.Sort(glist)
    95  	templGoroutines.Execute(w, glist)
    96  }
    97  
    98  var templGoroutines = template.Must(template.New("").Parse(`
    99  <html>
   100  <body>
   101  Goroutines: <br>
   102  {{range $}}
   103    <a href="/goroutine?id={{.ID}}">{{.Name}}</a> N={{.N}} <br>
   104  {{end}}
   105  </body>
   106  </html>
   107  `))
   108  
   109  // httpGoroutine serves list of goroutines in a particular group.
   110  func httpGoroutine(w http.ResponseWriter, r *http.Request) {
   111  	events, err := parseEvents()
   112  	if err != nil {
   113  		http.Error(w, err.Error(), http.StatusInternalServerError)
   114  		return
   115  	}
   116  	pc, err := strconv.ParseUint(r.FormValue("id"), 10, 64)
   117  	if err != nil {
   118  		http.Error(w, fmt.Sprintf("failed to parse id parameter '%v': %v", r.FormValue("id"), err), http.StatusInternalServerError)
   119  		return
   120  	}
   121  	analyzeGoroutines(events)
   122  	var glist gdescList
   123  	for _, g := range gs {
   124  		if g.PC != pc {
   125  			continue
   126  		}
   127  		glist = append(glist, g)
   128  	}
   129  	sort.Sort(glist)
   130  	err = templGoroutine.Execute(w, struct {
   131  		PC    uint64
   132  		GList gdescList
   133  	}{pc, glist})
   134  	if err != nil {
   135  		http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
   136  		return
   137  	}
   138  }
   139  
   140  var templGoroutine = template.Must(template.New("").Parse(`
   141  <html>
   142  <body>
   143  <table border="1" sortable="1">
   144  <tr>
   145  <th> Goroutine </th>
   146  <th> Total time, ns </th>
   147  <th> Execution time, ns </th>
   148  <th> <a href="/io?id={{.PC}}">Network wait time, ns</a><a href="/io?id={{.PC}}&raw=1" download="io.profile">⬇</a> </th>
   149  <th> <a href="/block?id={{.PC}}">Sync block time, ns</a><a href="/block?id={{.PC}}&raw=1" download="block.profile">⬇</a> </th>
   150  <th> <a href="/syscall?id={{.PC}}">Blocking syscall time, ns</a><a href="/syscall?id={{.PC}}&raw=1" download="syscall.profile">⬇</a> </th>
   151  <th> <a href="/sched?id={{.PC}}">Scheduler wait time, ns</a><a href="/sched?id={{.PC}}&raw=1" download="sched.profile">⬇</a> </th>
   152  <th> GC sweeping time, ns </th>
   153  <th> GC pause time, ns </th>
   154  </tr>
   155  {{range .GList}}
   156    <tr>
   157      <td> <a href="/trace?goid={{.ID}}">{{.ID}}</a> </td>
   158      <td> {{.TotalTime}} </td>
   159      <td> {{.ExecTime}} </td>
   160      <td> {{.IOTime}} </td>
   161      <td> {{.BlockTime}} </td>
   162      <td> {{.SyscallTime}} </td>
   163      <td> {{.SchedWaitTime}} </td>
   164      <td> {{.SweepTime}} </td>
   165      <td> {{.GCTime}} </td>
   166    </tr>
   167  {{end}}
   168  </table>
   169  </body>
   170  </html>
   171  `))
   172  

View as plain text