From 7beec5fab4a5c54e17ff93c1bbabcb034e075302 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leandro=20L=C3=B3pez=20=28inkel=29?= Date: Tue, 19 Oct 2021 14:44:43 -0300 Subject: [PATCH 1/3] hclsyntax: Add benchmark for LexConfig --- hclsyntax/public_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hclsyntax/public_test.go b/hclsyntax/public_test.go index 62809985..596b1a26 100644 --- a/hclsyntax/public_test.go +++ b/hclsyntax/public_test.go @@ -2,6 +2,8 @@ package hclsyntax import ( "testing" + + "github.com/hashicorp/hcl/v2" ) func TestValidIdentifier(t *testing.T) { @@ -44,3 +46,19 @@ func TestValidIdentifier(t *testing.T) { }) } } + +var T Tokens + +func BenchmarkLexConfig(b *testing.B) { + src := []byte("module \"once\" {\n source = \"../modules/foo\"\n}\n\nmodule \"twice\" {\n source = \"../modules/foo\"\n}\n") + filename := "testdata/dave/main.tf" + start := hcl.Pos{Line: 1, Column: 1, Byte: 0} + + var tokens Tokens + + for i := 0; i < b.N; i++ { + tokens, _ = LexConfig(src, filename, start) + } + + T = tokens +} From 6fe2e711b3b4f7a7607bee348547e04c6c3ec19e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leandro=20L=C3=B3pez=20=28inkel=29?= Date: Tue, 19 Oct 2021 14:47:56 -0300 Subject: [PATCH 2/3] hclsyntax: Copy only tok.Range instead of whole object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doing this reduces the memory used in ~11%, as the following benchstat comparison shows: name old time/op new time/op delta LexConfig-12 9.27µs ± 0% 9.03µs ± 1% -2.55% (p=0.000 n=9+10) name old alloc/op new alloc/op delta LexConfig-12 8.94kB ± 0% 7.98kB ± 0% -10.74% (p=0.000 n=10+10) name old allocs/op new allocs/op delta LexConfig-12 37.0 ± 0% 37.0 ± 0% ~ (all equal) Benchmarks were created using: go test -benchmem -benchtime=200000x -count=10 -bench=. --- hclsyntax/token.go | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/hclsyntax/token.go b/hclsyntax/token.go index f4c6c934..4fe26a1e 100644 --- a/hclsyntax/token.go +++ b/hclsyntax/token.go @@ -191,8 +191,7 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { toldBadUTF8 := 0 for _, tok := range tokens { - // copy token so it's safe to point to it - tok := tok + tokRange := tok.Range switch tok.Type { case TokenBitwiseAnd, TokenBitwiseOr, TokenBitwiseXor, TokenBitwiseNot: @@ -211,7 +210,7 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { Severity: hcl.DiagError, Summary: "Unsupported operator", Detail: fmt.Sprintf("Bitwise operators are not supported.%s", suggestion), - Subject: &tok.Range, + Subject: &tokRange, }) toldBitwise++ } @@ -221,7 +220,7 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { Severity: hcl.DiagError, Summary: "Unsupported operator", Detail: "\"**\" is not a supported operator. Exponentiation is not supported as an operator.", - Subject: &tok.Range, + Subject: &tokRange, }) toldExponent++ @@ -234,7 +233,7 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { Severity: hcl.DiagError, Summary: "Invalid character", Detail: "The \"`\" character is not valid. To create a multi-line string, use the \"heredoc\" syntax, like \"< Date: Wed, 20 Oct 2021 10:14:21 -0300 Subject: [PATCH 3/3] hclsyntax: Allocate copy of tok.Range only when it's needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In a similar fashion as the parent commit, here instead of always copying the tok.Range for later use, we define a function to get this copied value, and thus we only allocate the copy if it's needed, otherwise don't. For the benchmark introduced earlier, the reduction in allocations and memory usage is outstanding: name old time/op new time/op delta LexConfig-12 9.05µs ± 1% 7.83µs ± 1% -13.54% (p=0.000 n=10+10) name old alloc/op new alloc/op delta LexConfig-12 7.98kB ± 0% 6.06kB ± 0% -24.07% (p=0.000 n=10+10) name old allocs/op new allocs/op delta LexConfig-12 37.0 ± 0% 7.0 ± 0% -81.08% (p=0.000 n=10+10) Benchmarks were created using: go test -benchmem -benchtime=200000x -count=10 -bench=. --- hclsyntax/token.go | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/hclsyntax/token.go b/hclsyntax/token.go index 4fe26a1e..5ef093f9 100644 --- a/hclsyntax/token.go +++ b/hclsyntax/token.go @@ -191,7 +191,10 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { toldBadUTF8 := 0 for _, tok := range tokens { - tokRange := tok.Range + tokRange := func() *hcl.Range { + r := tok.Range + return &r + } switch tok.Type { case TokenBitwiseAnd, TokenBitwiseOr, TokenBitwiseXor, TokenBitwiseNot: @@ -210,7 +213,7 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { Severity: hcl.DiagError, Summary: "Unsupported operator", Detail: fmt.Sprintf("Bitwise operators are not supported.%s", suggestion), - Subject: &tokRange, + Subject: tokRange(), }) toldBitwise++ } @@ -220,7 +223,7 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { Severity: hcl.DiagError, Summary: "Unsupported operator", Detail: "\"**\" is not a supported operator. Exponentiation is not supported as an operator.", - Subject: &tokRange, + Subject: tokRange(), }) toldExponent++ @@ -233,7 +236,7 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics { Severity: hcl.DiagError, Summary: "Invalid character", Detail: "The \"`\" character is not valid. To create a multi-line string, use the \"heredoc\" syntax, like \"<