diff --git a/internal/lsp/debug/serve.go b/internal/lsp/debug/serve.go index 3ea564e0..43460ec7 100644 --- a/internal/lsp/debug/serve.go +++ b/internal/lsp/debug/serve.go @@ -14,6 +14,8 @@ import ( "net/http" _ "net/http/pprof" // pull in the standard pprof handlers "path" + "runtime" + "strconv" "sync" "golang.org/x/tools/internal/span" @@ -63,6 +65,7 @@ func init() { http.HandleFunc("/view/", Render(viewTmpl, getView)) http.HandleFunc("/file/", Render(fileTmpl, getFile)) http.HandleFunc("/info", Render(infoTmpl, getInfo)) + http.HandleFunc("/memory", Render(memoryTmpl, getMemory)) } // AddCache adds a cache to the set being served @@ -171,6 +174,12 @@ func getInfo(r *http.Request) interface{} { return template.HTML(buf.String()) } +func getMemory(r *http.Request) interface{} { + var m runtime.MemStats + runtime.ReadMemStats(&m) + return m +} + // AddSession adds a session to the set being served func AddSession(session Session) { mu.Lock() @@ -235,6 +244,22 @@ func Render(tmpl *template.Template, fun func(*http.Request) interface{}) func(h } } +func commas(s string) string { + for i := len(s); i > 3; { + i -= 3 + s = s[:i] + "," + s[i:] + } + return s +} + +func fuint64(v uint64) string { + return commas(strconv.FormatUint(v, 10)) +} + +func fuint32(v uint32) string { + return commas(strconv.FormatUint(uint64(v), 10)) +} + var BaseTemplate = template.Must(template.New("").Parse(` @@ -244,11 +269,16 @@ var BaseTemplate = template.Must(template.New("").Parse(` display:inline-block; width:6rem; } +td.value { + text-align: right; +} +{{block "head" .}}{{end}} Main Info +Memory Debug

{{template "title" .}}

@@ -262,7 +292,10 @@ Unknown page {{define "sessionlink"}}Session {{.}}{{end}} {{define "viewlink"}}View {{.}}{{end}} {{define "filelink"}}{{.URI}}{{end}} -`)) +`)).Funcs(template.FuncMap{ + "fuint64": fuint64, + "fuint32": fuint32, +}) var mainTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` {{define "title"}}GoPls server information{{end}} @@ -283,6 +316,36 @@ var infoTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` {{end}} `)) +var memoryTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` +{{define "title"}}GoPls memory usage{{end}} +{{define "head"}}{{end}} +{{define "body"}} +

Stats

+ + + + + + + + + + + + + + + + +
Allocated bytes{{fuint64 .HeapAlloc}}
Total allocated bytes{{fuint64 .TotalAlloc}}
System bytes{{fuint64 .Sys}}
Heap system bytes{{fuint64 .HeapSys}}
Malloc calls{{fuint64 .Mallocs}}
Frees{{fuint64 .Frees}}
Idle heap bytes{{fuint64 .HeapIdle}}
In use bytes{{fuint64 .HeapInuse}}
Released to system bytes{{fuint64 .HeapReleased}}
Heap object count{{fuint64 .HeapObjects}}
Stack in use bytes{{fuint64 .StackInuse}}
Stack from system bytes{{fuint64 .StackSys}}
Bucket hash bytes{{fuint64 .BuckHashSys}}
GC metaata bytes{{fuint64 .GCSys}}
Off heap bytes{{fuint64 .OtherSys}}
+

By size

+ + +{{range .BySize}}{{end}} +
SizeMallocsFrees
{{fuint32 .Size}}{{fuint64 .Mallocs}}{{fuint64 .Frees}}
+{{end}} +`)) + var debugTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(` {{define "title"}}GoPls Debug pages{{end}} {{define "body"}}