perf(verify): parallelize smoke and ABI checks
Assisted-by: MiMo V2.5 Pro
This commit is contained in:
+64
-16
@@ -16,9 +16,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"sourcedock.dev/petrbalvin/gasm-devkit/arch"
|
"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)
|
fmt.Printf("fuzz: %d functions tested, %d iterations each\n", fuzzed, *fuzzN)
|
||||||
}
|
}
|
||||||
|
// Print function info and profile.
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
fl, _ := k.Func(name)
|
fl, _ := k.Func(name)
|
||||||
flags := ""
|
flags := ""
|
||||||
@@ -1228,7 +1231,6 @@ decoders) that crash on random input but should succeed on valid data.
|
|||||||
flags = " NOSPLIT"
|
flags = " NOSPLIT"
|
||||||
}
|
}
|
||||||
fmt.Printf(" %s: %d bytes, args=%d, frame=%d%s\n", name, fl.Size, fl.Args, fl.Frame, flags)
|
fmt.Printf(" %s: %d bytes, args=%d, frame=%d%s\n", name, fl.Size, fl.Args, fl.Frame, flags)
|
||||||
|
|
||||||
if *profile {
|
if *profile {
|
||||||
blocks, err := k.Blocks(name)
|
blocks, err := k.Blocks(name)
|
||||||
if err != nil {
|
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))
|
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)
|
args := make([]byte, fl.Args)
|
||||||
_, err := k.CallFunc(name, args)
|
_, err := k.CallFunc(name, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf(" smoke: FAIL — %v\n", err)
|
msgs = append(msgs, fmt.Sprintf(" smoke: FAIL — %v", err))
|
||||||
rc = 1
|
failed = true
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf(" smoke: OK\n")
|
msgs = append(msgs, " smoke: OK")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if *abi && fl.NoSplit {
|
if *abi {
|
||||||
// Try varied-input ABI fuzzing first.
|
|
||||||
if src, err := readSource(path); err == nil {
|
if src, err := readSource(path); err == nil {
|
||||||
result := k.FuzzFuncCheckedByName(name, src, *abiN, int64(*abiN))
|
result := k.FuzzFuncCheckedByName(name, src, *abiN, int64(*abiN))
|
||||||
if result.Mismatches > 0 {
|
if result.Mismatches > 0 {
|
||||||
fmt.Printf(" abi: %s\n", result)
|
msgs = append(msgs, fmt.Sprintf(" abi: %s", result))
|
||||||
rc = 1
|
failed = true
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf(" abi: clean (%d varied inputs)\n", result.Matches)
|
msgs = append(msgs, fmt.Sprintf(" abi: clean (%d varied inputs)", result.Matches))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Fallback: single zeroed-arg call.
|
|
||||||
args := make([]byte, fl.Args)
|
args := make([]byte, fl.Args)
|
||||||
_, report, err := k.CallFuncChecked(name, args)
|
_, report, err := k.CallFuncChecked(name, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf(" abi: FAIL — %v\n", err)
|
msgs = append(msgs, fmt.Sprintf(" abi: FAIL — %v", err))
|
||||||
rc = 1
|
failed = true
|
||||||
} else if !report.OK() {
|
} else if !report.OK() {
|
||||||
fmt.Printf(" abi: %s\n", report)
|
msgs = append(msgs, fmt.Sprintf(" abi: %s", report))
|
||||||
rc = 1
|
failed = true
|
||||||
} else {
|
} 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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user