Skip to content

Instantly share code, notes, and snippets.

@quasilyte
Created December 8, 2021 08:59
Show Gist options
  • Save quasilyte/46d9c058723f7bdba7ef50a163f2ce90 to your computer and use it in GitHub Desktop.
Save quasilyte/46d9c058723f7bdba7ef50a163f2ce90 to your computer and use it in GitHub Desktop.
bytes.Buffer grow benchmarks
package main
import (
"bytes"
"encoding/xml"
"fmt"
"html/template"
"strings"
"testing"
)
func BenchmarkBufferWrite(b *testing.B) {
for _, size := range []int{1, 8, 16, 32, 64, 128, 1024, 4096} {
for _, numparts := range []int{1, 4, 8, 16} {
parts := make([]string, numparts)
for i := range parts {
parts[i] = strings.Repeat("a", size)
}
b.Run(fmt.Sprintf("len%d_x%d", size, numparts), func(b *testing.B) {
for i := 0; i < b.N; i++ {
var b bytes.Buffer
for _, part := range parts {
b.WriteString(part)
}
bytesSink = b.Bytes()
}
})
}
}
}
func BenchmarkXMLMarshal(b *testing.B) {
type User struct {
ID int `xml:"id"`
Name string `xml:"name"`
Tags []string `xml:"tag"`
}
type Root struct {
Users []User `xml:"user"`
}
tags := []string{"simple-tag", "new"}
createRoot := func(numUsers int) *Root {
root := &Root{}
for i := 0; i < numUsers; i++ {
u := User{
ID: i + 1,
Name: fmt.Sprintf("user-%d", i),
}
if i%2 == 0 {
u.Tags = tags
}
root.Users = append(root.Users, u)
}
return root
}
for _, numUsers := range []int{50, 100, 200, 400, 800} {
b.Run(fmt.Sprintf("numElems%d", numUsers), func(b *testing.B) {
root := createRoot(numUsers)
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := xml.Marshal(root)
if err != nil {
b.Fatal(err)
}
}
})
}
}
func BenchmarkHTMLEscape(b *testing.B) {
inputs := []string{
`short & simple`,
`<div id="data" class="a b"><b></b></div>`,
`with "quotes" and longer than the previous text`,
`this text has "-quotes, < and > chars & it's also longer than any of the texts before`,
}
for _, repeat := range []int{1, 2, 4, 8, 16, 32, 128, 1024} {
for i, data := range inputs {
data = strings.Repeat(data, repeat)
b.Run(fmt.Sprintf("input%dx%d_%dbytes", i, repeat, len(data)), func(b *testing.B) {
for i := 0; i < b.N; i++ {
stringSink = template.HTMLEscapeString(data)
}
})
}
}
}
func BenchmarkHTMLTemplate(b *testing.B) {
makeDocument := func(numURLs int) (string, []string) {
var b strings.Builder
urls := make([]string, numURLs)
for i := 0; i < numURLs; i++ {
fmt.Fprintf(&b, `<a href="{{index .URLS %d}}"></a>`, i)
urls[i] = fmt.Sprintf("https://google.com/search?q=golang how to avoid GC spikes free without sms attempt %d&sclient=superpro", i)
}
return b.String(), urls
}
for _, numURLs := range []int{50, 500} {
doc, urls := makeDocument(numURLs)
tmpl := template.Must(template.New("example").Parse(doc))
var data = struct {
URLS []string
}{
URLS: urls,
}
b.Run(fmt.Sprintf("numURLs%d", numURLs), func(b *testing.B) {
for i := 0; i < b.N; i++ {
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
b.Fatal(err)
}
}
})
}
}
var stringSink string
var bytesSink []byte
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment