From 2f0245fa188c9ee166908609d0e906f45dfd4c7c Mon Sep 17 00:00:00 2001 From: Adrian Hesketh Date: Thu, 17 Aug 2023 20:32:41 +0100 Subject: [PATCH] chore: update Go benchmark to include Go templates --- benchmarks/templ/README.md | 21 ++--- benchmarks/templ/render_test.go | 36 +++++++- .../counter/components/components_templ.go | 88 +++++++++++++------ 3 files changed, 101 insertions(+), 44 deletions(-) diff --git a/benchmarks/templ/README.md b/benchmarks/templ/README.md index c0a905352..9275b0108 100644 --- a/benchmarks/templ/README.md +++ b/benchmarks/templ/README.md @@ -10,23 +10,18 @@ Used to test code generation strategies for improvements to render time. go test -bench . ``` -## Results - -Currently getting the following results which show that using an internal `bytes.Buffer` within a template could save 25% of time. - -To put this in perspective, the React benchmark is hitting 156,735 operations per second. - -There are 1,000,000,000 nanoseconds in a second, so this is 6,380 ns per operation, which is 6 times slower than templ. - +## Results as of 2023-08-17 ``` go test -bench . goos: darwin goarch: arm64 pkg: github.com/a-h/templ/benchmarks/templ -BenchmarkCurrent-10 1029445 1153 ns/op 1088 B/op 21 allocs/op -BenchmarkCandidate-10 1419076 845.7 ns/op 1464 B/op 20 allocs/op -BenchmarkIOWriteString-10 14667363 82.41 ns/op 352 B/op 2 allocs/op +BenchmarkTempl-10 3291883 369.1 ns/op 536 B/op 6 allocs/op +BenchmarkGoTemplate-10 481052 2475 ns/op 1400 B/op 38 allocs/op +BenchmarkIOWriteString-10 20353198 56.64 ns/op 320 B/op 1 allocs/op PASS -ok github.com/a-h/templ/benchmarks/templ 5.448s -```` +ok github.com/a-h/templ/benchmarks/templ 4.650s +``` + +React comes in at 1,000,000,000ns / 114,131 ops/s = 8,757.5 ns per operation. diff --git a/benchmarks/templ/render_test.go b/benchmarks/templ/render_test.go index 816ffd805..ac8a11d72 100644 --- a/benchmarks/templ/render_test.go +++ b/benchmarks/templ/render_test.go @@ -2,12 +2,13 @@ package testhtml import ( "context" + "html/template" "io" "strings" "testing" ) -func BenchmarkCurrent(b *testing.B) { +func BenchmarkTempl(b *testing.B) { b.ReportAllocs() t := Render(Person{ Name: "Luiz Bonfa", @@ -24,15 +25,44 @@ func BenchmarkCurrent(b *testing.B) { } } -var html = `

Luiz Bonfa




` +var goTemplate = template.Must(template.New("example").Parse(`
+

{{.Name}}

+
+
+ email:{{.Email}}
+
+
+
+
+
+`)) + +func BenchmarkGoTemplate(b *testing.B) { + w := new(strings.Builder) + person := Person{ + Name: "Luiz Bonfa", + Email: "luiz@exapmle.com", + } + b.ReportAllocs() + for i := 0; i < b.N; i++ { + err := goTemplate.Execute(w, person) + if err != nil { + b.Errorf("failed to render: %v", err) + } + w.Reset() + } +} + +const html = `

Luiz Bonfa




