Files
five/hbrt/gobridge_bench_test.go
Charles KWON OhJun 59568f3301 Five v0.9 — Harbour + Go fusion language
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:41:50 +09:00

182 lines
4.6 KiB
Go

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()))
}