package hbrt import ( "math" "strings" "testing" ) // Pre-register fast functions var ( ffToUpper = RegisterFastFunc("strings.ToUpper", strings.ToUpper) ffContains = RegisterFastFunc("strings.Contains", strings.Contains) ffReplaceAll = RegisterFastFunc("strings.ReplaceAll", strings.ReplaceAll) ffSqrt = RegisterFastFunc("math.Sqrt", math.Sqrt) ffCount = RegisterFastFunc("strings.Count", strings.Count) ) // =================================================================== // Benchmark: strings.ToUpper — string → string // =================================================================== func BenchmarkDirect_ToUpper(b *testing.B) { for i := 0; i < b.N; i++ { _ = strings.ToUpper("hello five world") } } func BenchmarkReflect_ToUpper(b *testing.B) { v := MakeString("hello five world") for i := 0; i < b.N; i++ { GoCallFunc(strings.ToUpper, v) } } func BenchmarkFastPath_ToUpper(b *testing.B) { v := MakeString("hello five world") for i := 0; i < b.N; i++ { GoCallFast(ffToUpper, v) } } // =================================================================== // Benchmark: strings.Contains — string, string → bool // =================================================================== func BenchmarkDirect_Contains(b *testing.B) { for i := 0; i < b.N; i++ { _ = strings.Contains("hello five world", "five") } } func BenchmarkReflect_Contains(b *testing.B) { v1 := MakeString("hello five world") v2 := MakeString("five") for i := 0; i < b.N; i++ { GoCallFunc(strings.Contains, v1, v2) } } func BenchmarkFastPath_Contains(b *testing.B) { v1 := MakeString("hello five world") v2 := MakeString("five") for i := 0; i < b.N; i++ { GoCallFast(ffContains, v1, v2) } } // =================================================================== // Benchmark: strings.ReplaceAll — string, string, string → string // =================================================================== func BenchmarkDirect_ReplaceAll(b *testing.B) { for i := 0; i < b.N; i++ { _ = strings.ReplaceAll("a-b-c-d-e", "-", "_") } } func BenchmarkReflect_ReplaceAll(b *testing.B) { v1 := MakeString("a-b-c-d-e") v2 := MakeString("-") v3 := MakeString("_") for i := 0; i < b.N; i++ { GoCallFunc(strings.ReplaceAll, v1, v2, v3) } } func BenchmarkFastPath_ReplaceAll(b *testing.B) { v1 := MakeString("a-b-c-d-e") v2 := MakeString("-") v3 := MakeString("_") for i := 0; i < b.N; i++ { GoCallFast(ffReplaceAll, v1, v2, v3) } } // =================================================================== // Benchmark: math.Sqrt — float64 → float64 // =================================================================== func BenchmarkDirect_Sqrt(b *testing.B) { for i := 0; i < b.N; i++ { _ = math.Sqrt(144.0) } } func BenchmarkReflect_Sqrt(b *testing.B) { v := MakeDouble(144.0, 0, 0) for i := 0; i < b.N; i++ { GoCallFunc(math.Sqrt, v) } } func BenchmarkFastPath_Sqrt(b *testing.B) { v := MakeDouble(144.0, 0, 0) for i := 0; i < b.N; i++ { GoCallFast(ffSqrt, v) } } // =================================================================== // Benchmark: Object method call // =================================================================== func BenchmarkReflect_MethodCall(b *testing.B) { obj := WrapGo(&testStruct{Name: "test", Value: 42}) arg := MakeInt(1) for i := 0; i < b.N; i++ { GoCall(obj, "Add", arg) } } func BenchmarkCached_MethodCall(b *testing.B) { obj := WrapGo(&testStruct{Name: "test", Value: 42}) arg := MakeInt(1) for i := 0; i < b.N; i++ { GoCallCached(obj, "Add", arg) } } // =================================================================== // Summary comparison // =================================================================== func TestBenchSummary(t *testing.T) { v := MakeString("hello five world") v2 := MakeString("five") // Warm up caches GoCallFast(ffToUpper, v) GoCallFast(ffContains, v, v2) n := 1000000 // Direct start := testing.Benchmark(func(b *testing.B) { for i := 0; i < b.N; i++ { _ = strings.ToUpper("hello five world") } }) // Reflect reflectBm := testing.Benchmark(func(b *testing.B) { for i := 0; i < b.N; i++ { GoCallFunc(strings.ToUpper, v) } }) // Fast fastBm := testing.Benchmark(func(b *testing.B) { for i := 0; i < b.N; i++ { GoCallFast(ffToUpper, v) } }) _ = n t.Logf("ToUpper comparison:") t.Logf(" Direct: %v/op", start.NsPerOp()) t.Logf(" Reflect: %v/op (%.1fx)", reflectBm.NsPerOp(), float64(reflectBm.NsPerOp())/float64(start.NsPerOp())) t.Logf(" Fast: %v/op (%.1fx)", fastBm.NsPerOp(), float64(fastBm.NsPerOp())/float64(start.NsPerOp())) t.Logf(" Speedup: reflect→fast = %.1fx", float64(reflectBm.NsPerOp())/float64(fastBm.NsPerOp())) }