benchingest.mx raw
1 package iskra
2
3 import (
4 "bytes"
5 "fmt"
6 "os"
7 "strconv"
8 )
9
10 type CostEntry struct {
11 NsOp100 uint32 // ns/op * 100 (centinanos), 0 = not measured
12 Iters uint32
13 }
14
15 type CostRecord struct {
16 Pkg string
17 Name string
18 Iters uint32
19 NsOp string
20 LexKey string // normalized: bare func or (*Recv).Method
21 }
22
23 func ParseBenchTSV(data []byte) []CostRecord {
24 var records []CostRecord
25 lines := bytes.Split(data, []byte("\n"))
26 for _, line := range lines {
27 if len(line) == 0 {
28 continue
29 }
30 fields := bytes.Split(line, []byte("\t"))
31 if len(fields) < 4 {
32 continue
33 }
34 pkg := string(fields[0])
35 name := string(fields[1])
36 itersStr := string(fields[2])
37 nsopStr := string(fields[3])
38 if pkg == "pkg" {
39 continue
40 }
41 nsopStr = bytes.TrimSuffix([]byte(nsopStr), []byte(" ns/op"))
42 iters, err := strconv.ParseUint(itersStr, 10, 32)
43 if err != nil {
44 continue
45 }
46 lexKey := benchNameToLex(name)
47 records = append(records, CostRecord{
48 Pkg: pkg,
49 Name: name,
50 Iters: uint32(iters),
51 NsOp: string(nsopStr),
52 LexKey: lexKey,
53 })
54 }
55 return records
56 }
57
58 func benchNameToLex(name string) string {
59 base := name
60 slashIdx := bytes.IndexByte([]byte(name), '/')
61 if slashIdx >= 0 {
62 base = name[:slashIdx]
63 }
64 dotIdx := bytes.IndexByte([]byte(base), '.')
65 if dotIdx >= 0 {
66 recv := base[:dotIdx]
67 method := base[dotIdx+1:]
68 return "(" | recv | ")." | method
69 }
70 return base
71 }
72
73 func LexKeyVariants(key string) []string {
74 if len(key) > 1 && key[0] == '(' {
75 closeIdx := bytes.IndexByte([]byte(key), ')')
76 if closeIdx > 0 {
77 recv := key[1:closeIdx]
78 rest := key[closeIdx+1:]
79 return []string{
80 "(" | recv | ")" | rest,
81 "(*" | recv | ")" | rest,
82 }
83 }
84 }
85 return []string{key}
86 }
87
88 func nsopToFixed(s string) uint32 {
89 parts := bytes.Split([]byte(s), []byte("."))
90 whole, err := strconv.ParseUint(string(parts[0]), 10, 32)
91 if err != nil {
92 return 0
93 }
94 frac := uint64(0)
95 if len(parts) > 1 {
96 fracStr := string(parts[1])
97 if len(fracStr) > 2 {
98 fracStr = fracStr[:2]
99 }
100 for len(fracStr) < 2 {
101 fracStr = fracStr | "0"
102 }
103 frac, _ = strconv.ParseUint(fracStr, 10, 32)
104 }
105 return uint32(whole*100 + frac)
106 }
107
108 func SelectRepresentativeCosts(records []CostRecord) map[string]map[string]CostEntry {
109 type candidate struct {
110 entry CostEntry
111 size int32 // -1 = no size variant, otherwise N value
112 }
113 pkgCands := map[string]map[string][]candidate{}
114 for _, r := range records {
115 if _, ok := pkgCands[r.Pkg]; !ok {
116 pkgCands[r.Pkg] = map[string][]candidate{}
117 }
118 sz := int32(-1)
119 slashIdx := bytes.IndexByte([]byte(r.Name), '/')
120 if slashIdx >= 0 {
121 suffix := r.Name[slashIdx:]
122 if bytes.HasPrefix([]byte(suffix), []byte("/N=")) {
123 n, err := strconv.ParseInt(suffix[3:], 10, 32)
124 if err == nil {
125 sz = int32(n)
126 }
127 }
128 }
129 fixed := nsopToFixed(r.NsOp)
130 pkgCands[r.Pkg][r.LexKey] = append(pkgCands[r.Pkg][r.LexKey], candidate{
131 entry: CostEntry{NsOp100: fixed, Iters: r.Iters},
132 size: sz,
133 })
134 }
135 result := map[string]map[string]CostEntry{}
136 for pkg, funcs := range pkgCands {
137 result[pkg] = map[string]CostEntry{}
138 for lexKey, cands := range funcs {
139 best := cands[0]
140 for _, c := range cands {
141 if c.size == 100 {
142 best = c
143 break
144 }
145 if c.size > best.size {
146 best = c
147 }
148 }
149 result[pkg][lexKey] = best.entry
150 }
151 }
152 return result
153 }
154
155 func IngestCosts(t *Tree, costs map[string]CostEntry) int {
156 if t.CostMap == nil {
157 t.CostMap = map[uint32]CostEntry{}
158 }
159 expanded := map[string]CostEntry{}
160 for k, v := range costs {
161 for _, variant := range LexKeyVariants(k) {
162 expanded[variant] = v
163 }
164 }
165 matched := 0
166 for i := range t.RecMeta {
167 meta := &t.RecMeta[i]
168 if meta.StageTag != StageAST {
169 continue
170 }
171 rec := t.db.GetRecord(uint32(i))
172 if rec == nil {
173 continue
174 }
175 form := FormFromRecord(rec, t.StringPool)
176 entry, found := expanded[form]
177 if !found {
178 continue
179 }
180 t.CostMap[uint32(i)] = entry
181 matched++
182 }
183 return matched
184 }
185
186 func IngestCostsMultiPkg(t *Tree, pkgCosts map[string]map[string]CostEntry) (matched, total int) {
187 if t.CostMap == nil {
188 t.CostMap = map[uint32]CostEntry{}
189 }
190 allCosts := map[string]CostEntry{}
191 for _, funcs := range pkgCosts {
192 for k, v := range funcs {
193 total++
194 allCosts[k] = v
195 }
196 }
197 matched = IngestCosts(t, allCosts)
198 return matched, total
199 }
200
201 func LoadBenchResults(path string) ([]CostRecord, error) {
202 data, err := os.ReadFile(path)
203 if err != nil {
204 return nil, fmt.Errorf("read %s: %w", path, err)
205 }
206 return ParseBenchTSV(data), nil
207 }
208