- 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>
182 lines
4.6 KiB
Go
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()))
|
|
}
|