Improve ModuleInstance String() performance (#28246)

* Optimize (m ModuleInstance) String()

Optimize (m ModuleInstance) String() to preallocate the buffer and use strings.Builder instead of bytes.Buffer

This leads to a common case only doing a single allocation as opposed to a few allocations which the bytes.Buffer is doing.

* adding a benchmark test

Result:

```
$ go test -bench=String ./addrs -benchmem 
BenchmarkStringShort-12         18271692                56.52 ns/op           16 B/op          1 allocs/op
BenchmarkStringLong-12           8057071               158.5 ns/op            96 B/op          1 allocs/op
PASS
$ git checkout main addrs/module_instance.go
$ go test -bench=String ./addrs -benchmem 
BenchmarkStringShort-12          7690818               162.0 ns/op            80 B/op          2 allocs/op
BenchmarkStringLong-12           2922117               414.1 ns/op           288 B/op          3 allocs/op
```

* Update module_instance_test.go

switch spaces to tabs
This commit is contained in:
Dennis Gursky 2021-04-05 05:44:27 -07:00 committed by GitHub
parent 973ed6eae6
commit 4e42d21837
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 26 additions and 2 deletions

View File

@ -1,8 +1,8 @@
package addrs
import (
"bytes"
"fmt"
"strings"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
@ -251,7 +251,17 @@ func (m ModuleInstance) Parent() ModuleInstance {
//
// The address of the root module has the empty string as its representation.
func (m ModuleInstance) String() string {
var buf bytes.Buffer
if len(m) == 0 {
return ""
}
// Calculate minimal necessary space (no instance keys).
l := 0
for _, step := range m {
l += len(step.Name)
}
buf := strings.Builder{}
// 8 is len(".module.") which separates entries.
buf.Grow(l + len(m)*8)
sep := ""
for _, step := range m {
buf.WriteString(sep)

View File

@ -77,3 +77,17 @@ func TestModuleInstanceEqual_false(t *testing.T) {
})
}
}
func BenchmarkStringShort(b *testing.B) {
addr, _ := ParseModuleInstanceStr(`module.foo`)
for n := 0; n < b.N; n++ {
addr.String()
}
}
func BenchmarkStringLong(b *testing.B) {
addr, _ := ParseModuleInstanceStr(`module.southamerica-brazil-region.module.user-regional-desktops.module.user-name`)
for n := 0; n < b.N; n++ {
addr.String()
}
}