mirror of https://github.com/golang/go.git
cmd/trace: fix the broken link in region pages and improve UX
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>
This commit is contained in:
parent
664d270727
commit
af55060b39
|
|
@ -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 ®ionFilter{name: strings.Join(name, ","), cond: conditions}, nil
|
||||
return ®ionFilter{
|
||||
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>
|
||||
`))
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue