package luajit_bench import ( "testing" luajit "git.sharkk.net/Sky/LuaJIT-to-Go" ) // BenchmarkSimpleDoString benchmarks direct execution of a simple expression func BenchmarkSimpleDoString(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := "local x = 1 + 1" b.ResetTimer() TrackMemoryUsage(b, "dostring", func() { for i := 0; i < b.N; i++ { if err := state.DoString(code); err != nil { b.Fatalf("DoString failed: %v", err) } } }) } // BenchmarkSimpleCompileAndRun benchmarks compile and run of a simple expression func BenchmarkSimpleCompileAndRun(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := "local x = 1 + 1" b.ResetTimer() TrackMemoryUsage(b, "compile-run", func() { for i := 0; i < b.N; i++ { if err := state.CompileAndRun(code, "simple"); err != nil { b.Fatalf("CompileAndRun failed: %v", err) } } }) } // BenchmarkSimpleCompileLoadRun benchmarks compile, load, and run of a simple expression func BenchmarkSimpleCompileLoadRun(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := "local x = 1 + 1" b.ResetTimer() TrackMemoryUsage(b, "compile-load-run", func() { for i := 0; i < b.N; i++ { bytecode, err := state.CompileBytecode(code, "simple") if err != nil { b.Fatalf("CompileBytecode failed: %v", err) } if err := state.LoadAndRunBytecode(bytecode, "simple"); err != nil { b.Fatalf("LoadAndRunBytecode failed: %v", err) } } }) } // BenchmarkSimplePrecompiledBytecode benchmarks running precompiled bytecode func BenchmarkSimplePrecompiledBytecode(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := "local x = 1 + 1" bytecode, err := state.CompileBytecode(code, "simple") if err != nil { b.Fatalf("CompileBytecode failed: %v", err) } b.ResetTimer() TrackMemoryUsage(b, "precompiled", func() { for i := 0; i < b.N; i++ { if err := state.LoadAndRunBytecode(bytecode, "simple"); err != nil { b.Fatalf("LoadAndRunBytecode failed: %v", err) } } }) } // BenchmarkFunctionCallDoString benchmarks direct execution of a function call func BenchmarkFunctionCallDoString(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() // Setup function setupCode := ` function add(a, b) return a + b end ` if err := state.DoString(setupCode); err != nil { b.Fatalf("Failed to set up function: %v", err) } code := "local result = add(10, 20)" b.ResetTimer() TrackMemoryUsage(b, "func-dostring", func() { for i := 0; i < b.N; i++ { if err := state.DoString(code); err != nil { b.Fatalf("DoString failed: %v", err) } } }) } // BenchmarkFunctionCallPrecompiled benchmarks precompiled function call func BenchmarkFunctionCallPrecompiled(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() // Setup function setupCode := ` function add(a, b) return a + b end ` if err := state.DoString(setupCode); err != nil { b.Fatalf("Failed to set up function: %v", err) } code := "local result = add(10, 20)" bytecode, err := state.CompileBytecode(code, "call") if err != nil { b.Fatalf("CompileBytecode failed: %v", err) } b.ResetTimer() TrackMemoryUsage(b, "func-precompiled", func() { for i := 0; i < b.N; i++ { if err := state.LoadAndRunBytecode(bytecode, "call"); err != nil { b.Fatalf("LoadAndRunBytecode failed: %v", err) } } }) } // BenchmarkLoopDoString benchmarks direct execution of a loop func BenchmarkLoopDoString(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := ` local sum = 0 for i = 1, 1000 do sum = sum + i end ` b.ResetTimer() TrackMemoryUsage(b, "loop-dostring", func() { for i := 0; i < b.N; i++ { if err := state.DoString(code); err != nil { b.Fatalf("DoString failed: %v", err) } } }) } // BenchmarkLoopPrecompiled benchmarks precompiled loop execution func BenchmarkLoopPrecompiled(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := ` local sum = 0 for i = 1, 1000 do sum = sum + i end ` bytecode, err := state.CompileBytecode(code, "loop") if err != nil { b.Fatalf("CompileBytecode failed: %v", err) } b.ResetTimer() TrackMemoryUsage(b, "loop-precompiled", func() { for i := 0; i < b.N; i++ { if err := state.LoadAndRunBytecode(bytecode, "loop"); err != nil { b.Fatalf("LoadAndRunBytecode failed: %v", err) } } }) } // BenchmarkTableOperationsDoString benchmarks direct execution of table operations func BenchmarkTableOperationsDoString(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := ` local t = {} for i = 1, 100 do t[i] = i * 2 end local sum = 0 for i, v in ipairs(t) do sum = sum + v end ` b.ResetTimer() TrackMemoryUsage(b, "table-dostring", func() { for i := 0; i < b.N; i++ { if err := state.DoString(code); err != nil { b.Fatalf("DoString failed: %v", err) } } }) } // BenchmarkTableOperationsPrecompiled benchmarks precompiled table operations func BenchmarkTableOperationsPrecompiled(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := ` local t = {} for i = 1, 100 do t[i] = i * 2 end local sum = 0 for i, v in ipairs(t) do sum = sum + v end ` bytecode, err := state.CompileBytecode(code, "table") if err != nil { b.Fatalf("CompileBytecode failed: %v", err) } b.ResetTimer() TrackMemoryUsage(b, "table-precompiled", func() { for i := 0; i < b.N; i++ { if err := state.LoadAndRunBytecode(bytecode, "table"); err != nil { b.Fatalf("LoadAndRunBytecode failed: %v", err) } } }) } // BenchmarkGoFunctionCall benchmarks calling a Go function from Lua func BenchmarkGoFunctionCall(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() // Register a simple Go function add := func(s *luajit.State) int { a := s.ToNumber(1) b := s.ToNumber(2) s.PushNumber(a + b) return 1 } if err := state.RegisterGoFunction("add", add); err != nil { b.Fatalf("RegisterGoFunction failed: %v", err) } code := "local result = add(10, 20)" bytecode, err := state.CompileBytecode(code, "gofunc") if err != nil { b.Fatalf("CompileBytecode failed: %v", err) } b.ResetTimer() TrackMemoryUsage(b, "go-func-call", func() { for i := 0; i < b.N; i++ { if err := state.LoadAndRunBytecode(bytecode, "gofunc"); err != nil { b.Fatalf("LoadAndRunBytecode failed: %v", err) } } }) } // BenchmarkComplexScript benchmarks a more complex script func BenchmarkComplexScript(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := ` -- Define a simple class local Class = {} Class.__index = Class function Class.new(x, y) local self = setmetatable({}, Class) self.x = x or 0 self.y = y or 0 return self end function Class:move(dx, dy) self.x = self.x + dx self.y = self.y + dy return self end function Class:getPosition() return self.x, self.y end -- Create instances and operate on them local instances = {} for i = 1, 50 do instances[i] = Class.new(i, i*2) end local result = 0 for i, obj in ipairs(instances) do obj:move(i, -i) local x, y = obj:getPosition() result = result + x + y end return result ` b.ResetTimer() TrackMemoryUsage(b, "complex-script", func() { for i := 0; i < b.N; i++ { if _, err := state.ExecuteWithResult(code); err != nil { b.Fatalf("ExecuteWithResult failed: %v", err) } } }) } // BenchmarkComplexScriptPrecompiled benchmarks a precompiled complex script func BenchmarkComplexScriptPrecompiled(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() code := ` -- Define a simple class local Class = {} Class.__index = Class function Class.new(x, y) local self = setmetatable({}, Class) self.x = x or 0 self.y = y or 0 return self end function Class:move(dx, dy) self.x = self.x + dx self.y = self.y + dy return self end function Class:getPosition() return self.x, self.y end -- Create instances and operate on them local instances = {} for i = 1, 50 do instances[i] = Class.new(i, i*2) end local result = 0 for i, obj in ipairs(instances) do obj:move(i, -i) local x, y = obj:getPosition() result = result + x + y end return result ` bytecode, err := state.CompileBytecode(code, "complex") if err != nil { b.Fatalf("CompileBytecode failed: %v", err) } b.ResetTimer() TrackMemoryUsage(b, "complex-precompiled", func() { for i := 0; i < b.N; i++ { if err := state.LoadBytecode(bytecode, "complex"); err != nil { b.Fatalf("LoadBytecode failed: %v", err) } if err := state.RunBytecodeWithResults(1); err != nil { b.Fatalf("RunBytecodeWithResults failed: %v", err) } state.Pop(1) // Pop the result } }) } // BenchmarkMultipleExecutions benchmarks executing the same bytecode multiple times func BenchmarkMultipleExecutions(b *testing.B) { state := luajit.New() if state == nil { b.Fatal("Failed to create Lua state") } defer state.Close() // Setup a stateful environment setupCode := ` counter = 0 function increment(amount) counter = counter + (amount or 1) return counter end ` if err := state.DoString(setupCode); err != nil { b.Fatalf("Failed to set up environment: %v", err) } // Compile the function call code := "return increment(5)" bytecode, err := state.CompileBytecode(code, "increment") if err != nil { b.Fatalf("CompileBytecode failed: %v", err) } b.ResetTimer() TrackMemoryUsage(b, "multiple-executions", func() { for i := 0; i < b.N; i++ { if err := state.LoadBytecode(bytecode, "increment"); err != nil { b.Fatalf("LoadBytecode failed: %v", err) } if err := state.RunBytecodeWithResults(1); err != nil { b.Fatalf("RunBytecodeWithResults failed: %v", err) } state.Pop(1) // Pop the result } }) } // BenchmarkBatchVsIndividualTableFields compares batch vs individual table field setting func BenchmarkBatchVsIndividualTableFields(b *testing.B) { b.Run("Individual", func(b *testing.B) { state := luajit.New() defer state.Close() fields := map[string]string{ "name": "test", "version": "1.0", "description": "benchmark", "author": "user", "license": "MIT", "homepage": "example.com", "repository": "git://example.com", "keywords": "test,bench", } TrackMemoryUsage(b, "individual-fields", func() { for i := 0; i < b.N; i++ { tb := state.NewTableBuilder() for k, v := range fields { tb.SetString(k, v) } tb.Build() state.Pop(1) } }) }) b.Run("Batch", func(b *testing.B) { state := luajit.New() defer state.Close() fields := map[string]string{ "name": "test", "version": "1.0", "description": "benchmark", "author": "user", "license": "MIT", "homepage": "example.com", "repository": "git://example.com", "keywords": "test,bench", } TrackMemoryUsage(b, "batch-fields", func() { for i := 0; i < b.N; i++ { btb := state.NewBatchTableBuilder() for k, v := range fields { btb.SetString(k, v) } btb.Build() state.Pop(1) } }) }) } // BenchmarkBatchVsIndividualArrays compares batch vs individual array creation func BenchmarkBatchVsIndividualArrays(b *testing.B) { intArray := make([]int, 100) for i := range intArray { intArray[i] = i * 2 } b.Run("Individual", func(b *testing.B) { state := luajit.New() defer state.Close() TrackMemoryUsage(b, "individual-array", func() { for i := 0; i < b.N; i++ { state.CreateTable(len(intArray), 0) for j, v := range intArray { state.PushNumber(float64(j + 1)) state.PushNumber(float64(v)) state.SetTable(-3) } state.Pop(1) } }) }) b.Run("Batch", func(b *testing.B) { state := luajit.New() defer state.Close() TrackMemoryUsage(b, "batch-array", func() { for i := 0; i < b.N; i++ { state.BatchPushIntArray(intArray) state.Pop(1) } }) }) } // BenchmarkBatchVsIndividualGlobals compares batch vs individual global variable setting func BenchmarkBatchVsIndividualGlobals(b *testing.B) { globals := map[string]string{ "APP_NAME": "myapp", "APP_VERSION": "1.0.0", "APP_ENVIRONMENT": "production", "APP_DEBUG": "false", "APP_URL": "https://example.com", "APP_TIMEZONE": "UTC", "DB_HOST": "localhost", "DB_PORT": "5432", } b.Run("Individual", func(b *testing.B) { state := luajit.New() defer state.Close() TrackMemoryUsage(b, "individual-globals", func() { for i := 0; i < b.N; i++ { for k, v := range globals { state.PushString(v) state.SetGlobal(k) } } }) }) b.Run("Batch", func(b *testing.B) { state := luajit.New() defer state.Close() TrackMemoryUsage(b, "batch-globals", func() { for i := 0; i < b.N; i++ { state.BatchSetGlobals(globals) } }) }) } // BenchmarkBatchVsIndividualTableReads compares batch vs individual table field reading func BenchmarkBatchVsIndividualTableReads(b *testing.B) { state := luajit.New() defer state.Close() // Setup test table setupCode := ` config = { database = {host = "localhost", port = 5432, name = "mydb"}, server = {host = "0.0.0.0", port = 8080, ssl = true}, logging = {level = "info", file = "/var/log/app.log"}, cache = {enabled = true, ttl = 300, size = 1000} } ` if err := state.DoString(setupCode); err != nil { b.Fatalf("Setup failed: %v", err) } keys := []string{"database", "server", "logging", "cache"} b.Run("Individual", func(b *testing.B) { TrackMemoryUsage(b, "individual-reads", func() { for i := 0; i < b.N; i++ { state.GetGlobal("config") values := make(map[string]any) for _, key := range keys { state.GetField(-1, key) if val, err := state.ToValue(-1); err == nil { values[key] = val } state.Pop(1) } state.Pop(1) _ = values } }) }) b.Run("Batch", func(b *testing.B) { TrackMemoryUsage(b, "batch-reads", func() { for i := 0; i < b.N; i++ { state.GetGlobal("config") reader := state.NewBatchTableReader(-1) values, _ := reader.ReadFields(keys) state.Pop(1) _ = values } }) }) } // BenchmarkBatchValuePusher compares batch vs individual value pushing func BenchmarkBatchValuePusher(b *testing.B) { values := []any{"hello", 42, true, 3.14, "world", 100, false, 2.718} b.Run("Individual", func(b *testing.B) { state := luajit.New() defer state.Close() TrackMemoryUsage(b, "individual-push", func() { for i := 0; i < b.N; i++ { for _, v := range values { state.PushValue(v) } state.Pop(len(values)) } }) }) b.Run("Batch", func(b *testing.B) { state := luajit.New() defer state.Close() TrackMemoryUsage(b, "batch-push", func() { for i := 0; i < b.N; i++ { pusher := state.NewBatchValuePusher() for _, v := range values { pusher.Add(v) } pusher.Push() state.Pop(len(values)) } }) }) } // BenchmarkBatchTypeChecking compares batch vs individual type checking func BenchmarkBatchTypeChecking(b *testing.B) { state := luajit.New() defer state.Close() // Setup test values on stack state.PushString("hello") state.PushNumber(42) state.PushBoolean(true) state.PushNil() checks := []luajit.TypeCheck{ {Index: 1, ExpectedType: luajit.TypeString}, {Index: 2, ExpectedType: luajit.TypeNumber}, {Index: 3, ExpectedType: luajit.TypeBoolean}, {Index: 4, ExpectedType: luajit.TypeNil}, } b.Run("Individual", func(b *testing.B) { TrackMemoryUsage(b, "individual-check", func() { for i := 0; i < b.N; i++ { for _, check := range checks { if state.GetType(check.Index) != check.ExpectedType { b.Fatal("Type mismatch") } } } }) }) b.Run("Batch", func(b *testing.B) { TrackMemoryUsage(b, "batch-check", func() { for i := 0; i < b.N; i++ { if err := state.BatchCheckTypes(checks); err != nil { b.Fatal("Type check failed:", err) } } }) }) } // BenchmarkBatchGlobalManager benchmarks the batch global manager func BenchmarkBatchGlobalManager(b *testing.B) { state := luajit.New() defer state.Close() setGlobals := map[string]string{ "VAR1": "value1", "VAR2": "value2", "VAR3": "value3", "VAR4": "value4", } getGlobals := []string{"VAR1", "VAR2", "VAR3", "VAR4"} b.Run("Individual", func(b *testing.B) { TrackMemoryUsage(b, "individual-global-mgmt", func() { for i := 0; i < b.N; i++ { // Set globals for k, v := range setGlobals { state.PushString(v) state.SetGlobal(k) } // Get globals results := make(map[string]any) for _, name := range getGlobals { state.GetGlobal(name) if val, err := state.ToValue(-1); err == nil { results[name] = val } state.Pop(1) } _ = results } }) }) b.Run("Batch", func(b *testing.B) { TrackMemoryUsage(b, "batch-global-mgmt", func() { for i := 0; i < b.N; i++ { mgr := state.NewBatchGlobalManager() for k, v := range setGlobals { mgr.QueueSet(k, v) } for _, name := range getGlobals { mgr.QueueGet(name) } results, _ := mgr.Execute() _ = results } }) }) }