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
+
+Size | Mallocs | Frees |
+{{range .BySize}}{{fuint32 .Size}} | {{fuint64 .Mallocs}} | {{fuint64 .Frees}} |
{{end}}
+
+{{end}}
+`))
+
var debugTmpl = template.Must(template.Must(BaseTemplate.Clone()).Parse(`
{{define "title"}}GoPls Debug pages{{end}}
{{define "body"}}