Skip to content

Commit

Permalink
chore: update Go benchmark to include Go templates
Browse files Browse the repository at this point in the history
  • Loading branch information
a-h committed Aug 17, 2023
1 parent 35183ac commit 2f0245f
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 44 deletions.
21 changes: 8 additions & 13 deletions benchmarks/templ/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
36 changes: 33 additions & 3 deletions benchmarks/templ/render_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -24,15 +25,44 @@ func BenchmarkCurrent(b *testing.B) {
}
}

var html = `<div><h1>Luiz Bonfa</h1><div style="font-family: &#39;sans-serif&#39;" id="test" data-contents="something with &#34;quotes&#34; and a &lt;tag&gt;"><div>email:<a href="mailto: [email protected]">[email protected]</a></div></div></div><hr noshade><hr optionA optionB optionC="other"><hr noshade>`
var goTemplate = template.Must(template.New("example").Parse(`<div>
<h1>{{.Name}}</h1>
<div style="font-family: &#39;sans-serif&#39;" id="test" data-contents="something with &#34;quotes&#34; and a &lt;tag&gt;">
<div>
email:<a href="mailto: {{.Email}}">{{.Email}}</a></div>
</div>
</div>
<hr noshade>
<hr optionA optionB optionC="other">
<hr noshade>
`))

func BenchmarkGoTemplate(b *testing.B) {
w := new(strings.Builder)
person := Person{
Name: "Luiz Bonfa",
Email: "[email protected]",
}
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 = `<div><h1>Luiz Bonfa</h1><div style="font-family: &#39;sans-serif&#39;" id="test" data-contents="something with &#34;quotes&#34; and a &lt;tag&gt;"><div>email:<a href="mailto: [email protected]">[email protected]</a></div></div></div><hr noshade><hr optionA optionB optionC="other"><hr noshade>`

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()
}
}
88 changes: 60 additions & 28 deletions examples/counter/components/components_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 2f0245f

Please sign in to comment.