1
2
3
4
5 package cfile
6
7 import (
8 "encoding/json"
9 "fmt"
10 "internal/coverage"
11 "internal/coverage/calloc"
12 "internal/coverage/cformat"
13 "internal/coverage/cmerge"
14 "internal/coverage/decodecounter"
15 "internal/coverage/decodemeta"
16 "internal/coverage/pods"
17 "internal/coverage/rtcov"
18 "internal/runtime/atomic"
19 "io"
20 "os"
21 "path/filepath"
22 "strings"
23 "unsafe"
24 )
25
26
27
28
29
30 func ProcessCoverTestDir(dir string, cfile string, cm string, cpkg string, w io.Writer, selpkgs []string) error {
31 cmode := coverage.ParseCounterMode(cm)
32 if cmode == coverage.CtrModeInvalid {
33 return fmt.Errorf("invalid counter mode %q", cm)
34 }
35
36
37 ml := rtcov.Meta.List
38 if len(ml) == 0 {
39
40
41
42 } else {
43 if err := emitMetaDataToDirectory(dir, ml); err != nil {
44 return err
45 }
46 if err := emitCounterDataToDirectory(dir); err != nil {
47 return err
48 }
49 }
50
51
52
53
54
55 podlist, err := pods.CollectPods([]string{dir}, false)
56 if err != nil {
57 return fmt.Errorf("reading from %s: %v", dir, err)
58 }
59
60
61 var tf *os.File
62 var tfClosed bool
63 if cfile != "" {
64 var err error
65 tf, err = os.Create(cfile)
66 if err != nil {
67 return fmt.Errorf("internal error: opening coverage data output file %q: %v", cfile, err)
68 }
69 defer func() {
70 if !tfClosed {
71 tfClosed = true
72 tf.Close()
73 }
74 }()
75 }
76
77
78 ts := &tstate{
79 cm: &cmerge.Merger{},
80 cf: cformat.NewFormatter(cmode),
81 cmode: cmode,
82 }
83
84
85
86
87 hashstring := fmt.Sprintf("%x", finalHash)
88 importpaths := make(map[string]struct{})
89 for _, p := range podlist {
90 if !strings.Contains(p.MetaFile, hashstring) {
91 continue
92 }
93 if err := ts.processPod(p, importpaths); err != nil {
94 return err
95 }
96 }
97
98 metafilespath := filepath.Join(dir, coverage.MetaFilesFileName)
99 if _, err := os.Stat(metafilespath); err == nil {
100 if err := ts.readAuxMetaFiles(metafilespath, importpaths); err != nil {
101 return err
102 }
103 }
104
105
106 if err := ts.cf.EmitPercent(w, selpkgs, cpkg, true, true); err != nil {
107 return err
108 }
109
110
111 if tf != nil {
112 if err := ts.cf.EmitTextual(tf); err != nil {
113 return err
114 }
115 tfClosed = true
116 if err := tf.Close(); err != nil {
117 return fmt.Errorf("closing %s: %v", cfile, err)
118 }
119 }
120
121 return nil
122 }
123
124 type tstate struct {
125 calloc.BatchCounterAlloc
126 cm *cmerge.Merger
127 cf *cformat.Formatter
128 cmode coverage.CounterMode
129 }
130
131
132 func (ts *tstate) processPod(p pods.Pod, importpaths map[string]struct{}) error {
133
134 f, err := os.Open(p.MetaFile)
135 if err != nil {
136 return fmt.Errorf("unable to open meta-data file %s: %v", p.MetaFile, err)
137 }
138 defer func() {
139 f.Close()
140 }()
141 var mfr *decodemeta.CoverageMetaFileReader
142 mfr, err = decodemeta.NewCoverageMetaFileReader(f, nil)
143 if err != nil {
144 return fmt.Errorf("error reading meta-data file %s: %v", p.MetaFile, err)
145 }
146 newmode := mfr.CounterMode()
147 if newmode != ts.cmode {
148 return fmt.Errorf("internal error: counter mode clash: %q from test harness, %q from data file %s", ts.cmode.String(), newmode.String(), p.MetaFile)
149 }
150 newgran := mfr.CounterGranularity()
151 if err := ts.cm.SetModeAndGranularity(p.MetaFile, cmode, newgran); err != nil {
152 return err
153 }
154
155
156 pmm := make(map[pkfunc][]uint32)
157
158
159 readcdf := func(cdf string) error {
160 cf, err := os.Open(cdf)
161 if err != nil {
162 return fmt.Errorf("opening counter data file %s: %s", cdf, err)
163 }
164 defer cf.Close()
165 var cdr *decodecounter.CounterDataReader
166 cdr, err = decodecounter.NewCounterDataReader(cdf, cf)
167 if err != nil {
168 return fmt.Errorf("reading counter data file %s: %s", cdf, err)
169 }
170 var data decodecounter.FuncPayload
171 for {
172 ok, err := cdr.NextFunc(&data)
173 if err != nil {
174 return fmt.Errorf("reading counter data file %s: %v", cdf, err)
175 }
176 if !ok {
177 break
178 }
179
180
181 key := pkfunc{pk: data.PkgIdx, fcn: data.FuncIdx}
182 if prev, found := pmm[key]; found {
183
184 if err, _ := ts.cm.MergeCounters(data.Counters, prev); err != nil {
185 return fmt.Errorf("processing counter data file %s: %v", cdf, err)
186 }
187 }
188 c := ts.AllocateCounters(len(data.Counters))
189 copy(c, data.Counters)
190 pmm[key] = c
191 }
192 return nil
193 }
194
195
196 for _, cdf := range p.CounterDataFiles {
197 if err := readcdf(cdf); err != nil {
198 return err
199 }
200 }
201
202
203 np := uint32(mfr.NumPackages())
204 payload := []byte{}
205 for pkIdx := uint32(0); pkIdx < np; pkIdx++ {
206 var pd *decodemeta.CoverageMetaDataDecoder
207 pd, payload, err = mfr.GetPackageDecoder(pkIdx, payload)
208 if err != nil {
209 return fmt.Errorf("reading pkg %d from meta-file %s: %s", pkIdx, p.MetaFile, err)
210 }
211 ts.cf.SetPackage(pd.PackagePath())
212 importpaths[pd.PackagePath()] = struct{}{}
213 var fd coverage.FuncDesc
214 nf := pd.NumFuncs()
215 for fnIdx := uint32(0); fnIdx < nf; fnIdx++ {
216 if err := pd.ReadFunc(fnIdx, &fd); err != nil {
217 return fmt.Errorf("reading meta-data file %s: %v",
218 p.MetaFile, err)
219 }
220 key := pkfunc{pk: pkIdx, fcn: fnIdx}
221 counters, haveCounters := pmm[key]
222 for i := 0; i < len(fd.Units); i++ {
223 u := fd.Units[i]
224
225
226 if u.Parent != 0 {
227 continue
228 }
229 count := uint32(0)
230 if haveCounters {
231 count = counters[i]
232 }
233 ts.cf.AddUnit(fd.Srcfile, fd.Funcname, fd.Lit, u, count)
234 }
235 }
236 }
237 return nil
238 }
239
240 type pkfunc struct {
241 pk, fcn uint32
242 }
243
244 func (ts *tstate) readAuxMetaFiles(metafiles string, importpaths map[string]struct{}) error {
245
246
247 var mfc coverage.MetaFileCollection
248 data, err := os.ReadFile(metafiles)
249 if err != nil {
250 return fmt.Errorf("error reading auxmetafiles file %q: %v", metafiles, err)
251 }
252 if err := json.Unmarshal(data, &mfc); err != nil {
253 return fmt.Errorf("error reading auxmetafiles file %q: %v", metafiles, err)
254 }
255
256
257
258
259
260
261 for i := range mfc.ImportPaths {
262 p := mfc.ImportPaths[i]
263 if _, ok := importpaths[p]; ok {
264 continue
265 }
266 var pod pods.Pod
267 pod.MetaFile = mfc.MetaFileFragments[i]
268 if err := ts.processPod(pod, importpaths); err != nil {
269 return err
270 }
271 }
272 return nil
273 }
274
275
276
277
278
279
280
281 func Snapshot() float64 {
282 cl := getCovCounterList()
283 if len(cl) == 0 {
284
285 return 0.0
286 }
287
288 tot := uint64(0)
289 totExec := uint64(0)
290 for _, c := range cl {
291 sd := unsafe.Slice((*atomic.Uint32)(unsafe.Pointer(c.Counters)), c.Len)
292 tot += uint64(len(sd))
293 for i := 0; i < len(sd); i++ {
294
295 if sd[i].Load() == 0 {
296 continue
297 }
298
299 nCtrs := sd[i+coverage.NumCtrsOffset].Load()
300 cst := i + coverage.FirstCtrOffset
301
302 if cst+int(nCtrs) > len(sd) {
303 break
304 }
305 counters := sd[cst : cst+int(nCtrs)]
306 for i := range counters {
307 if counters[i].Load() != 0 {
308 totExec++
309 }
310 }
311 i += coverage.FirstCtrOffset + int(nCtrs) - 1
312 }
313 }
314 if tot == 0 {
315 return 0.0
316 }
317 return float64(totExec) / float64(tot)
318 }
319
View as plain text