` func BenchmarkIOWriteString(b *testing.B) { b.ReportAllocs() + w := new(strings.Builder) for i := 0; i < b.N; i++ { - w := new(strings.Builder) _, err := io.WriteString(w, html) if err != nil { b.Errorf("failed to render: %v", err) } + w.Reset() } } diff --git a/examples/counter/components/components_templ.go b/examples/counter/components/components_templ.go index 267d8b464..3f55c8f89 100644 --- a/examples/counter/components/components_templ.go +++ b/examples/counter/components/components_templ.go @@ -26,7 +26,7 @@ func border() templ.CSSClass { } } -func counts(global, session int) templ.Component { +func test(other string) templ.Component { return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { templBuffer, templIsBuffer := w.(*bytes.Buffer) if !templIsBuffer { @@ -39,12 +39,44 @@ func counts(global, session int) templ.Component { var_1 = templ.NopComponent } ctx = templ.ClearChildren(ctx) + _, err = templBuffer.WriteString("
") + if err != nil { + return err + } + if !templIsBuffer { + _, err = templBuffer.WriteTo(w) + } + return err + }) +} + +func counts(global, session int) templ.Component { + return templ.ComponentFunc(func(ctx context.Context, w io.Writer) (err error) { + templBuffer, templIsBuffer := w.(*bytes.Buffer) + if !templIsBuffer { + templBuffer = templ.GetBuffer() + defer templ.ReleaseBuffer(templBuffer) + } + ctx = templ.InitializeContext(ctx) + var_2 := templ.GetChildren(ctx) + if var_2 == nil { + var_2 = templ.NopComponent + } + ctx = templ.ClearChildren(ctx) _, err = templBuffer.WriteString("
") if err != nil { return err } - var var_2 = []any{"column", "has-text-centered", "is-primary", border} - err = templ.RenderCSSItems(ctx, templBuffer, var_2...) + var var_3 = []any{"column", "has-text-centered", "is-primary", border} + err = templ.RenderCSSItems(ctx, templBuffer, var_3...) if err != nil { return err } @@ -52,7 +84,7 @@ func counts(global, session int) templ.Component { if err != nil { return err } - _, err = templBuffer.WriteString(templ.EscapeString(templ.CSSClasses(var_2).String())) + _, err = templBuffer.WriteString(templ.EscapeString(templ.CSSClasses(var_3).String())) if err != nil { return err } @@ -60,8 +92,8 @@ func counts(global, session int) templ.Component { if err != nil { return err } - var var_3 string = strconv.Itoa(global) - _, err = templBuffer.WriteString(templ.EscapeString(var_3)) + var var_4 string = strconv.Itoa(global) + _, err = templBuffer.WriteString(templ.EscapeString(var_4)) if err != nil { return err } @@ -69,8 +101,8 @@ func counts(global, session int) templ.Component { if err != nil { return err } - var_4 := `Global` - _, err = templBuffer.WriteString(var_4) + var_5 := `Global` + _, err = templBuffer.WriteString(var_5) if err != nil { return err } @@ -78,8 +110,8 @@ func counts(global, session int) templ.Component { if err != nil { return err } - var_5 := `+1` - _, err = templBuffer.WriteString(var_5) + var_6 := `+1` + _, err = templBuffer.WriteString(var_6) if err != nil { return err } @@ -87,8 +119,8 @@ func counts(global, session int) templ.Component { if err != nil { return err } - var var_6 = []any{"column", "has-text-centered", border} - err = templ.RenderCSSItems(ctx, templBuffer, var_6...) + var var_7 = []any{"column", "has-text-centered", border} + err = templ.RenderCSSItems(ctx, templBuffer, var_7...) if err != nil { return err } @@ -96,7 +128,7 @@ func counts(global, session int) templ.Component { if err != nil { return err } - _, err = templBuffer.WriteString(templ.EscapeString(templ.CSSClasses(var_6).String())) + _, err = templBuffer.WriteString(templ.EscapeString(templ.CSSClasses(var_7).String())) if err != nil { return err } @@ -104,8 +136,8 @@ func counts(global, session int) templ.Component { if err != nil { return err } - var var_7 string = strconv.Itoa(session) - _, err = templBuffer.WriteString(templ.EscapeString(var_7)) + var var_8 string = strconv.Itoa(session) + _, err = templBuffer.WriteString(templ.EscapeString(var_8)) if err != nil { return err } @@ -113,8 +145,8 @@ func counts(global, session int) templ.Component { if err != nil { return err } - var_8 := `Session` - _, err = templBuffer.WriteString(var_8) + var_9 := `Session` + _, err = templBuffer.WriteString(var_9) if err != nil { return err } @@ -122,8 +154,8 @@ func counts(global, session int) templ.Component { if err != nil { return err } - var_9 := `+1` - _, err = templBuffer.WriteString(var_9) + var_10 := `+1` + _, err = templBuffer.WriteString(var_10) if err != nil { return err } @@ -146,17 +178,17 @@ func Page(global, session int) templ.Component { defer templ.ReleaseBuffer(templBuffer) } ctx = templ.InitializeContext(ctx) - var_10 := templ.GetChildren(ctx) - if var_10 == nil { - var_10 = templ.NopComponent + var_11 := templ.GetChildren(ctx) + if var_11 == nil { + var_11 = templ.NopComponent } ctx = templ.ClearChildren(ctx) _, err = templBuffer.WriteString("") if err != nil { return err } - var_11 := `Counts` - _, err = templBuffer.WriteString(var_11) + var_12 := `Counts` + _, err = templBuffer.WriteString(var_12) if err != nil { return err } @@ -164,8 +196,8 @@ func Page(global, session int) templ.Component { if err != nil { return err } - var_12 := `` - _, err = templBuffer.WriteString(var_12) + var_13 := `` + _, err = templBuffer.WriteString(var_13) if err != nil { return err } @@ -173,8 +205,8 @@ func Page(global, session int) templ.Component { if err != nil { return err } - var_13 := `Counts` - _, err = templBuffer.WriteString(var_13) + var_14 := `Counts` + _, err = templBuffer.WriteString(var_14) if err != nil { return err }