Skip to content
Open
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
23 changes: 23 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Contributing to Fastbelt

Issues and pull requests are welcome.

## Performance Benchmarking

Use the following command as the standard end-to-end benchmark:

```bash
go test -run '^$' -bench '^BenchmarkWorkspaceCycle$' ./examples/statemachine
```

For more targeted changes (for example in the lexer or parser), other benchmarks may be more suitable.

When running benchmarks, execute them at least 5 times and use the average `ms/resource` value as the standard metric. This helps reduce noise from other processes running on your machine, especially because Fastbelt makes heavy use of multithreading. You should also limit the number of CPU cores to 1 (`go test -cpu=1`) unless you need to compare in a multicore scenario.

For convenience, you can run the internal benchmark helper:

```bash
go run ./internal/bench -runs 30 -cpu 1
```

Except for changes where the expected performance impact is negligible, contributors should run benchmarks both with and without their changes (for example by comparing their branch with `main`) and include the results in the Pull Request description.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ For editor integration, see the VS Code extension in `internal/vscode-extensions

## Contributing

Issues and pull requests are welcome.
See [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution guidelines.

## License

Expand Down
16 changes: 13 additions & 3 deletions cmd/fastbelt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
"typefox.dev/fastbelt/internal/generator"
"typefox.dev/fastbelt/internal/grammar"
"typefox.dev/fastbelt/textdoc"
"typefox.dev/fastbelt/util/service"
"typefox.dev/fastbelt/workspace"
"typefox.dev/lsp"
)

Expand Down Expand Up @@ -86,12 +88,20 @@ func runLegacyGenerate(args []string) error {
return err
}

srv := grammar.CreateServices()
sc := grammar.CreateServices()
file, _ := textdoc.NewFile(lsp.URIFromPath(grammarPath), "fb", 0, string(grammarText))

document := core.NewDocument(file)
srv.Workspace().DocumentManager.Set(document)
if err := srv.Workspace().Builder.Build(context.Background(), []*core.Document{document}, func() {}); err != nil {
documents, err := service.Get[workspace.DocumentManager](sc)
if err != nil {
return err
}
documents.Set(document)
builder, err := service.Get[workspace.Builder](sc)
if err != nil {
return err
}
if err := builder.Build(context.Background(), []*core.Document{document}, func() {}); err != nil {
return err
}

Expand Down
28 changes: 19 additions & 9 deletions examples/statemachine/benchmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import (

"github.com/stretchr/testify/assert"
"typefox.dev/fastbelt"
"typefox.dev/fastbelt/lexer"
"typefox.dev/fastbelt/parser"
"typefox.dev/fastbelt/util/service"
"typefox.dev/fastbelt/workspace"
)

Expand All @@ -28,14 +31,16 @@ func BenchmarkWorkspaceCycle(b *testing.B) {
length += len(contents[i])
}
srv := CreateServices()
docManager := service.MustGet[workspace.DocumentManager](srv)
lock := service.MustGet[workspace.Lock](srv)
builder := service.MustGet[workspace.Builder](srv)

var totalNs int64
b.SetBytes(int64(length))
b.ResetTimer()
for range b.N {
// Fresh document manager per cycle so each build starts from a clean state.
srv.Workspace().DocumentManager = workspace.NewDefaultDocumentManager()
docManager := srv.Workspace().DocumentManager
docManager.Clear()

docs := make([]*fastbelt.Document, resourceCount)
for i, content := range contents {
Expand All @@ -49,8 +54,8 @@ func BenchmarkWorkspaceCycle(b *testing.B) {
}

start := time.Now()
srv.Workspace().Lock.Write(context.Background(), func(ctx context.Context, downgrade func()) {
if err := srv.Workspace().Builder.Build(ctx, docs, downgrade); err != nil {
lock.Write(context.Background(), func(ctx context.Context, downgrade func()) {
if err := builder.Build(ctx, docs, downgrade); err != nil {
b.Errorf("build failed: %v", err)
}
})
Expand All @@ -66,11 +71,12 @@ func BenchmarkWorkspaceCycle(b *testing.B) {
func BenchmarkTraverseContentSeq(b *testing.B) {
content, _ := generateStatemachineContent(0)
srv := CreateServices()
documentParser := service.MustGet[workspace.DocumentParser](srv)
doc, err := fastbelt.NewDocumentFromString("file:///workspace/statemachine_0.statemachine", "statemachine", content)
if err != nil {
b.Fatal(err)
}
srv.Workspace().DocumentParser.Parse(doc)
documentParser.Parse(doc)

for b.Loop() {
count := 0
Expand All @@ -84,11 +90,12 @@ func BenchmarkTraverseContentSeq(b *testing.B) {
func TestAllNodesEquivalence(t *testing.T) {
content, elementCount := generateStatemachineContent(0)
srv := CreateServices()
documentParser := service.MustGet[workspace.DocumentParser](srv)
doc, err := fastbelt.NewDocumentFromString("file:///workspace/statemachine_0.statemachine", "statemachine", content)
if err != nil {
t.Fatal(err)
}
srv.Workspace().DocumentParser.Parse(doc)
documentParser.Parse(doc)
nodeCount := 0
for range fastbelt.AllNodes(doc.Root) {
nodeCount++
Expand All @@ -100,11 +107,12 @@ func TestAllChildrenEquivalence(t *testing.T) {
content, elementCount := generateStatemachineContent(0)
totalCount := elementCount - 1 // AllChildren does not include the root node, so we subtract 1 from the total count
srv := CreateServices()
documentParser := service.MustGet[workspace.DocumentParser](srv)
doc, err := fastbelt.NewDocumentFromString("file:///workspace/statemachine_0.statemachine", "statemachine", content)
if err != nil {
t.Fatal(err)
}
srv.Workspace().DocumentParser.Parse(doc)
documentParser.Parse(doc)
childCount := 0
for range fastbelt.AllChildren(doc.Root) {
childCount++
Expand All @@ -117,7 +125,9 @@ func TestAllChildrenEquivalence(t *testing.T) {
func BenchmarkParser(b *testing.B) {
content, _ := generateStatemachineContent(0)
srv := CreateServices()
tokens := srv.Generated().Lexer.Lex(content).Tokens
lexerService := service.MustGet[lexer.Lexer](srv)
parserService := service.MustGet[parser.Parser](srv)
tokens := lexerService.Lex(content).Tokens
doc, err := fastbelt.NewDocumentFromString("file:///workspace/statemachine_0.statemachine", "statemachine", content)
if err != nil {
b.Fatal(err)
Expand All @@ -126,7 +136,7 @@ func BenchmarkParser(b *testing.B) {
b.SetBytes(int64(len(content)))
b.ResetTimer()
for b.Loop() {
result := srv.Generated().Parser.Parse(doc)
result := parserService.Parse(doc)
doc.Root = result.Node
}
}
Expand Down
64 changes: 39 additions & 25 deletions examples/statemachine/linker_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 17 additions & 13 deletions examples/statemachine/parser_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading