feat: add benchmark target to Makefile #14

Merged
mvhutz merged 2 commits from feat/benchmark-target into main 2026-01-11 22:48:27 +00:00
2 changed files with 75 additions and 1 deletions

View File

@@ -1,7 +1,7 @@
BINARY_NAME=lambda
TEST=simple
.PHONY: help build run profile explain graph docs clean
.PHONY: help build run profile explain graph docs bench clean
.DEFAULT_GOAL := help
.SILENT:
@@ -13,6 +13,7 @@ help:
echo " explain - Build and run with explanation mode and profiling"
echo " graph - Generate and open CPU profile visualization"
echo " docs - Start local godoc server on port 6060"
echo " bench - Run benchmarks for all samples"
echo " clean - Remove all build artifacts"
build:
@@ -37,6 +38,9 @@ docs:
echo ">>> View at 'http://localhost:6060/pkg/git.maximhutz.com/max/lambda/'"
go run golang.org/x/tools/cmd/godoc@latest -http=:6060
bench:
go test -bench=. -benchtime=10x -cpu=4 ./cmd/lambda
clean:
rm -f ${BINARY_NAME}
rm -f program.out

View File

@@ -0,0 +1,70 @@
package main
import (
"os"
"testing"
"git.maximhutz.com/max/lambda/internal/config"
"git.maximhutz.com/max/lambda/internal/engine"
"git.maximhutz.com/max/lambda/pkg/convert"
"git.maximhutz.com/max/lambda/pkg/lambda"
"git.maximhutz.com/max/lambda/pkg/saccharine"
)
// Helper function to run a single sample through the lambda interpreter.
func runSample(samplePath string) error {
// Read the sample file.
input, err := os.ReadFile(samplePath)
if err != nil {
return err
}
// Parse code into syntax tree.
ast, err := saccharine.Parse(string(input))
if err != nil {
return err
}
// Compile expression to lambda calculus.
compiled := convert.SaccharineToLambda(ast)
// Create minimal config for benchmarking.
cfg := &config.Config{
Source: config.StringSource{Data: ""},
Destination: config.StdoutDestination{},
Profile: "",
Explanation: false,
Statistics: false,
Verbose: false,
}
// Create and run the engine.
process := engine.New(cfg, &compiled)
process.Run()
// Get final result (to ensure it's not optimized away).
_ = lambda.Stringify(compiled)
return nil
}
// Benchmark all samples using sub-benchmarks.
func BenchmarkSamples(b *testing.B) {
samples := map[string]string{
"Church": "../../samples/church.txt",
"Fast": "../../samples/fast.txt",
"Saccharine": "../../samples/saccharine.txt",
"Simple": "../../samples/simple.txt",
"Thunk": "../../samples/thunk.txt",
}
for name, path := range samples {
b.Run(name, func(b *testing.B) {
for b.Loop() {
if err := runSample(path); err != nil {
b.Fatal(err)
}
}
})
}
}