diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2024-04-09 09:02:58 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2024-04-09 08:33:12 +0000 |
| commit | da07505f2b87b144347aa19597979d340b134b06 (patch) | |
| tree | 9b4cb823a01ffc801097465b1dc7a43f7092d826 /pkg | |
| parent | bf86f5aaada407ff2fed28fe03bc0b892caf4e41 (diff) | |
pkg/cover: don't memorize all coverage points twice
Currently we memorize all coverage points twice:
as a slice and as a map.
The map also contains __sanitizer_cov_trace_cmp PCs,
but I think that's wrong, it should contain only
__sanitizer_cov_trace_pc callbacks.
We were careful to put as least pressure on the GC as possible
by keeping all PCs as a dense allCoverPoints slice and subslicing it
in all symbol/compilation unit objects.
Don't duplicate coverage points in the map and just use the same slice
we store for other purposes.
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/cover/backend/backend.go | 14 | ||||
| -rw-r--r-- | pkg/cover/backend/dwarf.go | 18 | ||||
| -rw-r--r-- | pkg/cover/html.go | 4 | ||||
| -rw-r--r-- | pkg/cover/report.go | 10 |
4 files changed, 21 insertions, 25 deletions
diff --git a/pkg/cover/backend/backend.go b/pkg/cover/backend/backend.go index a343dfe02..7ac0e8140 100644 --- a/pkg/cover/backend/backend.go +++ b/pkg/cover/backend/backend.go @@ -11,13 +11,13 @@ import ( ) type Impl struct { - Units []*CompileUnit - Symbols []*Symbol - Frames []Frame - Symbolize func(pcs map[*Module][]uint64) ([]Frame, error) - RestorePC func(pc uint32) uint64 - CallbackPoints map[uint64]bool - CoverageCallbackPoints []uint64 + Units []*CompileUnit + Symbols []*Symbol + Frames []Frame + Symbolize func(pcs map[*Module][]uint64) ([]Frame, error) + RestorePC func(pc uint32) uint64 + CallbackPoints []uint64 + PreciseCoverage bool } type Module struct { diff --git a/pkg/cover/backend/dwarf.go b/pkg/cover/backend/dwarf.go index b90bf0cc4..b13ba2ca8 100644 --- a/pkg/cover/backend/dwarf.go +++ b/pkg/cover/backend/dwarf.go @@ -154,7 +154,7 @@ func makeDWARFUnsafe(params *dwarfParams) (*Impl, error) { var allRanges []pcRange var allUnits []*CompileUnit var pcBase uint64 - var verifyCoverPoints = true + preciseCoverage := true for _, module := range modules { errc := make(chan error, 1) go func() { @@ -190,7 +190,7 @@ func makeDWARFUnsafe(params *dwarfParams) (*Impl, error) { allRanges = append(allRanges, ranges...) allUnits = append(allUnits, units...) if IsKcovBrokenInCompiler(params.getCompilerVersion(module.Path)) { - verifyCoverPoints = false + preciseCoverage = false } } @@ -225,23 +225,15 @@ func makeDWARFUnsafe(params *dwarfParams) (*Impl, error) { // On FreeBSD .text address in ELF is 0, but .text is actually mapped at 0xffffffff. pcBase = ^uint64(0) } - var allCoverPointsMap = make(map[uint64]bool) - if verifyCoverPoints { - for i := 0; i < 2; i++ { - for _, pc := range allCoverPoints[i] { - allCoverPointsMap[pc] = true - } - } - } impl := &Impl{ Units: allUnits, Symbols: allSymbols, Symbolize: func(pcs map[*Module][]uint64) ([]Frame, error) { return symbolize(target, objDir, srcDir, buildDir, splitBuildDelimiters, pcs) }, - RestorePC: makeRestorePC(params, pcBase), - CallbackPoints: allCoverPointsMap, - CoverageCallbackPoints: allCoverPoints[0], + RestorePC: makeRestorePC(params, pcBase), + CallbackPoints: allCoverPoints[0], + PreciseCoverage: preciseCoverage, } return impl, nil } diff --git a/pkg/cover/html.go b/pkg/cover/html.go index 6e266ebce..319a61ddd 100644 --- a/pkg/cover/html.go +++ b/pkg/cover/html.go @@ -225,8 +225,8 @@ type CoverageInfo struct { // DoCoverJSONL is a handler for "/cover?jsonl=1". func (rg *ReportGenerator) DoCoverJSONL(w io.Writer, params CoverHandlerParams) error { - if rg.CoverageCallbackPoints != nil { - if err := rg.symbolizePCs(rg.CoverageCallbackPoints); err != nil { + if rg.CallbackPoints != nil { + if err := rg.symbolizePCs(rg.CallbackPoints); err != nil { return fmt.Errorf("failed to symbolize PCs(): %w", err) } } diff --git a/pkg/cover/report.go b/pkg/cover/report.go index 4e7ec3001..7b291874b 100644 --- a/pkg/cover/report.go +++ b/pkg/cover/report.go @@ -93,14 +93,13 @@ func (rg *ReportGenerator) prepareFileMap(progs []Prog, debug bool) (fileMap, er } progPCs := make(map[uint64]map[int]bool) unmatchedProgPCs := make(map[uint64]bool) - verifyCallbackPoints := (len(rg.CallbackPoints) > 0) for i, prog := range progs { for _, pc := range prog.PCs { if progPCs[pc] == nil { progPCs[pc] = make(map[int]bool) } progPCs[pc][i] = true - if verifyCallbackPoints && !rg.CallbackPoints[pc] { + if rg.PreciseCoverage && !contains(rg.CallbackPoints, pc) { unmatchedProgPCs[pc] = true } } @@ -136,7 +135,7 @@ func (rg *ReportGenerator) prepareFileMap(progs []Prog, debug bool) (fileMap, er } // If the backend provided coverage callback locations for the binaries, use them to // verify data returned by kcov. - if verifyCallbackPoints && (len(unmatchedProgPCs) > 0) { + if len(unmatchedProgPCs) > 0 { return nil, coverageCallbackMismatch(debug, len(progPCs), unmatchedProgPCs) } for _, unit := range rg.Units { @@ -168,6 +167,11 @@ func (rg *ReportGenerator) prepareFileMap(progs []Prog, debug bool) (fileMap, er return files, nil } +func contains(pcs []uint64, pc uint64) bool { + idx := sort.Search(len(pcs), func(i int) bool { return pcs[i] >= pc }) + return idx < len(pcs) && pcs[idx] == pc +} + func coverageCallbackMismatch(debug bool, numPCs int, unmatchedProgPCs map[uint64]bool) error { debugStr := "" if debug { |
