Reduce number of allocations for rendering elements and attributes (#265) This change does some optimizations to reduce the number of memory heap allocations. Also: - Checks for `io.StringWriter` and uses that if available. - Pre-allocates byte slices for commonly used strings. - Fixed the benchmarks to not count `strings.Builder` allocations. These are the benchmark results from before the changes (with the benchmark fix): ``` go test -bench . -benchmem ./... goos: darwin goarch: arm64 pkg: maragu.dev/gomponents cpu: Apple M3 Max BenchmarkAttr/boolean_attributes-16 25371446 46.81 ns/op 40 B/op 3 allocs/op BenchmarkAttr/name-value_attributes-16 13534495 88.24 ns/op 72 B/op 4 allocs/op BenchmarkEl/normal_elements-16 14068998 86.28 ns/op 48 B/op 5 allocs/op PASS ok maragu.dev/gomponents 4.894s PASS ok maragu.dev/gomponents/components 0.163s goos: darwin goarch: arm64 pkg: maragu.dev/gomponents/html cpu: Apple M3 Max BenchmarkLargeHTMLDocument-16 526 2092062 ns/op 2950444 B/op 90031 allocs/op PASS ok maragu.dev/gomponents/html 1.463s PASS ok maragu.dev/gomponents/http 0.168s ? maragu.dev/gomponents/internal/assert [no test files] PASS ok maragu.dev/gomponents/internal/import 0.135s ``` After: ``` go test -bench . -benchmem ./... goos: darwin goarch: arm64 pkg: maragu.dev/gomponents cpu: Apple M3 Max BenchmarkAttr/boolean_attributes-16 51947022 19.75 ns/op 8 B/op 1 allocs/op BenchmarkAttr/name-value_attributes-16 18138727 64.87 ns/op 24 B/op 2 allocs/op BenchmarkEl/normal_elements-16 21048692 55.48 ns/op 24 B/op 2 allocs/op PASS ok maragu.dev/gomponents 3.687s PASS ok maragu.dev/gomponents/components 0.158s goos: darwin goarch: arm64 pkg: maragu.dev/gomponents/html cpu: Apple M3 Max BenchmarkLargeHTMLDocument-16 714 1535017 ns/op 2630426 B/op 40028 allocs/op PASS ok maragu.dev/gomponents/html 1.398s PASS ok maragu.dev/gomponents/http 0.171s ? maragu.dev/gomponents/internal/assert [no test files] PASS ok maragu.dev/gomponents/internal/import 0.137s ```
1 file changed, 3 insertions(+), 2 deletions(-)
changed files
M html/elements_test.go → html/elements_test.go
@@ -168,7 +168,7 @@ } } func BenchmarkLargeHTMLDocument(b *testing.B) { - b.ReportAllocs() + var sb strings.Builder for i := 0; i < b.N; i++ { elements := make([]g.Node, 0, 10000)@@ -181,7 +181,8 @@ ) } doc := Div(elements...) - var sb strings.Builder _ = doc.Render(&sb) + + sb.Reset() } }