Home | History | Annotate | Download | only in 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 || 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