]> Cypherpunks repositories - gostls13.git/commitdiff
net/http/pprof: remove html/template dependency
authorEgon Elbre <egonelbre@gmail.com>
Wed, 23 Sep 2020 11:06:28 +0000 (14:06 +0300)
committerHajime Hoshi <hajimehoshi@gmail.com>
Fri, 9 Oct 2020 09:55:58 +0000 (09:55 +0000)
html/template indirectly uses reflect MethodByName, this causes linker
to use conservative mode resulting in larger binaries. The template here
is trivial and can be replaced by string manipulation.

This reduces a binary using only net/http/pprof by ~2.5MB.

Fixes #41569

Change-Id: I240e1daa6376182ff4961997ee3ec7b96cb07be8
Reviewed-on: https://go-review.googlesource.com/c/go/+/256900
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Hajime Hoshi <hajimehoshi@gmail.com>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Hajime Hoshi <hajimehoshi@gmail.com>
Trust: Brad Fitzpatrick <bradfitz@golang.org>

src/go/build/deps_test.go
src/net/http/pprof/pprof.go

index fa8ecf10f4281542d40a5b5bca6fdb010b64208c..42382d583c0eb9a19984563ec24aa4f4acc702ea 100644 (file)
@@ -449,7 +449,7 @@ var depsRules = `
        OS, compress/gzip, regexp
        < internal/profile;
 
-       html/template, internal/profile, net/http, runtime/pprof, runtime/trace
+       html, internal/profile, net/http, runtime/pprof, runtime/trace
        < net/http/pprof;
 
        # RPC
index 5ff7fdc3deedbb7b776131f6e3a9a885116a89b0..2bfcfb95459633d0805215db38dd72a26f301c56 100644 (file)
@@ -61,11 +61,12 @@ import (
        "bytes"
        "context"
        "fmt"
-       "html/template"
+       "html"
        "internal/profile"
        "io"
        "log"
        "net/http"
+       "net/url"
        "os"
        "runtime"
        "runtime/pprof"
@@ -352,6 +353,13 @@ var profileDescriptions = map[string]string{
        "trace":        "A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.",
 }
 
+type profileEntry struct {
+       Name  string
+       Href  string
+       Desc  string
+       Count int
+}
+
 // Index responds with the pprof-formatted profile named by the request.
 // For example, "/debug/pprof/heap" serves the "heap" profile.
 // Index responds to a request for "/debug/pprof/" with an HTML page
@@ -368,17 +376,11 @@ func Index(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("X-Content-Type-Options", "nosniff")
        w.Header().Set("Content-Type", "text/html; charset=utf-8")
 
-       type profile struct {
-               Name  string
-               Href  string
-               Desc  string
-               Count int
-       }
-       var profiles []profile
+       var profiles []profileEntry
        for _, p := range pprof.Profiles() {
-               profiles = append(profiles, profile{
+               profiles = append(profiles, profileEntry{
                        Name:  p.Name(),
-                       Href:  p.Name() + "?debug=1",
+                       Href:  p.Name(),
                        Desc:  profileDescriptions[p.Name()],
                        Count: p.Count(),
                })
@@ -386,7 +388,7 @@ func Index(w http.ResponseWriter, r *http.Request) {
 
        // Adding other profiles exposed from within this package
        for _, p := range []string{"cmdline", "profile", "trace"} {
-               profiles = append(profiles, profile{
+               profiles = append(profiles, profileEntry{
                        Name: p,
                        Href: p,
                        Desc: profileDescriptions[p],
@@ -397,12 +399,14 @@ func Index(w http.ResponseWriter, r *http.Request) {
                return profiles[i].Name < profiles[j].Name
        })
 
-       if err := indexTmpl.Execute(w, profiles); err != nil {
+       if err := indexTmplExecute(w, profiles); err != nil {
                log.Print(err)
        }
 }
 
-var indexTmpl = template.Must(template.New("index").Parse(`<html>
+func indexTmplExecute(w io.Writer, profiles []profileEntry) error {
+       var b bytes.Buffer
+       b.WriteString(`<html>
 <head>
 <title>/debug/pprof/</title>
 <style>
@@ -418,22 +422,28 @@ var indexTmpl = template.Must(template.New("index").Parse(`<html>
 Types of profiles available:
 <table>
 <thead><td>Count</td><td>Profile</td></thead>
-{{range .}}
-       <tr>
-       <td>{{.Count}}</td><td><a href={{.Href}}>{{.Name}}</a></td>
-       </tr>
-{{end}}
-</table>
+`)
+
+       for _, profile := range profiles {
+               link := &url.URL{Path: profile.Href, RawQuery: "debug=1"}
+               fmt.Fprintf(&b, "<tr><td>%d</td><td><a href='%s'>%s</a></td></tr>\n", profile.Count, link, html.EscapeString(profile.Name))
+       }
+
+       b.WriteString(`</table>
 <a href="goroutine?debug=2">full goroutine stack dump</a>
 <br/>
 <p>
 Profile Descriptions:
 <ul>
-{{range .}}
-<li><div class=profile-name>{{.Name}}:</div> {{.Desc}}</li>
-{{end}}
-</ul>
+`)
+       for _, profile := range profiles {
+               fmt.Fprintf(&b, "<li><div class=profile-name>%s: </div> %s</li>\n", html.EscapeString(profile.Name), html.EscapeString(profile.Desc))
+       }
+       b.WriteString(`</ul>
 </p>
 </body>
-</html>
-`))
+</html>`)
+
+       _, err := w.Write(b.Bytes())
+       return err
+}