From 171ec3714ee4886a3f5ecbfe71f63c8f81c7fd7c Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Tue, 9 Apr 2024 08:46:39 +0200 Subject: pkg/cover: fix jsonl hit count calculation prepareFileMap does more work than we need and leads to incorrect hit counts. prepareFileMap produces hit counts per source line (for source reports), but jsonl exports data based on coverage callbacks, not source lines. So if we have 2 callbacks on the same line, we will double count them (both will have hit count 2). If we calculate total percent later based on that data, it will be wrong. Use simpler calculation based on PCs. --- pkg/cover/html.go | 20 +++++++++++--------- pkg/cover/report.go | 4 ++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/pkg/cover/html.go b/pkg/cover/html.go index 319a61ddd..a3a9f0846 100644 --- a/pkg/cover/html.go +++ b/pkg/cover/html.go @@ -230,20 +230,22 @@ func (rg *ReportGenerator) DoCoverJSONL(w io.Writer, params CoverHandlerParams) return fmt.Errorf("failed to symbolize PCs(): %w", err) } } - var progs = fixUpPCs(rg.target.Arch, params.Progs, params.CoverFilter) - fm, err := rg.prepareFileMap(progs, params.Debug) - if err != nil { - return fmt.Errorf("failed to rg.prepareFileMap(): %w", err) + progs := fixUpPCs(rg.target.Arch, params.Progs, params.CoverFilter) + if err := rg.symbolizePCs(uniquePCs(progs)); err != nil { + return err + } + progPCs := make(map[uint64]int) + for _, prog := range progs { + for _, pc := range prog.PCs { + progPCs[pc]++ + } } - encoder := json.NewEncoder(w) for _, frame := range rg.Frames { endCol := frame.Range.EndCol if endCol == backend.LineEnd { endCol = -1 } - pcProgCount := FileByFrame(fm, &frame).lines[frame.StartLine].pcProgCount - hitCount := pcProgCount[frame.PC] covInfo := &CoverageInfo{ FilePath: frame.Name, FuncName: frame.FuncName, @@ -251,11 +253,11 @@ func (rg *ReportGenerator) DoCoverJSONL(w io.Writer, params CoverHandlerParams) StartCol: frame.Range.StartCol, EndLine: frame.Range.EndLine, EndCol: endCol, - HitCount: hitCount, + HitCount: progPCs[frame.PC], Inline: frame.Inline, PC: frame.PC, } - if err = encoder.Encode(covInfo); err != nil { + if err := encoder.Encode(covInfo); err != nil { return fmt.Errorf("failed to json.Encode(): %w", err) } } diff --git a/pkg/cover/report.go b/pkg/cover/report.go index 7b291874b..400ffdc02 100644 --- a/pkg/cover/report.go +++ b/pkg/cover/report.go @@ -106,7 +106,7 @@ func (rg *ReportGenerator) prepareFileMap(progs []Prog, debug bool) (fileMap, er } matchedPC := false for _, frame := range rg.Frames { - f := FileByFrame(files, &frame) + f := fileByFrame(files, &frame) ln := f.lines[frame.StartLine] coveredBy := progPCs[frame.PC] if len(coveredBy) == 0 { @@ -222,7 +222,7 @@ func (rg *ReportGenerator) symbolizePCs(PCs []uint64) error { return nil } -func FileByFrame(files map[string]*file, frame *backend.Frame) *file { +func fileByFrame(files map[string]*file, frame *backend.Frame) *file { f := files[frame.Name] if f == nil { f = &file{ -- cgit mrf-deployment