Source file src/simd/archsimd/_gen/cmd/specstats/main.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 // Specstats reports progress on the internal/spec transition described in 6 // SPEC-TRANSITION.md. It prints the report to standard output: 7 // 8 // go run ./cmd/specstats 9 // 10 // The report is not checked in. Nearly every figure in it is a total that 11 // almost every spec or API change moves, so a checked-in copy made changes in 12 // flight conflict with each other and went stale whenever someone forgot to 13 // regenerate it. Run it at whatever commit you want numbers for. The figures 14 // that must not regress are enforced by TestInvariants instead. 15 // 16 // Every figure it prints is a fraction heading for 100% or a defect count 17 // heading for zero, tied to the tasks that move it. Anything that is merely 18 // interesting, rather than a measure of how far along we are, does not belong 19 // here. 20 // 21 // # How it is put together 22 // 23 // Almost every figure in the report is the same operation: count the distinct 24 // things at some granularity, and count how many of them are done. So the 25 // program builds one fact table -- [fact], a declaration as seen in one build 26 // configuration -- and everything downstream is a pivot over it: pick a grain 27 // ([fact.declKey], [fact.triple], [fact.pair], name), pick a predicate, and 28 // optionally group by a dimension. [tally] does the counting and [pivot] does 29 // the grouping, so a new figure is a few lines rather than a new loop. 30 // 31 // Like Fill, this parses rather than type-checks, so it sees every target's 32 // declarations regardless of build tags (SPEC-TRANSITION.md ยง2.4). It is 33 // mostly a measurement tool: it reports divergence and does not judge it. The 34 // exception is the counts that have reached zero (see [invariant]), which 35 // TestInvariants enforces. fill builds the checker, and should absorb the 36 // comparison half of this program rather than leave two implementations to 37 // drift. 38 package main 39 40 import ( 41 "bytes" 42 "flag" 43 "log" 44 "os" 45 "path/filepath" 46 47 "simd/archsimd/_gen/gentools" 48 "simd/archsimd/_gen/specgen" 49 ) 50 51 func main() { 52 log.SetFlags(0) 53 log.SetPrefix("specstats: ") 54 genOpts := gentools.RegisterFlags(nil) 55 flag.Parse() 56 if genOpts.Write || genOpts.Diff { 57 log.Fatal("the report is no longer checked in; run without -w or -diff to print it") 58 } 59 60 var buf bytes.Buffer 61 load(genOpts).report(&buf) 62 os.Stdout.Write(buf.Bytes()) 63 } 64 65 // load reads spec and the simd and archsimd APIs and measures them. 66 func load(genOpts *gentools.Options) *metrics { 67 specDir := specgen.MustFindSpecDir(genOpts.GOROOT) 68 simdDir := filepath.Clean(filepath.Join(specDir, "..", "..")) 69 genDir := filepath.Join(simdDir, "archsimd", "_gen") 70 71 spec, err := specgen.Load(specDir, nil) 72 if err != nil { 73 log.Fatalf("loading spec: %s", err) 74 } 75 return measure(loadAPI(genOpts, simdDir), spec, genDir) 76 } 77