Source file src/simd/archsimd/_gen/cmd/specstats/report.go

     1  // Copyright 2026 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"strings"
    11  )
    12  
    13  func (m *metrics) report(w *bytes.Buffer) {
    14  	fmt.Fprintf(w, "SIMD spec transition progress\n\n")
    15  	fmt.Fprintf(w, "Generated by archsimd/_gen/cmd/specstats; do not edit.\n")
    16  	fmt.Fprintf(w, "Regenerate with: go run ./cmd/specstats -w\n\n")
    17  	fmt.Fprintf(w, "Every fraction heads for 100%%; every count heads for zero. Bracketed\n")
    18  	fmt.Fprintf(w, "names are SPEC-TRANSITION.md tasks that move the figure. Indented,\n")
    19  	fmt.Fprintf(w, "untagged numbers are context breaking down the figure above them.\n")
    20  	fmt.Fprintf(w, "String, Len, ToArch, and FromArch are excluded throughout (§2.7).\n")
    21  
    22  	m.summary(w)
    23  	m.coverage(w)
    24  	m.signatures(w)
    25  	m.documentation(w)
    26  	m.retirement(w)
    27  	m.disagreement(w)
    28  }
    29  
    30  func (m *metrics) summary(w *bytes.Buffer) {
    31  	section(w, "Summary", "")
    32  
    33  	note(w, "Heading for 100%:")
    34  	frac(w, "spec coverage, by (receiver, name) (§1)", m.covPair.result(), "spec-common, spec-all")
    35  	frac(w, "docs sourced from spec (§3)", m.fromSpec.result(), "gen-docs, comments-yaml, handwritten-fill, template-docs")
    36  
    37  	note(w, "\nHeading for zero:")
    38  	count(w, "type mismatches with spec (§2)", m.typeOK.result().miss(), "fill-enforce")
    39  	count(w, "type divergence across targets (§2)", m.typeSame.result().miss(), "fill-enforce")
    40  	count(w, "spec coverage gaps in defined names (§5)", m.apiOnly, "spec-all, convert-lo, mask-bits")
    41  	count(w, "hand-written doc conflicts with spec (§3)", m.handConflict, "doc-triage")
    42  	count(w, "simd mirror drift (§3)", m.mirror.result().miss(), "comments-yaml")
    43  	count(w, "categories.yaml entries (§4)", m.catEntries, "cat-rehome, compiler-ops-impl, cat-delete")
    44  	count(w, "midway/comments.yaml entries spec covers (§4)", m.commentsSpecCovered, "comments-yaml, spec-all")
    45  }
    46  
    47  func (m *metrics) coverage(w *bytes.Buffer) {
    48  	section(w, "1. Spec coverage of API", "spec-common, spec-all")
    49  
    50  	frac(w, "by (target, receiver, name)", m.covTriple.result(), "")
    51  	frac(w, "by (receiver, name)", m.covPair.result(), "")
    52  	frac(w, "by name", m.covName.result(), "")
    53  
    54  	note(w, "\nBy build configuration:")
    55  	for _, bc := range buildConfigs {
    56  		frac(w, "  "+bc.name, m.covTarget.result(bc.name), "")
    57  	}
    58  
    59  	note(w, "\nBy generator (declarations per tool, counted once per tool per pair):")
    60  	for _, g := range m.covGen.dims() {
    61  		if strings.Contains(g, "/") {
    62  			continue
    63  		}
    64  		frac(w, "  "+g, m.covGen.result(g), "")
    65  	}
    66  
    67  	note(w, "\nHigh-drift-risk names (emitted by >1 generator):")
    68  	frac(w, "  covered", m.covMulti.result(), "spec-all")
    69  	frac(w, "  portable core (comments.yaml .common_methods)", m.covCommon.result(), "spec-common")
    70  
    71  	fmt.Fprintf(w, "\n")
    72  	kv(w, "spec operations written so far", len(m.ops))
    73  	kv(w, "  expanding to distinct names", m.specNames)
    74  	kv(w, "  expanding to (receiver, name) pairs", m.specPairs)
    75  }
    76  
    77  func (m *metrics) signatures(w *bytes.Buffer) {
    78  	section(w, "2. Signatures and names", "named-results, fill-enforce")
    79  
    80  	note(w, `Spec/API disagreement, for declarations spec covers. As in specdoc.Fill,
    81  a named argument whose name differs from spec's is a mismatch; an unnamed
    82  one (or _) is not, and is counted below as a name Fill fills in instead:`)
    83  	count(w, "  type mismatches", m.typeOK.result().miss(), "fill-enforce")
    84  	count(w, "  parameter-name mismatches", m.paramNameOK.result().miss(), "named-results")
    85  	count(w, "  result-name mismatches", m.resultNameOK.result().miss(), "named-results")
    86  
    87  	note(w, "\nNames spec gives that the API leaves unnamed, for declarations spec covers:")
    88  	count(w, "  declarations with unnamed parameters", m.paramsFilled.result().miss(), "named-results")
    89  	count(w, "  declarations with unnamed results", m.resultsFilled.result().miss(), "named-results")
    90  
    91  	note(w, `
    92  API consistency across targets (the "one meaning" invariant), for
    93  (receiver, name) pairs declared for more than one target. An unnamed
    94  argument agrees with any name:`)
    95  	count(w, "  divergent parameter or result types", m.typeSame.result().miss(), "fill-enforce")
    96  	count(w, "  divergent parameter names", m.paramNameSame.result().miss(), "fill-enforce, spec-all")
    97  	count(w, "  divergent result names", m.resultNameSame.result().miss(), "named-results")
    98  }
    99  
   100  func (m *metrics) documentation(w *bytes.Buffer) {
   101  	section(w, "3. Documentation", "gen-docs, comments-yaml, handwritten-fill, template-docs")
   102  	note(w, `A declaration counts as sourced from spec when its doc comment begins with
   103  spec's text (a prefix test, because Fill leaves generator notes below).`)
   104  
   105  	frac(w, "covered declarations whose doc comes from spec", m.fromSpec.result(), "gen-docs, comments-yaml, handwritten-fill, template-docs")
   106  	fmt.Fprintf(w, "\n")
   107  	frac(w, "simd ∩ archsimd methods with matching docs", m.crossPkg.result(), "gen-docs, comments-yaml")
   108  	fmt.Fprintf(w, "\n")
   109  	count(w, "hand-written doc conflicts with spec", m.handConflict, "doc-triage")
   110  	for _, fc := range m.handConflictByFile {
   111  		count(w, "    "+fc.file, fc.n, "doc-triage")
   112  	}
   113  	count(w, "drifted docs in simd mirror (stubs vs emulated)", m.mirror.result().miss(), "comments-yaml")
   114  	kv(w, "  mirrored declarations", m.mirror.result().d)
   115  }
   116  
   117  func (m *metrics) retirement(w *bytes.Buffer) {
   118  	section(w, "4. Retiring the old inputs", "comments-yaml, cat-rehome, compiler-ops-impl, cat-delete")
   119  	note(w, `categories.yaml's exported entries are emptied field by field: template-docs
   120  removes documentation, cat-rehome removes the rest, sig-from-spec removes
   121  commutative, and cat-delete removes the file. Compiler-only entries are
   122  handled wholesale by compiler-ops-impl.`)
   123  
   124  	count(w, "categories.yaml entries", m.catEntries, "cat-rehome, compiler-ops-impl, cat-delete")
   125  	sub(w, "unique operation names", m.catUniq)
   126  	sub(w, "  exported", m.catExported)
   127  	count(w, "compiler-only categories.yaml entries", m.catCompilerOnly, "compiler-ops-impl")
   128  	fmt.Fprintf(w, "\n  exported entries, by field:\n")
   129  	for _, k := range sortedKeys(m.catExportedFields) {
   130  		if k != "go" {
   131  			tag := "cat-rehome"
   132  			if k == "commutative" {
   133  				tag = "sig-from-spec"
   134  			}
   135  			countIndented(w, k, m.catExportedFields[k], tag)
   136  		}
   137  	}
   138  	fmt.Fprintf(w, "\n")
   139  	count(w, "midway/comments.yaml entries spec covers", m.commentsSpecCovered, "comments-yaml, spec-all")
   140  	fmt.Fprintf(w, "\n")
   141  	count(w, "commutativity disagreements, spec vs categories.yaml", m.commutDrift, "spec-all")
   142  }
   143  
   144  func (m *metrics) disagreement(w *bytes.Buffer) {
   145  	section(w, "5. Spec/API coverage disagreement detail", "spec-all, convert-lo, mask-bits")
   146  	note(w, `Where both sides define a name, receivers only the API declares are spec
   147  bugs (a constraint is wrong or a sibling function is missing). Receivers
   148  only spec generates are a review queue -- spec is deliberately maximal.`)
   149  
   150  	count(w, "spec misses receivers of a name it defines", m.apiOnly, "spec-all, convert-lo, mask-bits")
   151  	count(w, "    declarations affected, counting each target", m.apiOnlyDecls, "spec-all, convert-lo, mask-bits")
   152  	count(w, "spec operations implemented nowhere", len(m.specOnly), "spec-all")
   153  	emptyList(w, len(m.specOnly))
   154  	for _, n := range m.specOnly {
   155  		fmt.Fprintf(w, "    %s\n", n)
   156  	}
   157  
   158  	fmt.Fprintf(w, "\nEvery name either side defines, less the %d spec has never defined at all\n",
   159  		m.rel[relAPIOnly].names)
   160  	fmt.Fprintf(w, "(%d receivers, counted as coverage in §1 rather than disagreement):\n\n",
   161  		m.rel[relAPIOnly].apiOnly)
   162  	fmt.Fprintf(w, "  %-14s %7s %14s %14s\n", "relation", "names", "Σ|api - spec|", "Σ|spec - api|")
   163  	fmt.Fprintf(w, "  %-14s %7s %14s %14s\n", "", "", "(-> 0)", "(review)")
   164  	var total relTotal
   165  	for r := relEqual; r <= relSpecOnly; r++ {
   166  		t := m.rel[r]
   167  		fmt.Fprintf(w, "  %-14s %7d %14d %14d\n", relationName[r], t.names, t.apiOnly, t.specOnly)
   168  		total.names, total.apiOnly, total.specOnly = total.names+t.names, total.apiOnly+t.apiOnly, total.specOnly+t.specOnly
   169  	}
   170  	fmt.Fprintf(w, "  %-14s %7d %14d %14d\n", "total", total.names, total.apiOnly, total.specOnly)
   171  
   172  	note(w, "\nNames that disagree, with api - spec receivers (the defects):")
   173  	fmt.Fprintf(w, "  %-26s %-11s %5s %6s %12s %12s\n",
   174  		"name", "relation", "|api|", "|spec|", "|api - spec|", "|spec - api|")
   175  	n := 0
   176  	for _, r := range m.names {
   177  		if r.rel == relEqual || r.rel == relAPIOnly {
   178  			continue
   179  		}
   180  		n++
   181  		fmt.Fprintf(w, "  %-26s %-11s %5d %6d %12d %12d\n",
   182  			r.name, relationName[r.rel], r.api, r.spec, len(r.apiOnly), r.specOnly)
   183  		wrap(w, "      ", "api - spec = ", r.apiOnly)
   184  	}
   185  	emptyList(w, n)
   186  }
   187  

View as plain text