github.com/bir3/gocompiler@v0.9.2202/src/internal/coverage/cmerge/merge.go (about) 1 // Copyright 2022 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 cmerge 6 7 // package cmerge provides a few small utility APIs for helping 8 // with merging of counter data for a given function. 9 10 import ( 11 "fmt" 12 "github.com/bir3/gocompiler/src/internal/coverage" 13 "math" 14 ) 15 16 type ModeMergePolicy uint8 17 18 const ( 19 ModeMergeStrict ModeMergePolicy = iota 20 ModeMergeRelaxed 21 ) 22 23 // Merger provides state and methods to help manage the process of 24 // merging together coverage counter data for a given function, for 25 // tools that need to implicitly merge counter as they read multiple 26 // coverage counter data files. 27 type Merger struct { 28 cmode coverage.CounterMode 29 cgran coverage.CounterGranularity 30 policy ModeMergePolicy 31 overflow bool 32 } 33 34 func (cm *Merger) SetModeMergePolicy(policy ModeMergePolicy) { 35 cm.policy = policy 36 } 37 38 // MergeCounters takes the counter values in 'src' and merges them 39 // into 'dst' according to the correct counter mode. 40 func (m *Merger) MergeCounters(dst, src []uint32) (error, bool) { 41 if len(src) != len(dst) { 42 return fmt.Errorf("merging counters: len(dst)=%d len(src)=%d", len(dst), len(src)), false 43 } 44 if m.cmode == coverage.CtrModeSet { 45 for i := 0; i < len(src); i++ { 46 if src[i] != 0 { 47 dst[i] = 1 48 } 49 } 50 } else { 51 for i := 0; i < len(src); i++ { 52 dst[i] = m.SaturatingAdd(dst[i], src[i]) 53 } 54 } 55 ovf := m.overflow 56 m.overflow = false 57 return nil, ovf 58 } 59 60 // Saturating add does a saturating addition of 'dst' and 'src', 61 // returning added value or math.MaxUint32 if there is an overflow. 62 // Overflows are recorded in case the client needs to track them. 63 func (m *Merger) SaturatingAdd(dst, src uint32) uint32 { 64 result, overflow := SaturatingAdd(dst, src) 65 if overflow { 66 m.overflow = true 67 } 68 return result 69 } 70 71 // Saturating add does a saturating addition of 'dst' and 'src', 72 // returning added value or math.MaxUint32 plus an overflow flag. 73 func SaturatingAdd(dst, src uint32) (uint32, bool) { 74 d, s := uint64(dst), uint64(src) 75 sum := d + s 76 overflow := false 77 if uint64(uint32(sum)) != sum { 78 overflow = true 79 sum = math.MaxUint32 80 } 81 return uint32(sum), overflow 82 } 83 84 // SetModeAndGranularity records the counter mode and granularity for 85 // the current merge. In the specific case of merging across coverage 86 // data files from different binaries, where we're combining data from 87 // more than one meta-data file, we need to check for and resolve 88 // mode/granularity clashes. 89 func (cm *Merger) SetModeAndGranularity(mdf string, cmode coverage.CounterMode, cgran coverage.CounterGranularity) error { 90 if cm.cmode == coverage.CtrModeInvalid { 91 // Set merger mode based on what we're seeing here. 92 cm.cmode = cmode 93 cm.cgran = cgran 94 } else { 95 // Granularity clashes are always errors. 96 if cm.cgran != cgran { 97 return fmt.Errorf("counter granularity clash while reading meta-data file %s: previous file had %s, new file has %s", mdf, cm.cgran.String(), cgran.String()) 98 } 99 // Mode clashes are treated as errors if we're using the 100 // default strict policy. 101 if cm.cmode != cmode { 102 if cm.policy == ModeMergeStrict { 103 return fmt.Errorf("counter mode clash while reading meta-data file %s: previous file had %s, new file has %s", mdf, cm.cmode.String(), cmode.String()) 104 } 105 // In the case of a relaxed mode merge policy, upgrade 106 // mode if needed. 107 if cm.cmode < cmode { 108 cm.cmode = cmode 109 } 110 } 111 } 112 return nil 113 } 114 115 func (cm *Merger) ResetModeAndGranularity() { 116 cm.cmode = coverage.CtrModeInvalid 117 cm.cgran = coverage.CtrGranularityInvalid 118 cm.overflow = false 119 } 120 121 func (cm *Merger) Mode() coverage.CounterMode { 122 return cm.cmode 123 } 124 125 func (cm *Merger) Granularity() coverage.CounterGranularity { 126 return cm.cgran 127 }