Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pool lexers to reduce allocations and improve performance #1610

Merged
merged 4 commits into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ jobs:

- name: Run benchmark on current branch
run: |
( for i in {1..${{ steps.settings.outputs.benchmark_repetitions }}}; do go test ./... -run=XXX -bench=. -shuffle=on; done | sed 's/pkg:.*/pkg: github.com\/onflow\/cadence\/runtime/' ) | tee new.txt
( for i in {1..${{ steps.settings.outputs.benchmark_repetitions }}}; do go test ./... -run=XXX -bench=. -benchmem -shuffle=on; done | sed 's/pkg:.*/pkg: github.com\/onflow\/cadence\/runtime/' ) | tee new.txt
# the package replace line above is to make the results table more readable, since it is not fragmented by package


Expand All @@ -55,15 +55,15 @@ jobs:

- name: Run benchmark on base branch
run: |
( for i in {1..${{ steps.settings.outputs.benchmark_repetitions }}}; do go test ./... -run=XXX -bench=. -shuffle=on; done | sed 's/pkg:.*/pkg: github.com\/onflow\/cadence\/runtime/' ) | tee old.txt
( for i in {1..${{ steps.settings.outputs.benchmark_repetitions }}}; do go test ./... -run=XXX -bench=. -benchmem -shuffle=on; done | sed 's/pkg:.*/pkg: github.com\/onflow\/cadence\/runtime/' ) | tee old.txt

# see https://trstringer.com/github-actions-multiline-strings/ to see why this part is complex
- name: Use benchstat for comparison
run: |
export PATH=$PATH:$(go env GOPATH)/bin
GO111MODULE=off go get golang.org/x/perf/cmd/benchstat
echo "BENCHSTAT<<EOF" >> $GITHUB_ENV
echo "$(benchstat -html -sort delta old.txt new.txt | sed '/<title/,/<\/style>/d' | sed 's/<!doctype html>//g')" >> $GITHUB_ENV
echo "$(benchstat -html -sort name old.txt new.txt | sed '/<title/,/<\/style>/d' | sed 's/<!doctype html>//g')" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Find existing comment on PR
uses: peter-evans/find-comment@v1
Expand All @@ -81,9 +81,9 @@ jobs:
body: |
## Cadence [Benchstat](https://pkg.go.dev/golang.org/x/perf/cmd/benchstat) comparison
This branch with compared with the base branch ${{ github.event.pull_request.base.label }} commit ${{ github.event.pull_request.base.sha }}
The command `for i in {1..N}; do go test ./... -run=XXX -bench=. -shuffle=on; done` was used.
The command `for i in {1..N}; do go test ./... -run=XXX -bench=. -benchmem -shuffle=on; done` was used.
Bench tests were run a total of ${{ steps.settings.outputs.benchmark_repetitions }} times on each branch.
## Results
${{ env.BENCHSTAT }}

edit-mode: replace
edit-mode: replace
37 changes: 29 additions & 8 deletions runtime/parser2/lexer/lexer.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package lexer

import (
"fmt"
"sync"
"unicode/utf8"

"github.com/onflow/cadence/runtime/ast"
Expand Down Expand Up @@ -95,15 +96,35 @@ func (l *lexer) Revert(cursor int) {
l.cursor = cursor
}

func (l *lexer) clear() {
l.startOffset = 0
l.endOffset = 0
l.prevEndOffset = 0
l.current = EOF
l.prev = EOF
l.canBackup = false
l.startPos = position{line: 1}
l.cursor = 0
l.tokens = l.tokens[:0]
l.tokenCount = 0
}

func (l *lexer) Reclaim() {
pool.Put(l)
}

var pool = sync.Pool{
New: func() interface{} {
return &lexer{
tokens: make([]Token, 0, 2048),
}
},
}

func Lex(input string) TokenStream {
l := &lexer{
input: input,
startPos: position{line: 1},
endOffset: 0,
prevEndOffset: 0,
current: EOF,
prev: EOF,
}
l := pool.Get().(*lexer)
l.clear()
l.input = input
l.run(rootState)
return l
}
Expand Down
1 change: 1 addition & 0 deletions runtime/parser2/lexer/tokenstream.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,5 @@ type TokenStream interface {
Revert(cursor int)
// Input returns the whole input as source code
Input() string
Reclaim()
}
5 changes: 4 additions & 1 deletion runtime/parser2/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type parser struct {
func Parse(input string, parse func(*parser) interface{}) (result interface{}, errors []error) {
// create a lexer, which turns the input string into tokens
tokens := lexer.Lex(input)
defer tokens.Reclaim()
return ParseTokenStream(tokens, parse)
}

Expand Down Expand Up @@ -432,7 +433,9 @@ func ParseArgumentList(input string) (arguments ast.Arguments, errs []error) {
}

func ParseProgram(input string) (program *ast.Program, err error) {
return ParseProgramFromTokenStream(lexer.Lex(input))
tokens := lexer.Lex(input)
defer tokens.Reclaim()
return ParseProgramFromTokenStream(tokens)
}

func ParseProgramFromTokenStream(input lexer.TokenStream) (program *ast.Program, err error) {
Expand Down