]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/trace: fix the broken link in region pages and improve UX
authorRohith Ravi <entombedvirus@gmail.com>
Sun, 19 Apr 2020 02:21:15 +0000 (02:21 +0000)
committerHyang-Ah Hana Kim <hyangah@gmail.com>
Tue, 21 Apr 2020 14:57:43 +0000 (14:57 +0000)
The trace tool had a broken link due to a parameter encoding error,
which has been corrected.

In addition:

- the user regions page has been enhanced to include links to
pprof style profiles for region specific io, block, syscall and
schedwait profiles.

- sortable table headers have a pointer cursor to indicate they're
clickable.

Fixes #38518

Change-Id: I26cd5157bd9753750f5f53ea03aac5d2d41b021c
Reviewed-on: https://go-review.googlesource.com/c/go/+/228899
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
src/cmd/trace/annotations.go
src/cmd/trace/goroutines.go

index 817ed0d4a2ddcda2aaa53b959311618200618fed..9b45457436bda9966ec698eea03b55718a468f24 100644 (file)
@@ -12,6 +12,7 @@ import (
        "log"
        "math"
        "net/http"
+       "net/url"
        "reflect"
        "sort"
        "strconv"
@@ -146,10 +147,12 @@ func httpUserRegion(w http.ResponseWriter, r *http.Request) {
                MaxTotal int64
                Data     []regionDesc
                Name     string
+               Filter   *regionFilter
        }{
                MaxTotal: maxTotal,
                Data:     data,
                Name:     filter.name,
+               Filter:   filter,
        })
        if err != nil {
                http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
@@ -748,8 +751,9 @@ func taskMatches(t *taskDesc, text string) bool {
 }
 
 type regionFilter struct {
-       name string
-       cond []func(regionTypeID, regionDesc) bool
+       name   string
+       params url.Values
+       cond   []func(regionTypeID, regionDesc) bool
 }
 
 func (f *regionFilter) match(id regionTypeID, s regionDesc) bool {
@@ -768,6 +772,7 @@ func newRegionFilter(r *http.Request) (*regionFilter, error) {
 
        var name []string
        var conditions []func(regionTypeID, regionDesc) bool
+       filterParams := make(url.Values)
 
        param := r.Form
        if typ, ok := param["type"]; ok && len(typ) > 0 {
@@ -775,12 +780,15 @@ func newRegionFilter(r *http.Request) (*regionFilter, error) {
                conditions = append(conditions, func(id regionTypeID, s regionDesc) bool {
                        return id.Type == typ[0]
                })
+               filterParams.Add("type", typ[0])
        }
        if pc, err := strconv.ParseUint(r.FormValue("pc"), 16, 64); err == nil {
-               name = append(name, fmt.Sprintf("pc=%x", pc))
+               encPC := fmt.Sprintf("%x", pc)
+               name = append(name, "pc="+encPC)
                conditions = append(conditions, func(id regionTypeID, s regionDesc) bool {
                        return id.Frame.PC == pc
                })
+               filterParams.Add("pc", encPC)
        }
 
        if lat, err := time.ParseDuration(r.FormValue("latmin")); err == nil {
@@ -788,15 +796,21 @@ func newRegionFilter(r *http.Request) (*regionFilter, error) {
                conditions = append(conditions, func(_ regionTypeID, s regionDesc) bool {
                        return s.duration() >= lat
                })
+               filterParams.Add("latmin", lat.String())
        }
        if lat, err := time.ParseDuration(r.FormValue("latmax")); err == nil {
                name = append(name, fmt.Sprintf("latency <= %s", lat))
                conditions = append(conditions, func(_ regionTypeID, s regionDesc) bool {
                        return s.duration() <= lat
                })
+               filterParams.Add("latmax", lat.String())
        }
 
-       return &regionFilter{name: strings.Join(name, ","), cond: conditions}, nil
+       return &regionFilter{
+               name:   strings.Join(name, ","),
+               cond:   conditions,
+               params: filterParams,
+       }, nil
 }
 
 type durationHistogram struct {
@@ -946,7 +960,7 @@ var templUserRegionTypes = template.Must(template.New("").Parse(`
 {{range $}}
   <tr>
     <td>{{.Type}}<br>{{.Frame.Fn}}<br>{{.Frame.File}}:{{.Frame.Line}}</td>
-    <td><a href="/userregion?type={{.Type}}&pc={{.Frame.PC}}">{{.Histogram.Count}}</a></td>
+    <td><a href="/userregion?type={{.Type}}&pc={{.Frame.PC | printf "%x"}}">{{.Histogram.Count}}</a></td>
     <td>{{.Histogram.ToHTML (.UserRegionURL)}}</td>
   </tr>
 {{end}}
@@ -1181,14 +1195,27 @@ var templUserRegionType = template.Must(template.New("").Funcs(template.FuncMap{
                }
                return 0
        },
+       "filterParams": func(f *regionFilter) template.URL {
+               return template.URL(f.params.Encode())
+       },
 }).Parse(`
 <!DOCTYPE html>
-<title>Goroutine {{.Name}}</title>
+<title>User Region {{.Name}}</title>
 <style>
 th {
   background-color: #050505;
   color: #fff;
 }
+th.total-time,
+th.exec-time,
+th.io-time,
+th.block-time,
+th.syscall-time,
+th.sched-time,
+th.sweep-time,
+th.pause-time {
+  cursor: pointer;
+}
 table {
   border-collapse: collapse;
 }
@@ -1235,19 +1262,28 @@ function reloadTable(key, value) {
 
 <h2>{{.Name}}</h2>
 
+{{ with $p := filterParams .Filter}}
+<table class="summary">
+       <tr><td>Network Wait Time:</td><td> <a href="/regionio?{{$p}}">graph</a><a href="/regionio?{{$p}}&raw=1" download="io.profile">(download)</a></td></tr>
+       <tr><td>Sync Block Time:</td><td> <a href="/regionblock?{{$p}}">graph</a><a href="/regionblock?{{$p}}&raw=1" download="block.profile">(download)</a></td></tr>
+       <tr><td>Blocking Syscall Time:</td><td> <a href="/regionsyscall?{{$p}}">graph</a><a href="/regionsyscall?{{$p}}&raw=1" download="syscall.profile">(download)</a></td></tr>
+       <tr><td>Scheduler Wait Time:</td><td> <a href="/regionsched?{{$p}}">graph</a><a href="/regionsched?{{$p}}&raw=1" download="sched.profile">(download)</a></td></tr>
+</table>
+{{ end }}
+<p>
 <table class="details">
 <tr>
 <th> Goroutine </th>
 <th> Task </th>
-<th onclick="reloadTable('sortby', 'TotalTime')"> Total</th>
+<th onclick="reloadTable('sortby', 'TotalTime')" class="total-time"> Total</th>
 <th></th>
 <th onclick="reloadTable('sortby', 'ExecTime')" class="exec-time"> Execution</th>
 <th onclick="reloadTable('sortby', 'IOTime')" class="io-time"> Network wait</th>
 <th onclick="reloadTable('sortby', 'BlockTime')" class="block-time"> Sync block </th>
 <th onclick="reloadTable('sortby', 'SyscallTime')" class="syscall-time"> Blocking syscall</th>
 <th onclick="reloadTable('sortby', 'SchedWaitTime')" class="sched-time"> Scheduler wait</th>
-<th onclick="reloadTable('sortby', 'SweepTime')"> GC sweeping</th>
-<th onclick="reloadTable('sortby', 'GCTime')"> GC pause</th>
+<th onclick="reloadTable('sortby', 'SweepTime')" class="sweep-time"> GC sweeping</th>
+<th onclick="reloadTable('sortby', 'GCTime')" class="pause-time"> GC pause</th>
 </tr>
 {{range .Data}}
   <tr>
@@ -1274,4 +1310,5 @@ function reloadTable(key, value) {
   </tr>
 {{end}}
 </table>
+</p>
 `))
index 100891d64e0404cae55b682ba01477d8d2239794..74d1b0a11dfc4ec000104954c046c1c1b434ce02 100644 (file)
@@ -193,6 +193,16 @@ th {
   background-color: #050505;
   color: #fff;
 }
+th.total-time,
+th.exec-time,
+th.io-time,
+th.block-time,
+th.syscall-time,
+th.sched-time,
+th.sweep-time,
+th.pause-time {
+  cursor: pointer;
+}
 table {
   border-collapse: collapse;
 }
@@ -250,15 +260,15 @@ function reloadTable(key, value) {
 <table class="details">
 <tr>
 <th> Goroutine</th>
-<th onclick="reloadTable('sortby', 'TotalTime')"> Total</th>
+<th onclick="reloadTable('sortby', 'TotalTime')" class="total-time"> Total</th>
 <th></th>
 <th onclick="reloadTable('sortby', 'ExecTime')" class="exec-time"> Execution</th>
 <th onclick="reloadTable('sortby', 'IOTime')" class="io-time"> Network wait</th>
 <th onclick="reloadTable('sortby', 'BlockTime')" class="block-time"> Sync block </th>
 <th onclick="reloadTable('sortby', 'SyscallTime')" class="syscall-time"> Blocking syscall</th>
 <th onclick="reloadTable('sortby', 'SchedWaitTime')" class="sched-time"> Scheduler wait</th>
-<th onclick="reloadTable('sortby', 'SweepTime')"> GC sweeping</th>
-<th onclick="reloadTable('sortby', 'GCTime')"> GC pause</th>
+<th onclick="reloadTable('sortby', 'SweepTime')" class="sweep-time"> GC sweeping</th>
+<th onclick="reloadTable('sortby', 'GCTime')" class="pause-time"> GC pause</th>
 </tr>
 {{range .GList}}
   <tr>