| // Copyright 2026 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "bytes" |
| "fmt" |
| "strings" |
| ) |
| |
| func (m *metrics) report(w *bytes.Buffer) { |
| fmt.Fprintf(w, "SIMD spec transition progress\n\n") |
| fmt.Fprintf(w, "Generated by archsimd/_gen/cmd/specstats; do not edit.\n") |
| fmt.Fprintf(w, "Regenerate with: go run ./cmd/specstats -w\n\n") |
| fmt.Fprintf(w, "Every fraction heads for 100%%; every count heads for zero. Bracketed\n") |
| fmt.Fprintf(w, "names are SPEC-TRANSITION.md tasks that move the figure. Indented,\n") |
| fmt.Fprintf(w, "untagged numbers are context breaking down the figure above them.\n") |
| fmt.Fprintf(w, "String and Len are excluded throughout (§2.7).\n") |
| |
| m.summary(w) |
| m.coverage(w) |
| m.signatures(w) |
| m.documentation(w) |
| m.retirement(w) |
| m.disagreement(w) |
| } |
| |
| func (m *metrics) summary(w *bytes.Buffer) { |
| section(w, "Summary", "") |
| |
| note(w, "Heading for 100%:") |
| frac(w, "spec coverage, by (receiver, name) (§1)", m.covPair.result(), "spec-common, spec-all") |
| frac(w, "docs sourced from spec (§3)", m.fromSpec.result(), "gen-docs, comments-yaml, handwritten-fill, template-docs") |
| |
| note(w, "\nHeading for zero:") |
| count(w, "type mismatches with spec (§2)", m.typeOK.result().miss(), "fill-enforce") |
| count(w, "type divergence across targets (§2)", m.typeSame.result().miss(), "fill-enforce") |
| count(w, "spec coverage gaps in defined names (§5)", m.apiOnly, "spec-all, convert-lo, mask-bits") |
| count(w, "hand-written doc conflicts with spec (§3)", m.handConflict, "doc-triage") |
| count(w, "simd mirror drift (§3)", m.mirror.result().miss(), "comments-yaml") |
| count(w, "categories.yaml entries (§4)", m.catEntries, "cat-rehome, compiler-ops-impl, cat-delete") |
| count(w, "midway/comments.yaml entries spec covers (§4)", m.commentsSpecCovered, "comments-yaml, spec-all") |
| } |
| |
| func (m *metrics) coverage(w *bytes.Buffer) { |
| section(w, "1. Spec coverage of API", "spec-common, spec-all") |
| |
| frac(w, "by (target, receiver, name)", m.covTriple.result(), "") |
| frac(w, "by (receiver, name)", m.covPair.result(), "") |
| frac(w, "by name", m.covName.result(), "") |
| |
| note(w, "\nBy build configuration:") |
| for _, bc := range buildConfigs { |
| frac(w, " "+bc.name, m.covTarget.result(bc.name), "") |
| } |
| |
| note(w, "\nBy generator (declarations per tool, counted once per tool per pair):") |
| for _, g := range m.covGen.dims() { |
| if strings.Contains(g, "/") { |
| continue |
| } |
| frac(w, " "+g, m.covGen.result(g), "") |
| } |
| |
| note(w, "\nHigh-drift-risk names (emitted by >1 generator):") |
| frac(w, " covered", m.covMulti.result(), "spec-all") |
| frac(w, " portable core (comments.yaml .common_methods)", m.covCommon.result(), "spec-common") |
| |
| fmt.Fprintf(w, "\n") |
| kv(w, "spec operations written so far", len(m.ops)) |
| kv(w, " expanding to distinct names", m.specNames) |
| kv(w, " expanding to (receiver, name) pairs", m.specPairs) |
| } |
| |
| func (m *metrics) signatures(w *bytes.Buffer) { |
| section(w, "2. Signatures and names", "named-results, fill-enforce") |
| |
| note(w, `Spec/API disagreement, for declarations spec covers. As in specdoc.Fill, |
| a named argument whose name differs from spec's is a mismatch; an unnamed |
| one (or _) is not, and is counted below as a name Fill fills in instead:`) |
| count(w, " type mismatches", m.typeOK.result().miss(), "fill-enforce") |
| count(w, " parameter-name mismatches", m.paramNameOK.result().miss(), "named-results") |
| count(w, " result-name mismatches", m.resultNameOK.result().miss(), "named-results") |
| |
| note(w, "\nNames spec gives that the API leaves unnamed, for declarations spec covers:") |
| count(w, " declarations with unnamed parameters", m.paramsFilled.result().miss(), "named-results") |
| count(w, " declarations with unnamed results", m.resultsFilled.result().miss(), "named-results") |
| |
| note(w, ` |
| API consistency across targets (the "one meaning" invariant), for |
| (receiver, name) pairs declared for more than one target. An unnamed |
| argument agrees with any name:`) |
| count(w, " divergent parameter or result types", m.typeSame.result().miss(), "fill-enforce") |
| count(w, " divergent parameter names", m.paramNameSame.result().miss(), "fill-enforce, spec-all") |
| count(w, " divergent result names", m.resultNameSame.result().miss(), "named-results") |
| } |
| |
| func (m *metrics) documentation(w *bytes.Buffer) { |
| section(w, "3. Documentation", "gen-docs, comments-yaml, handwritten-fill, template-docs") |
| note(w, `A declaration counts as sourced from spec when its doc comment begins with |
| spec's text (a prefix test, because Fill leaves generator notes below).`) |
| |
| frac(w, "covered declarations whose doc comes from spec", m.fromSpec.result(), "gen-docs, comments-yaml, handwritten-fill, template-docs") |
| fmt.Fprintf(w, "\n") |
| frac(w, "simd ∩ archsimd methods with matching docs", m.crossPkg.result(), "gen-docs, comments-yaml") |
| fmt.Fprintf(w, "\n") |
| count(w, "hand-written doc conflicts with spec", m.handConflict, "doc-triage") |
| for _, fc := range m.handConflictByFile { |
| count(w, " "+fc.file, fc.n, "doc-triage") |
| } |
| count(w, "drifted docs in simd mirror (stubs vs emulated)", m.mirror.result().miss(), "comments-yaml") |
| kv(w, " mirrored declarations", m.mirror.result().d) |
| } |
| |
| func (m *metrics) retirement(w *bytes.Buffer) { |
| section(w, "4. Retiring the old inputs", "comments-yaml, cat-rehome, compiler-ops-impl, cat-delete") |
| note(w, `categories.yaml's exported entries are emptied field by field: template-docs |
| removes documentation, cat-rehome removes the rest, sig-from-spec removes |
| commutative, and cat-delete removes the file. Compiler-only entries are |
| handled wholesale by compiler-ops-impl.`) |
| |
| count(w, "categories.yaml entries", m.catEntries, "cat-rehome, compiler-ops-impl, cat-delete") |
| sub(w, "unique operation names", m.catUniq) |
| sub(w, " exported", m.catExported) |
| count(w, "compiler-only categories.yaml entries", m.catCompilerOnly, "compiler-ops-impl") |
| fmt.Fprintf(w, "\n exported entries, by field:\n") |
| for _, k := range sortedKeys(m.catExportedFields) { |
| if k != "go" { |
| tag := "cat-rehome" |
| if k == "commutative" { |
| tag = "sig-from-spec" |
| } |
| countIndented(w, k, m.catExportedFields[k], tag) |
| } |
| } |
| fmt.Fprintf(w, "\n") |
| count(w, "midway/comments.yaml entries spec covers", m.commentsSpecCovered, "comments-yaml, spec-all") |
| fmt.Fprintf(w, "\n") |
| count(w, "commutativity disagreements, spec vs categories.yaml", m.commutDrift, "spec-all") |
| } |
| |
| func (m *metrics) disagreement(w *bytes.Buffer) { |
| section(w, "5. Spec/API coverage disagreement detail", "spec-all, convert-lo, mask-bits") |
| note(w, `Where both sides define a name, receivers only the API declares are spec |
| bugs (a constraint is wrong or a sibling function is missing). Receivers |
| only spec generates are a review queue -- spec is deliberately maximal.`) |
| |
| count(w, "spec misses receivers of a name it defines", m.apiOnly, "spec-all, convert-lo, mask-bits") |
| count(w, " declarations affected, counting each target", m.apiOnlyDecls, "spec-all, convert-lo, mask-bits") |
| count(w, "spec operations implemented nowhere", len(m.specOnly), "spec-all") |
| emptyList(w, len(m.specOnly)) |
| for _, n := range m.specOnly { |
| fmt.Fprintf(w, " %s\n", n) |
| } |
| |
| fmt.Fprintf(w, "\nEvery name either side defines, less the %d spec has never defined at all\n", |
| m.rel[relAPIOnly].names) |
| fmt.Fprintf(w, "(%d receivers, counted as coverage in §1 rather than disagreement):\n\n", |
| m.rel[relAPIOnly].apiOnly) |
| fmt.Fprintf(w, " %-14s %7s %14s %14s\n", "relation", "names", "Σ|api - spec|", "Σ|spec - api|") |
| fmt.Fprintf(w, " %-14s %7s %14s %14s\n", "", "", "(-> 0)", "(review)") |
| var total relTotal |
| for r := relEqual; r <= relSpecOnly; r++ { |
| t := m.rel[r] |
| fmt.Fprintf(w, " %-14s %7d %14d %14d\n", relationName[r], t.names, t.apiOnly, t.specOnly) |
| total.names, total.apiOnly, total.specOnly = total.names+t.names, total.apiOnly+t.apiOnly, total.specOnly+t.specOnly |
| } |
| fmt.Fprintf(w, " %-14s %7d %14d %14d\n", "total", total.names, total.apiOnly, total.specOnly) |
| |
| note(w, "\nNames that disagree, with api - spec receivers (the defects):") |
| fmt.Fprintf(w, " %-26s %-11s %5s %6s %12s %12s\n", |
| "name", "relation", "|api|", "|spec|", "|api - spec|", "|spec - api|") |
| n := 0 |
| for _, r := range m.names { |
| if r.rel == relEqual || r.rel == relAPIOnly { |
| continue |
| } |
| n++ |
| fmt.Fprintf(w, " %-26s %-11s %5d %6d %12d %12d\n", |
| r.name, relationName[r.rel], r.api, r.spec, len(r.apiOnly), r.specOnly) |
| wrap(w, " ", "api - spec = ", r.apiOnly) |
| } |
| emptyList(w, n) |
| } |