Source file
src/cmd/covdata/metamerge.go
1
2
3
4
5 package main
6
7
8
9
10
11 import (
12 "crypto/md5"
13 "fmt"
14 "internal/coverage"
15 "internal/coverage/calloc"
16 "internal/coverage/cmerge"
17 "internal/coverage/decodecounter"
18 "internal/coverage/decodemeta"
19 "internal/coverage/encodecounter"
20 "internal/coverage/encodemeta"
21 "internal/coverage/slicewriter"
22 "io"
23 "os"
24 "path/filepath"
25 "sort"
26 "time"
27 "unsafe"
28 )
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 type metaMerge struct {
50 calloc.BatchCounterAlloc
51 cmerge.Merger
52
53 pkm map[string]*pkstate
54
55 pkgs []*pkstate
56
57 p *pkstate
58
59 pod *podstate
60
61 astate *argstate
62 }
63
64
65 type pkstate struct {
66
67 pkgIdx uint32
68
69 ctab map[uint32]decodecounter.FuncPayload
70
71 mdblob []byte
72
73 *pcombinestate
74 }
75
76 type podstate struct {
77 pmm map[pkfunc]decodecounter.FuncPayload
78 mdf string
79 mfr *decodemeta.CoverageMetaFileReader
80 fileHash [16]byte
81 }
82
83 type pkfunc struct {
84 pk, fcn uint32
85 }
86
87
88 type pcombinestate struct {
89
90 cmdb *encodemeta.CoverageMetaDataBuilder
91
92
93 ftab map[[16]byte]uint32
94 }
95
96 func newMetaMerge() *metaMerge {
97 return &metaMerge{
98 pkm: make(map[string]*pkstate),
99 astate: &argstate{},
100 }
101 }
102
103 func (mm *metaMerge) visitMetaDataFile(mdf string, mfr *decodemeta.CoverageMetaFileReader) {
104 dbgtrace(2, "visitMetaDataFile(mdf=%s)", mdf)
105
106
107 mm.pod.mdf = mdf
108
109 mm.pod.mfr = mfr
110
111 mm.pod.fileHash = mfr.FileHash()
112
113 newgran := mfr.CounterGranularity()
114 newmode := mfr.CounterMode()
115 if err := mm.SetModeAndGranularity(mdf, newmode, newgran); err != nil {
116 fatal("%v", err)
117 }
118 }
119
120 func (mm *metaMerge) beginCounterDataFile(cdr *decodecounter.CounterDataReader) {
121 state := argvalues{
122 osargs: cdr.OsArgs(),
123 goos: cdr.Goos(),
124 goarch: cdr.Goarch(),
125 }
126 mm.astate.Merge(state)
127 }
128
129 func copyMetaDataFile(inpath, outpath string) {
130 inf, err := os.Open(inpath)
131 if err != nil {
132 fatal("opening input meta-data file %s: %v", inpath, err)
133 }
134 defer inf.Close()
135
136 fi, err := inf.Stat()
137 if err != nil {
138 fatal("accessing input meta-data file %s: %v", inpath, err)
139 }
140
141 outf, err := os.OpenFile(outpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode())
142 if err != nil {
143 fatal("opening output meta-data file %s: %v", outpath, err)
144 }
145
146 _, err = io.Copy(outf, inf)
147 outf.Close()
148 if err != nil {
149 fatal("writing output meta-data file %s: %v", outpath, err)
150 }
151 }
152
153 func (mm *metaMerge) beginPod() {
154 mm.pod = &podstate{
155 pmm: make(map[pkfunc]decodecounter.FuncPayload),
156 }
157 }
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 func (mm *metaMerge) endPod(pcombine bool) {
175 if pcombine {
176
177
178 mm.pod = nil
179 return
180 }
181
182 finalHash := mm.pod.fileHash
183 if matchpkg != nil {
184
185 finalHash = mm.emitMeta(*outdirflag, pcombine)
186 } else {
187
188 inpath := mm.pod.mdf
189 mdfbase := filepath.Base(mm.pod.mdf)
190 outpath := filepath.Join(*outdirflag, mdfbase)
191 copyMetaDataFile(inpath, outpath)
192 }
193
194
195 mm.emitCounters(*outdirflag, finalHash)
196
197
198 mm.pkm = make(map[string]*pkstate)
199 mm.pkgs = nil
200 mm.pod = nil
201
202
203 mm.ResetModeAndGranularity()
204 }
205
206
207
208
209 func (mm *metaMerge) emitMeta(outdir string, pcombine bool) [16]byte {
210 fh := md5.New()
211 blobs := [][]byte{}
212 tlen := uint64(unsafe.Sizeof(coverage.MetaFileHeader{}))
213 for _, p := range mm.pkgs {
214 var blob []byte
215 if pcombine {
216 mdw := &slicewriter.WriteSeeker{}
217 p.cmdb.Emit(mdw)
218 blob = mdw.BytesWritten()
219 } else {
220 blob = p.mdblob
221 }
222 ph := md5.Sum(blob)
223 blobs = append(blobs, blob)
224 if _, err := fh.Write(ph[:]); err != nil {
225 panic(fmt.Sprintf("internal error: md5 sum failed: %v", err))
226 }
227 tlen += uint64(len(blob))
228 }
229 var finalHash [16]byte
230 fhh := fh.Sum(nil)
231 copy(finalHash[:], fhh)
232
233
234 fn := fmt.Sprintf("%s.%x", coverage.MetaFilePref, finalHash)
235 fpath := filepath.Join(outdir, fn)
236 mf, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
237 if err != nil {
238 fatal("unable to open output meta-data file %s: %v", fpath, err)
239 }
240
241
242 mfw := encodemeta.NewCoverageMetaFileWriter(fpath, mf)
243 err = mfw.Write(finalHash, blobs, mm.Mode(), mm.Granularity())
244 if err != nil {
245 fatal("error writing %s: %v\n", fpath, err)
246 }
247 return finalHash
248 }
249
250 func (mm *metaMerge) emitCounters(outdir string, metaHash [16]byte) {
251
252
253
254
255 var dummyPID int
256 fn := fmt.Sprintf(coverage.CounterFileTempl, coverage.CounterFilePref, metaHash, dummyPID, time.Now().UnixNano())
257 fpath := filepath.Join(outdir, fn)
258 cf, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
259 if err != nil {
260 fatal("opening counter data file %s: %v", fpath, err)
261 }
262 defer func() {
263 if err := cf.Close(); err != nil {
264 fatal("error closing output meta-data file %s: %v", fpath, err)
265 }
266 }()
267
268 args := mm.astate.ArgsSummary()
269 cfw := encodecounter.NewCoverageDataWriter(cf, coverage.CtrULeb128)
270 if err := cfw.Write(metaHash, args, mm); err != nil {
271 fatal("counter file write failed: %v", err)
272 }
273 mm.astate = &argstate{}
274 }
275
276
277
278
279 func (mm *metaMerge) VisitFuncs(f encodecounter.CounterVisitorFn) error {
280 if *verbflag >= 4 {
281 fmt.Printf("counterVisitor invoked\n")
282 }
283
284
285 for pidx, p := range mm.pkgs {
286 fids := make([]int, 0, len(p.ctab))
287 for fid := range p.ctab {
288 fids = append(fids, int(fid))
289 }
290 sort.Ints(fids)
291 if *verbflag >= 4 {
292 fmt.Printf("fids for pk=%d: %+v\n", pidx, fids)
293 }
294 for _, fid := range fids {
295 fp := p.ctab[uint32(fid)]
296 if *verbflag >= 4 {
297 fmt.Printf("counter write for pk=%d fid=%d len(ctrs)=%d\n", pidx, fid, len(fp.Counters))
298 }
299 if err := f(uint32(pidx), uint32(fid), fp.Counters); err != nil {
300 return err
301 }
302 }
303 }
304 return nil
305 }
306
307 func (mm *metaMerge) visitPackage(pd *decodemeta.CoverageMetaDataDecoder, pkgIdx uint32, pcombine bool) {
308 p, ok := mm.pkm[pd.PackagePath()]
309 if !ok {
310 p = &pkstate{
311 pkgIdx: uint32(len(mm.pkgs)),
312 }
313 mm.pkgs = append(mm.pkgs, p)
314 mm.pkm[pd.PackagePath()] = p
315 if pcombine {
316 p.pcombinestate = new(pcombinestate)
317 cmdb, err := encodemeta.NewCoverageMetaDataBuilder(pd.PackagePath(), pd.PackageName(), pd.ModulePath())
318 if err != nil {
319 fatal("fatal error creating meta-data builder: %v", err)
320 }
321 dbgtrace(2, "install new pkm entry for package %s pk=%d", pd.PackagePath(), pkgIdx)
322 p.cmdb = cmdb
323 p.ftab = make(map[[16]byte]uint32)
324 } else {
325 var err error
326 p.mdblob, err = mm.pod.mfr.GetPackagePayload(pkgIdx, nil)
327 if err != nil {
328 fatal("error extracting package %d payload from %s: %v",
329 pkgIdx, mm.pod.mdf, err)
330 }
331 }
332 p.ctab = make(map[uint32]decodecounter.FuncPayload)
333 }
334 mm.p = p
335 }
336
337 func (mm *metaMerge) visitFuncCounterData(data decodecounter.FuncPayload) {
338 key := pkfunc{pk: data.PkgIdx, fcn: data.FuncIdx}
339 val := mm.pod.pmm[key]
340
341
342
343 if *verbflag > 4 {
344 fmt.Printf("visit pk=%d fid=%d len(counters)=%d\n", data.PkgIdx, data.FuncIdx, len(data.Counters))
345 }
346 if len(val.Counters) < len(data.Counters) {
347 t := val.Counters
348 val.Counters = mm.AllocateCounters(len(data.Counters))
349 copy(val.Counters, t)
350 }
351 err, overflow := mm.MergeCounters(val.Counters, data.Counters)
352 if err != nil {
353 fatal("%v", err)
354 }
355 if overflow {
356 warn("uint32 overflow during counter merge")
357 }
358 mm.pod.pmm[key] = val
359 }
360
361 func (mm *metaMerge) visitFunc(pkgIdx uint32, fnIdx uint32, fd *coverage.FuncDesc, verb string, pcombine bool) {
362 if *verbflag >= 3 {
363 fmt.Printf("visit pk=%d fid=%d func %s\n", pkgIdx, fnIdx, fd.Funcname)
364 }
365
366 var counters []uint32
367 key := pkfunc{pk: pkgIdx, fcn: fnIdx}
368 v, haveCounters := mm.pod.pmm[key]
369 if haveCounters {
370 counters = v.Counters
371 }
372
373 if pcombine {
374
375
376
377
378 fnhash := encodemeta.HashFuncDesc(fd)
379 gfidx, ok := mm.p.ftab[fnhash]
380 if !ok {
381
382
383 gfidx = uint32(mm.p.cmdb.AddFunc(*fd))
384 mm.p.ftab[fnhash] = gfidx
385 if *verbflag >= 3 {
386 fmt.Printf("new meta entry for fn %s fid=%d\n", fd.Funcname, gfidx)
387 }
388 }
389 fnIdx = gfidx
390 }
391 if !haveCounters {
392 return
393 }
394
395
396 gfp, ok := mm.p.ctab[fnIdx]
397 if ok {
398 if verb == "subtract" || verb == "intersect" {
399 panic("should never see this for intersect/subtract")
400 }
401 if *verbflag >= 3 {
402 fmt.Printf("counter merge for %s fidx=%d\n", fd.Funcname, fnIdx)
403 }
404
405 err, overflow := mm.MergeCounters(gfp.Counters, counters)
406 if err != nil {
407 fatal("%v", err)
408 }
409 if overflow {
410 warn("uint32 overflow during counter merge")
411 }
412 mm.p.ctab[fnIdx] = gfp
413 } else {
414 if *verbflag >= 3 {
415 fmt.Printf("null merge for %s fidx %d\n", fd.Funcname, fnIdx)
416 }
417 gfp := v
418 gfp.PkgIdx = mm.p.pkgIdx
419 gfp.FuncIdx = fnIdx
420 mm.p.ctab[fnIdx] = gfp
421 }
422 }
423
View as plain text