From: Hana Kim Date: Wed, 28 Mar 2018 19:22:26 +0000 (-0400) Subject: cmd/trace: make span tables pretty X-Git-Tag: go1.11beta1~1050 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=3ac17f86be1bb9b6a7cfde2b1dcef88bc5c2c1a6;p=gostls13.git cmd/trace: make span tables pretty Mostly same as golang.org/cl/102156, except the parts that deal with different data types. Change-Id: I061b858b73898725e3bf175ed022c2e3e55fc485 Reviewed-on: https://go-review.googlesource.com/103158 Reviewed-by: Andrew Bonventre --- diff --git a/src/cmd/trace/annotations.go b/src/cmd/trace/annotations.go index 35f0ee39d2..ffe8ed48ae 100644 --- a/src/cmd/trace/annotations.go +++ b/src/cmd/trace/annotations.go @@ -8,6 +8,7 @@ import ( "log" "math" "net/http" + "reflect" "sort" "strconv" "strings" @@ -111,21 +112,41 @@ func httpUserSpan(w http.ResponseWriter, r *http.Request) { var data []spanDesc + var maxTotal int64 for id, spans := range allSpans { for _, s := range spans { if !filter.match(id, s) { continue } data = append(data, s) + if maxTotal < s.TotalTime { + maxTotal = s.TotalTime + } } } + sortby := r.FormValue("sortby") + _, ok := reflect.TypeOf(spanDesc{}).FieldByNameFunc(func(s string) bool { + return s == sortby + }) + if !ok { + sortby = "TotalTime" + } + sort.Slice(data, func(i, j int) bool { + ival := reflect.ValueOf(data[i]).FieldByName(sortby).Int() + jval := reflect.ValueOf(data[j]).FieldByName(sortby).Int() + return ival > jval + }) + err = templUserSpanType.Execute(w, struct { - Data []spanDesc - Title string + MaxTotal int64 + Data []spanDesc + Name string }{ - Data: data, - Title: filter.name}) + MaxTotal: maxTotal, + Data: data, + Name: filter.name, + }) if err != nil { http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError) return @@ -1113,40 +1134,121 @@ func isUserAnnotationEvent(ev *trace.Event) bool { return false } -var templUserSpanType = template.Must(template.New("").Parse(` - - -

{{.Title}}

- +var templUserSpanType = template.Must(template.New("").Funcs(template.FuncMap{ + "prettyDuration": func(nsec int64) template.HTML { + d := time.Duration(nsec) * time.Nanosecond + return template.HTML(niceDuration(d)) + }, + "percent": func(dividened, divisor int64) template.HTML { + if divisor == 0 { + return "" + } + return template.HTML(fmt.Sprintf("(%.1f%%)", float64(dividened)/float64(divisor)*100)) + }, + "barLen": func(dividened, divisor int64) template.HTML { + if divisor == 0 { + return "0" + } + return template.HTML(fmt.Sprintf("%.2f%%", float64(dividened)/float64(divisor)*100)) + }, + "unknownTime": func(desc spanDesc) int64 { + sum := desc.ExecTime + desc.IOTime + desc.BlockTime + desc.SyscallTime + desc.SchedWaitTime + if sum < desc.TotalTime { + return desc.TotalTime - sum + } + return 0 + }, +}).Parse(` + +Goroutine {{.Name}} + + + + +

{{.Name}}

+ +
- - - - - - - - - + + + + + + + + + {{range .Data}} - - - - - - - - - + + + + + + + + + {{end}}
Goroutine Task Total time, ns Execution time, ns Network wait time, ns Sync block time, ns Blocking syscall time, ns Scheduler wait time, ns GC sweeping time, ns GC pause time, ns Logs Total Execution Network wait Sync block Blocking syscall Scheduler wait GC sweeping GC pause
{{.G}} {{.TaskID}} {{.TotalTime}} {{.ExecTime}} {{.IOTime}} {{.BlockTime}} {{.SyscallTime}} {{.SchedWaitTime}} {{.SweepTime}} {{.GCTime}} /* TODO */ {{prettyDuration .TotalTime}} +
+ {{if unknownTime .}} {{end}} + {{if .ExecTime}} {{end}} + {{if .IOTime}} {{end}} + {{if .BlockTime}} {{end}} + {{if .SyscallTime}} {{end}} + {{if .SchedWaitTime}} {{end}} +
+
{{prettyDuration .ExecTime}} {{prettyDuration .IOTime}} {{prettyDuration .BlockTime}} {{prettyDuration .SyscallTime}} {{prettyDuration .SchedWaitTime}} {{prettyDuration .SweepTime}} {{percent .SweepTime .TotalTime}} {{prettyDuration .GCTime}} {{percent .GCTime .TotalTime}}
- - `))