diff --git a/Makefile b/Makefile index c7a3c83..52b2222 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/cmd/lambda/benchmark_test.go b/cmd/lambda/benchmark_test.go new file mode 100644 index 0000000..ed5d871 --- /dev/null +++ b/cmd/lambda/benchmark_test.go @@ -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) + } + } + }) + } +}