perf(verify): parallelize smoke and ABI checks

Assisted-by: MiMo V2.5 Pro
This commit is contained in:
2026-08-21 01:20:31 +02:00
parent 94b98468bb
commit f5fcaf9fa6
+64 -16
View File
@@ -16,9 +16,11 @@ import (
"os"
"os/exec"
"path/filepath"
"runtime"
"sort"
"strconv"
"strings"
"sync"
"syscall"
"sourcedock.dev/petrbalvin/gasm-devkit/arch"
@@ -1221,6 +1223,7 @@ decoders) that crash on random input but should succeed on valid data.
}
fmt.Printf("fuzz: %d functions tested, %d iterations each\n", fuzzed, *fuzzN)
}
// Print function info and profile.
for _, name := range names {
fl, _ := k.Func(name)
flags := ""
@@ -1228,7 +1231,6 @@ decoders) that crash on random input but should succeed on valid data.
flags = " NOSPLIT"
}
fmt.Printf(" %s: %d bytes, args=%d, frame=%d%s\n", name, fl.Size, fl.Args, fl.Frame, flags)
if *profile {
blocks, err := k.Blocks(name)
if err != nil {
@@ -1237,40 +1239,86 @@ decoders) that crash on random input but should succeed on valid data.
fmt.Printf(" blocks: %d\n", len(blocks))
}
}
}
if *smoke && fl.NoSplit {
// Run smoke and ABI checks in parallel.
if *smoke || *abi {
type checkResult struct {
name string
msg string
fail bool
}
var mu sync.Mutex
var results []checkResult
sem := make(chan struct{}, runtime.NumCPU())
var wg sync.WaitGroup
for _, name := range names {
fl, _ := k.Func(name)
if !fl.NoSplit {
continue
}
wg.Add(1)
go func(name string, fl asm.FuncLayout) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
var msgs []string
failed := false
if *smoke {
args := make([]byte, fl.Args)
_, err := k.CallFunc(name, args)
if err != nil {
fmt.Printf(" smoke: FAIL — %v\n", err)
rc = 1
msgs = append(msgs, fmt.Sprintf(" smoke: FAIL — %v", err))
failed = true
} else {
fmt.Printf(" smoke: OK\n")
msgs = append(msgs, " smoke: OK")
}
}
if *abi && fl.NoSplit {
// Try varied-input ABI fuzzing first.
if *abi {
if src, err := readSource(path); err == nil {
result := k.FuzzFuncCheckedByName(name, src, *abiN, int64(*abiN))
if result.Mismatches > 0 {
fmt.Printf(" abi: %s\n", result)
rc = 1
msgs = append(msgs, fmt.Sprintf(" abi: %s", result))
failed = true
} else {
fmt.Printf(" abi: clean (%d varied inputs)\n", result.Matches)
msgs = append(msgs, fmt.Sprintf(" abi: clean (%d varied inputs)", result.Matches))
}
} else {
// Fallback: single zeroed-arg call.
args := make([]byte, fl.Args)
_, report, err := k.CallFuncChecked(name, args)
if err != nil {
fmt.Printf(" abi: FAIL — %v\n", err)
rc = 1
msgs = append(msgs, fmt.Sprintf(" abi: FAIL — %v", err))
failed = true
} else if !report.OK() {
fmt.Printf(" abi: %s\n", report)
rc = 1
msgs = append(msgs, fmt.Sprintf(" abi: %s", report))
failed = true
} else {
fmt.Printf(" abi: clean\n")
msgs = append(msgs, " abi: clean")
}
}
}
mu.Lock()
results = append(results, checkResult{name: name, msg: strings.Join(msgs, "\n"), fail: failed})
mu.Unlock()
}(name, fl)
}
wg.Wait()
// Print results in source order.
resultMap := make(map[string]checkResult, len(results))
for _, r := range results {
resultMap[r.name] = r
}
for _, name := range names {
if r, ok := resultMap[name]; ok {
fmt.Println(r.msg)
if r.fail {
rc = 1
}
}
}