feat(audit): list every corpus failure per architecture
This commit is contained in:
+31
-11
@@ -38,7 +38,7 @@ import (
|
||||
// construction and are excluded from the diff; the other architectures list
|
||||
// their conditional branches outright.
|
||||
func cmdAuditInstructions(args []string) error {
|
||||
fs := newCommand("audit-instructions", "gasm audit-instructions [--corpus [dir]] [-I dir] [amd64|arm64|riscv64|loong64]", `
|
||||
fs := newCommand("audit-instructions", "gasm audit-instructions [--corpus [dir]] [--list] [-I dir] [amd64|arm64|riscv64|loong64]", `
|
||||
Compare the gasm encoder for the given architecture (default amd64) against
|
||||
go tool asm and print the diff: superset encodings (gasm-only, shippable via
|
||||
gasm asm --format goobj) and known-but-unencodable names (the backlog). The
|
||||
@@ -55,16 +55,19 @@ toolchain probing. A file whose name carries a recognisable _arch suffix is
|
||||
attempted for that architecture; a file without one is attempted for all
|
||||
four, exactly as a GOARCH build would compile it. The report gives the
|
||||
per-architecture pass rates and the most common failure reasons, which drive
|
||||
the encodability backlog by frequency rather than by table order.
|
||||
the encodability backlog by frequency rather than by table order. With
|
||||
-list the report also prints every failing file with its reason, per
|
||||
architecture.
|
||||
`)
|
||||
corpus := fs.Bool("corpus", false, "assemble a corpus of .s files and report pass rates and failure reasons")
|
||||
list := fs.Bool("list", false, "with --corpus, list every failing file with its reason, per architecture")
|
||||
var dirs includeDirs
|
||||
fs.Var(&dirs, "I", "directory to search for #include files (may be repeated)")
|
||||
if err := fs.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
if *corpus {
|
||||
return cmdAuditCorpus(fs.Args(), dirs)
|
||||
return cmdAuditCorpus(fs.Args(), dirs, *list)
|
||||
}
|
||||
archName := "amd64"
|
||||
switch n := len(fs.Args()); {
|
||||
@@ -403,20 +406,30 @@ type corpusTally struct {
|
||||
assembled int
|
||||
reasons map[string]int // failure reason → count
|
||||
example map[string]string // failure reason → one representative file
|
||||
fails []corpusFailure // every failure, in file order, for --list
|
||||
}
|
||||
|
||||
func (t *corpusTally) fail(path, reason string) {
|
||||
// corpusFailure is one failed attempt, recorded for the --list report.
|
||||
type corpusFailure struct {
|
||||
path string
|
||||
reason string
|
||||
detail string
|
||||
}
|
||||
|
||||
func (t *corpusTally) fail(path string, err error) {
|
||||
reason := corpusReason(err)
|
||||
t.reasons[reason]++
|
||||
if t.example[reason] == "" {
|
||||
t.example[reason] = path
|
||||
}
|
||||
t.fails = append(t.fails, corpusFailure{path: path, reason: reason, detail: firstLine(err.Error())})
|
||||
}
|
||||
|
||||
// cmdAuditCorpus implements audit-instructions --corpus. The include
|
||||
// directories carry #include resolution over a corpus whose files refer to
|
||||
// headers such as GOROOT/pkg/include, the same -I a toolchain comparison
|
||||
// needs.
|
||||
func cmdAuditCorpus(args []string, dirs includeDirs) error {
|
||||
func cmdAuditCorpus(args []string, dirs includeDirs, list bool) error {
|
||||
if len(args) > 1 {
|
||||
return &usageError{fmt.Errorf("audit-instructions --corpus takes at most one directory argument")}
|
||||
}
|
||||
@@ -454,7 +467,7 @@ func cmdAuditCorpus(args []string, dirs includeDirs) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
printCorpusStats(stats)
|
||||
printCorpusStats(stats, list)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -645,7 +658,7 @@ func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
hdrDir, err := hdr.dirFor(pkgDir, goos, goarchName(tg.a))
|
||||
if err != nil {
|
||||
ok = false
|
||||
t.fail(path, corpusReason(err))
|
||||
t.fail(path, err)
|
||||
continue
|
||||
}
|
||||
f, errs := parser.ParseWithOptions(path, src, parser.Options{
|
||||
@@ -654,12 +667,12 @@ func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
})
|
||||
if len(errs) > 0 {
|
||||
ok = false
|
||||
t.fail(path, corpusReason(errs[0]))
|
||||
t.fail(path, errs[0])
|
||||
continue
|
||||
}
|
||||
if _, err := assembleFile(tg.a, f); err != nil {
|
||||
ok = false
|
||||
t.fail(path, corpusReason(err))
|
||||
t.fail(path, err)
|
||||
continue
|
||||
}
|
||||
t.assembled++
|
||||
@@ -684,7 +697,7 @@ func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
}
|
||||
if err != nil {
|
||||
ok = false
|
||||
t.fail(path, corpusReason(err))
|
||||
t.fail(path, err)
|
||||
continue
|
||||
}
|
||||
t.assembled++
|
||||
@@ -706,7 +719,7 @@ func runCorpusAudit(root string, dirs includeDirs) (*corpusStats, error) {
|
||||
}
|
||||
|
||||
// printCorpusStats renders the corpus audit report.
|
||||
func printCorpusStats(s *corpusStats) {
|
||||
func printCorpusStats(s *corpusStats, list bool) {
|
||||
fmt.Printf("corpus %s: %d files (%d generic, attempted for all architectures; %d named for other Go ports, never attempted)\n", s.root, s.files, s.generic, s.otherPort)
|
||||
// The rate is over the files a supported build would attempt: the
|
||||
// other ports' files sit in the count for completeness but can never
|
||||
@@ -721,6 +734,13 @@ func printCorpusStats(s *corpusStats) {
|
||||
fmt.Printf(" %4d %s\n", t.reasons[r], r)
|
||||
fmt.Printf(" e.g. %s\n", t.example[r])
|
||||
}
|
||||
if !list {
|
||||
continue
|
||||
}
|
||||
for _, f := range t.fails {
|
||||
fmt.Printf(" FAIL %s\n", f.path)
|
||||
fmt.Printf(" %s: %s\n", f.reason, f.detail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user