"log"
"math"
"net/http"
+ "net/url"
"reflect"
"sort"
"strconv"
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)
}
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 {
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 {
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 {
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 {
{{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}}
}
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;
}
<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>
</tr>
{{end}}
</table>
+</p>
`))
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;
}
<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>