more attempts at batching
This commit is contained in:
parent
3a4cb27473
commit
081fb0b7de
@ -470,3 +470,316 @@ func BenchmarkMultipleExecutions(b *testing.B) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -136,3 +136,637 @@ func BenchmarkLuaBytecodeExecution(b *testing.B) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkBatchTableOperations compares batch vs individual table operations
|
||||
func BenchmarkBatchTableOperations(b *testing.B) {
|
||||
testData := map[string]any{
|
||||
"name": "testapp",
|
||||
"version": "1.0.0",
|
||||
"port": 8080,
|
||||
"debug": true,
|
||||
"timeout": 30.5,
|
||||
"tags": []string{"web", "api", "service"},
|
||||
"limits": []int{100, 200, 300, 400, 500},
|
||||
}
|
||||
|
||||
b.Run("Individual", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
defer L.Cleanup()
|
||||
|
||||
TrackMemoryUsage(b, "table-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
tb := L.NewTableBuilder()
|
||||
for k, v := range testData {
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
tb.SetString(k, val)
|
||||
case int:
|
||||
tb.SetNumber(k, float64(val))
|
||||
case bool:
|
||||
tb.SetBool(k, val)
|
||||
case float64:
|
||||
tb.SetNumber(k, val)
|
||||
default:
|
||||
tb.SetTable(k, v)
|
||||
}
|
||||
}
|
||||
tb.Build()
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Batch", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
defer L.Cleanup()
|
||||
|
||||
TrackMemoryUsage(b, "table-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
tb := L.NewTableBuilder()
|
||||
tb.BatchBuild(testData)
|
||||
tb.Build()
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("BatchTableBuilder", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
defer L.Cleanup()
|
||||
|
||||
TrackMemoryUsage(b, "table-batch-builder", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
btb := L.NewBatchTableBuilder()
|
||||
for k, v := range testData {
|
||||
switch val := v.(type) {
|
||||
case string:
|
||||
btb.SetString(k, val)
|
||||
case int:
|
||||
btb.SetNumber(k, float64(val))
|
||||
case bool:
|
||||
btb.SetBool(k, val)
|
||||
case float64:
|
||||
btb.SetNumber(k, val)
|
||||
default:
|
||||
btb.SetTable(k, v)
|
||||
}
|
||||
}
|
||||
btb.Build()
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkBatchArrayOperations compares different array creation methods
|
||||
func BenchmarkBatchArrayOperations(b *testing.B) {
|
||||
intArray := make([]int, 50)
|
||||
stringArray := make([]string, 50)
|
||||
floatArray := make([]float64, 50)
|
||||
boolArray := make([]bool, 50)
|
||||
|
||||
for i := range 50 {
|
||||
intArray[i] = i * 2
|
||||
stringArray[i] = "item" + string(rune('0'+i%10))
|
||||
floatArray[i] = float64(i) * 1.5
|
||||
boolArray[i] = i%2 == 0
|
||||
}
|
||||
|
||||
b.Run("IntArray_Individual", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "int-array-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.PushValue(intArray)
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("IntArray_Batch", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "int-array-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.BatchPushIntArray(intArray)
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("StringArray_Individual", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "string-array-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.PushValue(stringArray)
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("StringArray_Batch", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "string-array-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.BatchPushStringArray(stringArray)
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("FloatArray_Individual", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "float-array-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.PushValue(floatArray)
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("FloatArray_Batch", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "float-array-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.BatchPushFloatArray(floatArray)
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("BoolArray_Individual", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "bool-array-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.PushValue(boolArray)
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("BoolArray_Batch", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "bool-array-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.BatchPushBoolArray(boolArray)
|
||||
L.Pop(1)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkBatchGlobalOperations compares global variable operations
|
||||
func BenchmarkBatchGlobalOperations(b *testing.B) {
|
||||
globals := map[string]string{
|
||||
"APP_NAME": "myapp",
|
||||
"APP_VERSION": "1.0.0",
|
||||
"APP_ENV": "production",
|
||||
"DB_HOST": "localhost",
|
||||
"DB_PORT": "5432",
|
||||
"DB_NAME": "mydb",
|
||||
"CACHE_TTL": "300",
|
||||
"LOG_LEVEL": "info",
|
||||
}
|
||||
|
||||
b.Run("Individual_Set", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "globals-individual-set", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for k, v := range globals {
|
||||
L.PushString(v)
|
||||
L.SetGlobal(k)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Batch_Set", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "globals-batch-set", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.BatchSetGlobals(globals)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Setup globals for read tests
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
L.BatchSetGlobals(globals)
|
||||
|
||||
globalNames := make([]string, 0, len(globals))
|
||||
for k := range globals {
|
||||
globalNames = append(globalNames, k)
|
||||
}
|
||||
|
||||
b.Run("Individual_Get", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "globals-individual-get", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
values := make(map[string]any)
|
||||
for _, name := range globalNames {
|
||||
L.GetGlobal(name)
|
||||
if val, err := L.ToValue(-1); err == nil {
|
||||
values[name] = val
|
||||
}
|
||||
L.Pop(1)
|
||||
}
|
||||
_ = values
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Batch_Get", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "globals-batch-get", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
startTop := L.GetTop()
|
||||
L.BatchGetGlobals(globalNames)
|
||||
values := make(map[string]any, len(globalNames))
|
||||
for j, name := range globalNames {
|
||||
if val, err := L.ToValue(startTop + j + 1); err == nil {
|
||||
values[name] = val
|
||||
}
|
||||
}
|
||||
L.SetTop(startTop)
|
||||
_ = values
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkBatchTableReading compares table field reading methods
|
||||
func BenchmarkBatchTableReading(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
// Create a complex nested table structure
|
||||
setupCode := `
|
||||
config = {
|
||||
database = {
|
||||
host = "localhost",
|
||||
port = 5432,
|
||||
name = "myapp",
|
||||
timeout = 30,
|
||||
ssl = true,
|
||||
pool = {min = 5, max = 20}
|
||||
},
|
||||
server = {
|
||||
host = "0.0.0.0",
|
||||
port = 8080,
|
||||
workers = 4,
|
||||
timeout = 60,
|
||||
ssl = false,
|
||||
middleware = {"cors", "auth", "logging"}
|
||||
},
|
||||
cache = {
|
||||
enabled = true,
|
||||
ttl = 300,
|
||||
size = 1000,
|
||||
backend = "redis",
|
||||
cluster = false
|
||||
},
|
||||
logging = {
|
||||
level = "info",
|
||||
file = "/var/log/app.log",
|
||||
rotate = true,
|
||||
max_size = 100,
|
||||
format = "json"
|
||||
}
|
||||
}
|
||||
`
|
||||
if err := L.DoString(setupCode); err != nil {
|
||||
b.Fatalf("Setup failed: %v", err)
|
||||
}
|
||||
|
||||
topLevelKeys := []string{"database", "server", "cache", "logging"}
|
||||
dbKeys := []string{"host", "port", "name", "timeout", "ssl"}
|
||||
|
||||
b.Run("Individual_TopLevel", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "table-read-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("config")
|
||||
values := make(map[string]any)
|
||||
for _, key := range topLevelKeys {
|
||||
L.GetField(-1, key)
|
||||
if val, err := L.ToValue(-1); err == nil {
|
||||
values[key] = val
|
||||
}
|
||||
L.Pop(1)
|
||||
}
|
||||
L.Pop(1)
|
||||
_ = values
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Batch_TopLevel", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "table-read-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("config")
|
||||
reader := L.NewBatchTableReader(-1)
|
||||
values, _ := reader.ReadFields(topLevelKeys)
|
||||
L.Pop(1)
|
||||
_ = values
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Individual_Nested", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "nested-read-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("config")
|
||||
L.GetField(-1, "database")
|
||||
values := make(map[string]any)
|
||||
for _, key := range dbKeys {
|
||||
L.GetField(-1, key)
|
||||
if val, err := L.ToValue(-1); err == nil {
|
||||
values[key] = val
|
||||
}
|
||||
L.Pop(1)
|
||||
}
|
||||
L.Pop(2)
|
||||
_ = values
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Batch_Nested", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "nested-read-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("config")
|
||||
L.GetField(-1, "database")
|
||||
reader := L.NewBatchTableReader(-1)
|
||||
values, _ := reader.ReadFields(dbKeys)
|
||||
L.Pop(2)
|
||||
_ = values
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkBatchValuePushing compares value pushing methods
|
||||
func BenchmarkBatchValuePushing(b *testing.B) {
|
||||
mixedValues := []any{
|
||||
"string1", 42, true, 3.14,
|
||||
"string2", 100, false, 2.718,
|
||||
"string3", 256, true, 1.414,
|
||||
"string4", 500, false, 0.577,
|
||||
}
|
||||
|
||||
stringValues := []any{"hello", "world", "test", "bench", "mark", "go", "lua", "jit"}
|
||||
numberValues := []any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
||||
|
||||
b.Run("Mixed_Individual", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "mixed-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, v := range mixedValues {
|
||||
L.PushValue(v)
|
||||
}
|
||||
L.Pop(len(mixedValues))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Mixed_Batch", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "mixed-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
pusher := L.NewBatchValuePusher()
|
||||
for _, v := range mixedValues {
|
||||
pusher.Add(v)
|
||||
}
|
||||
pusher.Push()
|
||||
L.Pop(len(mixedValues))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Strings_Individual", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "strings-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, v := range stringValues {
|
||||
L.PushValue(v)
|
||||
}
|
||||
L.Pop(len(stringValues))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Strings_Batch", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "strings-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
pusher := L.NewBatchValuePusher()
|
||||
for _, v := range stringValues {
|
||||
pusher.Add(v)
|
||||
}
|
||||
pusher.Push()
|
||||
L.Pop(len(stringValues))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Numbers_Individual", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "numbers-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, v := range numberValues {
|
||||
L.PushValue(v)
|
||||
}
|
||||
L.Pop(len(numberValues))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("Numbers_Batch", func(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
TrackMemoryUsage(b, "numbers-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
pusher := L.NewBatchValuePusher()
|
||||
for _, v := range numberValues {
|
||||
pusher.Add(v)
|
||||
}
|
||||
pusher.Push()
|
||||
L.Pop(len(numberValues))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// BenchmarkBatchExtraction compares array extraction methods
|
||||
func BenchmarkBatchExtraction(b *testing.B) {
|
||||
L := luajit.New()
|
||||
defer L.Close()
|
||||
|
||||
// Create test arrays in Lua
|
||||
setupCode := `
|
||||
int_array = {}
|
||||
for i = 1, 100 do
|
||||
int_array[i] = i * 2
|
||||
end
|
||||
|
||||
float_array = {}
|
||||
for i = 1, 100 do
|
||||
float_array[i] = i * 1.5
|
||||
end
|
||||
|
||||
string_array = {}
|
||||
for i = 1, 100 do
|
||||
string_array[i] = "item" .. i
|
||||
end
|
||||
|
||||
bool_array = {}
|
||||
for i = 1, 100 do
|
||||
bool_array[i] = (i % 2 == 0)
|
||||
end
|
||||
`
|
||||
if err := L.DoString(setupCode); err != nil {
|
||||
b.Fatalf("Setup failed: %v", err)
|
||||
}
|
||||
|
||||
b.Run("IntArray_Individual", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "int-extract-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("int_array")
|
||||
result := make([]int, 100)
|
||||
for j := 1; j <= 100; j++ {
|
||||
L.PushNumber(float64(j))
|
||||
L.GetTable(-2)
|
||||
result[j-1] = int(L.ToNumber(-1))
|
||||
L.Pop(1)
|
||||
}
|
||||
L.Pop(1)
|
||||
_ = result
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("IntArray_Batch", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "int-extract-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("int_array")
|
||||
result, _ := L.BatchExtractIntArray(-1, 100)
|
||||
L.Pop(1)
|
||||
_ = result
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("FloatArray_Individual", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "float-extract-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("float_array")
|
||||
result := make([]float64, 100)
|
||||
for j := 1; j <= 100; j++ {
|
||||
L.PushNumber(float64(j))
|
||||
L.GetTable(-2)
|
||||
result[j-1] = L.ToNumber(-1)
|
||||
L.Pop(1)
|
||||
}
|
||||
L.Pop(1)
|
||||
_ = result
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("FloatArray_Batch", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "float-extract-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("float_array")
|
||||
result, _ := L.BatchExtractFloatArray(-1, 100)
|
||||
L.Pop(1)
|
||||
_ = result
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("StringArray_Individual", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "string-extract-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("string_array")
|
||||
result := make([]string, 100)
|
||||
for j := 1; j <= 100; j++ {
|
||||
L.PushNumber(float64(j))
|
||||
L.GetTable(-2)
|
||||
result[j-1] = L.ToString(-1)
|
||||
L.Pop(1)
|
||||
}
|
||||
L.Pop(1)
|
||||
_ = result
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("StringArray_Batch", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "string-extract-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("string_array")
|
||||
result, _ := L.BatchExtractStringArray(-1, 100)
|
||||
L.Pop(1)
|
||||
_ = result
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("BoolArray_Individual", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "bool-extract-individual", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("bool_array")
|
||||
result := make([]bool, 100)
|
||||
for j := 1; j <= 100; j++ {
|
||||
L.PushNumber(float64(j))
|
||||
L.GetTable(-2)
|
||||
result[j-1] = L.ToBoolean(-1)
|
||||
L.Pop(1)
|
||||
}
|
||||
L.Pop(1)
|
||||
_ = result
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
b.Run("BoolArray_Batch", func(b *testing.B) {
|
||||
TrackMemoryUsage(b, "bool-extract-batch", func() {
|
||||
for i := 0; i < b.N; i++ {
|
||||
L.GetGlobal("bool_array")
|
||||
result, _ := L.BatchExtractBoolArray(-1, 100)
|
||||
L.Pop(1)
|
||||
_ = result
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
27
bench/snapshot.txt
Normal file
27
bench/snapshot.txt
Normal file
@ -0,0 +1,27 @@
|
||||
cpu: AMD Ryzen 7 8845HS w/ Radeon 780M Graphics
|
||||
BenchmarkSimpleDoString-16 3050360 384.6 ns/op 0 dostring-bytes/op 0 dostring-mallocs
|
||||
BenchmarkSimpleCompileAndRun-16 3016736 386.8 ns/op 0 compile-run-bytes/op 0 compile-run-mallocs
|
||||
BenchmarkSimpleCompileLoadRun-16 1264791 933.1 ns/op 72.00 compile-load-run-bytes/op 2529585 compile-load-run-mallocs
|
||||
BenchmarkSimplePrecompiledBytecode-16 6726292 185.7 ns/op 0 precompiled-bytes/op 0 precompiled-mallocs
|
||||
BenchmarkFunctionCallDoString-16 2349952 518.0 ns/op 0 func-dostring-bytes/op 0 func-dostring-mallocs
|
||||
BenchmarkFunctionCallPrecompiled-16 6023224 207.9 ns/op 0 func-precompiled-bytes/op 0 func-precompiled-mallocs
|
||||
BenchmarkLoopDoString-16 149439 7880 ns/op 0 loop-dostring-bytes/op 0 loop-dostring-mallocs
|
||||
BenchmarkLoopPrecompiled-16 166184 6926 ns/op 0 loop-precompiled-bytes/op 0 loop-precompiled-mallocs
|
||||
BenchmarkTableOperationsDoString-16 66718 17634 ns/op 0 table-dostring-bytes/op 0 table-dostring-mallocs
|
||||
BenchmarkTableOperationsPrecompiled-16 74943 15629 ns/op 0 table-precompiled-bytes/op 0 table-precompiled-mallocs
|
||||
BenchmarkGoFunctionCall-16 2407584 475.5 ns/op 0.001120 go-func-call-bytes/op 8.000 go-func-call-mallocs
|
||||
BenchmarkComplexScript-16 37376 32377 ns/op 8.000 complex-script-bytes/op 37376 complex-script-mallocs
|
||||
BenchmarkComplexScriptPrecompiled-16 50720 23908 ns/op 0 complex-precompiled-bytes/op 0 complex-precompiled-mallocs
|
||||
BenchmarkMultipleExecutions-16 4314085 273.9 ns/op 0 multiple-executions-bytes/op 0 multiple-executions-mallocs
|
||||
BenchmarkLuaDirectExecution/SimpleAddition-16 2614246 451.6 ns/op 0 direct-SimpleAddition-bytes/op 0 direct-SimpleAddition-mallocs
|
||||
BenchmarkLuaDirectExecution/LoopSum-16 144027 8119 ns/op 0 direct-LoopSum-bytes/op 0 direct-LoopSum-mallocs
|
||||
BenchmarkLuaDirectExecution/FunctionCall-16 159513 7507 ns/op 0 direct-FunctionCall-bytes/op 0 direct-FunctionCall-mallocs
|
||||
BenchmarkLuaDirectExecution/TableCreation-16 134306 9002 ns/op 0 direct-TableCreation-bytes/op 0 direct-TableCreation-mallocs
|
||||
BenchmarkLuaDirectExecution/StringOperations-16 405411 2730 ns/op 0 direct-StringOperations-bytes/op 0 direct-StringOperations-mallocs
|
||||
BenchmarkLuaBytecodeExecution/SimpleAddition-16 6323188 186.6 ns/op 219.73 MB/s 0 bytecode-SimpleAddition-bytes/op 0 bytecode-SimpleAddition-mallocs
|
||||
BenchmarkLuaBytecodeExecution/LoopSum-16 162441 7137 ns/op 29.98 MB/s 0 bytecode-LoopSum-bytes/op 0 bytecode-LoopSum-mallocs
|
||||
BenchmarkLuaBytecodeExecution/FunctionCall-16 175790 6386 ns/op 35.70 MB/s 0 bytecode-FunctionCall-bytes/op 0 bytecode-FunctionCall-mallocs
|
||||
BenchmarkLuaBytecodeExecution/TableCreation-16 152374 7534 ns/op 29.47 MB/s 0 bytecode-TableCreation-bytes/op 0 bytecode-TableCreation-mallocs
|
||||
BenchmarkLuaBytecodeExecution/StringOperations-16 705818 1548 ns/op 158.23 MB/s 0 bytecode-StringOperations-bytes/op 0 bytecode-StringOperations-mallocs
|
||||
PASS
|
||||
ok git.sharkk.net/Sky/LuaJIT-to-Go/bench 33.958s
|
Loading…
x
Reference in New Issue
Block a user