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 || g.ExecTime == 0 { 125 continue 126 } 127 glist = append(glist, g) 128 } 129 sort.Sort(glist) 130 err = templGoroutine.Execute(w, glist) 131 if err != nil { 132 http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError) 133 return 134 } 135 } 136 137 var templGoroutine = template.Must(template.New("").Parse(` 138 <html> 139 <body> 140 <table border="1" sortable="1"> 141 <tr> 142 <th> Goroutine </th> 143 <th> Total time, ns </th> 144 <th> Execution time, ns </th> 145 <th> Network wait time, ns </th> 146 <th> Sync block time, ns </th> 147 <th> Blocking syscall time, ns </th> 148 <th> Scheduler wait time, ns </th> 149 <th> GC sweeping time, ns </th> 150 <th> GC pause time, ns </th> 151 </tr> 152 {{range $}} 153 <tr> 154 <td> <a href="/trace?goid={{.ID}}">{{.ID}}</a> </td> 155 <td> {{.TotalTime}} </td> 156 <td> {{.ExecTime}} </td> 157 <td> {{.IOTime}} </td> 158 <td> {{.BlockTime}} </td> 159 <td> {{.SyscallTime}} </td> 160 <td> {{.SchedWaitTime}} </td> 161 <td> {{.SweepTime}} </td> 162 <td> {{.GCTime}} </td> 163 </tr> 164 {{end}} 165 </table> 166 </body> 167 </html> 168 `)) 169