Commit c427ad74 authored by Tonis Tiigi's avatar Tonis Tiigi Committed by Brad Fitzpatrick

trace: initialize templates lazily

Parsing the templates can take a significant amount of
time(30-35ms) so it should not be done on the init phase.

Change-Id: I8f258b8028510e698a97b55faeac0d28a61b7b22
Reviewed-on: https://go-review.googlesource.com/21654Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 2497afe5
...@@ -21,11 +21,6 @@ import ( ...@@ -21,11 +21,6 @@ import (
"time" "time"
) )
var eventsTmpl = template.Must(template.New("events").Funcs(template.FuncMap{
"elapsed": elapsed,
"trimSpace": strings.TrimSpace,
}).Parse(eventsHTML))
const maxEventsPerLog = 100 const maxEventsPerLog = 100
type bucket struct { type bucket struct {
...@@ -101,7 +96,7 @@ func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) { ...@@ -101,7 +96,7 @@ func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) {
famMu.RLock() famMu.RLock()
defer famMu.RUnlock() defer famMu.RUnlock()
if err := eventsTmpl.Execute(w, data); err != nil { if err := eventsTmpl().Execute(w, data); err != nil {
log.Printf("net/trace: Failed executing template: %v", err) log.Printf("net/trace: Failed executing template: %v", err)
} }
} }
...@@ -421,6 +416,19 @@ func freeEventLog(el *eventLog) { ...@@ -421,6 +416,19 @@ func freeEventLog(el *eventLog) {
} }
} }
var eventsTmplCache *template.Template
var eventsTmplOnce sync.Once
func eventsTmpl() *template.Template {
eventsTmplOnce.Do(func() {
eventsTmplCache = template.Must(template.New("events").Funcs(template.FuncMap{
"elapsed": elapsed,
"trimSpace": strings.TrimSpace,
}).Parse(eventsHTML))
})
return eventsTmplCache
}
const eventsHTML = ` const eventsHTML = `
<html> <html>
<head> <head>
......
...@@ -12,6 +12,7 @@ import ( ...@@ -12,6 +12,7 @@ import (
"html/template" "html/template"
"log" "log"
"math" "math"
"sync"
"golang.org/x/net/internal/timeseries" "golang.org/x/net/internal/timeseries"
) )
...@@ -320,15 +321,20 @@ func (h *histogram) newData() *data { ...@@ -320,15 +321,20 @@ func (h *histogram) newData() *data {
func (h *histogram) html() template.HTML { func (h *histogram) html() template.HTML {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
if err := distTmpl.Execute(buf, h.newData()); err != nil { if err := distTmpl().Execute(buf, h.newData()); err != nil {
buf.Reset() buf.Reset()
log.Printf("net/trace: couldn't execute template: %v", err) log.Printf("net/trace: couldn't execute template: %v", err)
} }
return template.HTML(buf.String()) return template.HTML(buf.String())
} }
// Input: data var distTmplCache *template.Template
var distTmpl = template.Must(template.New("distTmpl").Parse(` var distTmplOnce sync.Once
func distTmpl() *template.Template {
distTmplOnce.Do(func() {
// Input: data
distTmplCache = template.Must(template.New("distTmpl").Parse(`
<table> <table>
<tr> <tr>
<td style="padding:0.25em">Count: {{.Count}}</td> <td style="padding:0.25em">Count: {{.Count}}</td>
...@@ -354,3 +360,6 @@ var distTmpl = template.Must(template.New("distTmpl").Parse(` ...@@ -354,3 +360,6 @@ var distTmpl = template.Must(template.New("distTmpl").Parse(`
{{end}} {{end}}
</table> </table>
`)) `))
})
return distTmplCache
}
...@@ -238,7 +238,7 @@ func Render(w io.Writer, req *http.Request, sensitive bool) { ...@@ -238,7 +238,7 @@ func Render(w io.Writer, req *http.Request, sensitive bool) {
completedMu.RLock() completedMu.RLock()
defer completedMu.RUnlock() defer completedMu.RUnlock()
if err := pageTmpl.ExecuteTemplate(w, "Page", data); err != nil { if err := pageTmpl().ExecuteTemplate(w, "Page", data); err != nil {
log.Printf("net/trace: Failed executing template: %v", err) log.Printf("net/trace: Failed executing template: %v", err)
} }
} }
...@@ -902,10 +902,18 @@ func elapsed(d time.Duration) string { ...@@ -902,10 +902,18 @@ func elapsed(d time.Duration) string {
return string(b) return string(b)
} }
var pageTmpl = template.Must(template.New("Page").Funcs(template.FuncMap{ var pageTmplCache *template.Template
"elapsed": elapsed, var pageTmplOnce sync.Once
"add": func(a, b int) int { return a + b },
}).Parse(pageHTML)) func pageTmpl() *template.Template {
pageTmplOnce.Do(func() {
pageTmplCache = template.Must(template.New("Page").Funcs(template.FuncMap{
"elapsed": elapsed,
"add": func(a, b int) int { return a + b },
}).Parse(pageHTML))
})
return pageTmplCache
}
const pageHTML = ` const pageHTML = `
{{template "Prolog" .}} {{template "Prolog" .}}
......
...@@ -70,6 +70,20 @@ func TestAuthRequest(t *testing.T) { ...@@ -70,6 +70,20 @@ func TestAuthRequest(t *testing.T) {
} }
} }
// TestParseTemplate checks that all templates used by this package are valid
// as they are parsed on first usage
func TestParseTemplate(t *testing.T) {
if tmpl := distTmpl(); tmpl == nil {
t.Error("invalid template returned from distTmpl()")
}
if tmpl := pageTmpl(); tmpl == nil {
t.Error("invalid template returned from pageTmpl()")
}
if tmpl := eventsTmpl(); tmpl == nil {
t.Error("invalid template returned from eventsTmpl()")
}
}
func benchmarkTrace(b *testing.B, maxEvents, numEvents int) { func benchmarkTrace(b *testing.B, maxEvents, numEvents int) {
numSpans := (b.N + numEvents + 1) / numEvents numSpans := (b.N + numEvents + 1) / numEvents
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment