Skip to content

Commit c427ad7

Browse files
tonistiigibradfitz
authored andcommitted
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/21654 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
1 parent 2497afe commit c427ad7

File tree

4 files changed

+53
-14
lines changed

4 files changed

+53
-14
lines changed

trace/events.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ import (
2121
"time"
2222
)
2323

24-
var eventsTmpl = template.Must(template.New("events").Funcs(template.FuncMap{
25-
"elapsed": elapsed,
26-
"trimSpace": strings.TrimSpace,
27-
}).Parse(eventsHTML))
28-
2924
const maxEventsPerLog = 100
3025

3126
type bucket struct {
@@ -101,7 +96,7 @@ func RenderEvents(w http.ResponseWriter, req *http.Request, sensitive bool) {
10196

10297
famMu.RLock()
10398
defer famMu.RUnlock()
104-
if err := eventsTmpl.Execute(w, data); err != nil {
99+
if err := eventsTmpl().Execute(w, data); err != nil {
105100
log.Printf("net/trace: Failed executing template: %v", err)
106101
}
107102
}
@@ -421,6 +416,19 @@ func freeEventLog(el *eventLog) {
421416
}
422417
}
423418

419+
var eventsTmplCache *template.Template
420+
var eventsTmplOnce sync.Once
421+
422+
func eventsTmpl() *template.Template {
423+
eventsTmplOnce.Do(func() {
424+
eventsTmplCache = template.Must(template.New("events").Funcs(template.FuncMap{
425+
"elapsed": elapsed,
426+
"trimSpace": strings.TrimSpace,
427+
}).Parse(eventsHTML))
428+
})
429+
return eventsTmplCache
430+
}
431+
424432
const eventsHTML = `
425433
<html>
426434
<head>

trace/histogram.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"html/template"
1313
"log"
1414
"math"
15+
"sync"
1516

1617
"golang.org/x/net/internal/timeseries"
1718
)
@@ -320,15 +321,20 @@ func (h *histogram) newData() *data {
320321

321322
func (h *histogram) html() template.HTML {
322323
buf := new(bytes.Buffer)
323-
if err := distTmpl.Execute(buf, h.newData()); err != nil {
324+
if err := distTmpl().Execute(buf, h.newData()); err != nil {
324325
buf.Reset()
325326
log.Printf("net/trace: couldn't execute template: %v", err)
326327
}
327328
return template.HTML(buf.String())
328329
}
329330

330-
// Input: data
331-
var distTmpl = template.Must(template.New("distTmpl").Parse(`
331+
var distTmplCache *template.Template
332+
var distTmplOnce sync.Once
333+
334+
func distTmpl() *template.Template {
335+
distTmplOnce.Do(func() {
336+
// Input: data
337+
distTmplCache = template.Must(template.New("distTmpl").Parse(`
332338
<table>
333339
<tr>
334340
<td style="padding:0.25em">Count: {{.Count}}</td>
@@ -354,3 +360,6 @@ var distTmpl = template.Must(template.New("distTmpl").Parse(`
354360
{{end}}
355361
</table>
356362
`))
363+
})
364+
return distTmplCache
365+
}

trace/trace.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ func Render(w io.Writer, req *http.Request, sensitive bool) {
238238

239239
completedMu.RLock()
240240
defer completedMu.RUnlock()
241-
if err := pageTmpl.ExecuteTemplate(w, "Page", data); err != nil {
241+
if err := pageTmpl().ExecuteTemplate(w, "Page", data); err != nil {
242242
log.Printf("net/trace: Failed executing template: %v", err)
243243
}
244244
}
@@ -902,10 +902,18 @@ func elapsed(d time.Duration) string {
902902
return string(b)
903903
}
904904

905-
var pageTmpl = template.Must(template.New("Page").Funcs(template.FuncMap{
906-
"elapsed": elapsed,
907-
"add": func(a, b int) int { return a + b },
908-
}).Parse(pageHTML))
905+
var pageTmplCache *template.Template
906+
var pageTmplOnce sync.Once
907+
908+
func pageTmpl() *template.Template {
909+
pageTmplOnce.Do(func() {
910+
pageTmplCache = template.Must(template.New("Page").Funcs(template.FuncMap{
911+
"elapsed": elapsed,
912+
"add": func(a, b int) int { return a + b },
913+
}).Parse(pageHTML))
914+
})
915+
return pageTmplCache
916+
}
909917

910918
const pageHTML = `
911919
{{template "Prolog" .}}

trace/trace_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,20 @@ func TestAuthRequest(t *testing.T) {
7070
}
7171
}
7272

73+
// TestParseTemplate checks that all templates used by this package are valid
74+
// as they are parsed on first usage
75+
func TestParseTemplate(t *testing.T) {
76+
if tmpl := distTmpl(); tmpl == nil {
77+
t.Error("invalid template returned from distTmpl()")
78+
}
79+
if tmpl := pageTmpl(); tmpl == nil {
80+
t.Error("invalid template returned from pageTmpl()")
81+
}
82+
if tmpl := eventsTmpl(); tmpl == nil {
83+
t.Error("invalid template returned from eventsTmpl()")
84+
}
85+
}
86+
7387
func benchmarkTrace(b *testing.B, maxEvents, numEvents int) {
7488
numSpans := (b.N + numEvents + 1) / numEvents
7589

0 commit comments

Comments
 (0)