Skip to content

llvm-cov: Show FileCoverageSummary with getCoverageForFile() #121192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: users/chapuni/cov/merge/forfile-base
Choose a base branch
from

Conversation

chapuni
Copy link
Contributor

@chapuni chapuni commented Dec 27, 2024

FunctionCoverageSummary::get() is removed since it was used only from SingleFileReport. "Merge" facilities with std::max are removed as well for now. They will be re-introduced later.

For file indices, show also files that have no functions but any other CoverageInfo.

Fixes #119282

Depends on: #120842, #121188, #121191

@llvmbot llvmbot added the PGO Profile Guided Optimizations label Dec 27, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 27, 2024

@llvm/pr-subscribers-pgo

Author: NAKAMURA Takumi (chapuni)

Changes

FunctionCoverageSummary::get() is removed since it was used only from SingleFileReport. "Merge" facilities with std::max are removed as well for now. They will be re-introduced later.

For file indices, show also files that have no functions but any other CoverageInfo.

Fixes #119282

Depends on: #121188, #121191


Full diff: https://github.com/llvm/llvm-project/pull/121192.diff

9 Files Affected:

  • (modified) llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h (+3-1)
  • (modified) llvm/lib/ProfileData/Coverage/CoverageMapping.cpp (+5-1)
  • (modified) llvm/test/tools/llvm-cov/branch-templates.test (+2-2)
  • (modified) llvm/test/tools/llvm-cov/coverage_watermark.test (+11-11)
  • (modified) llvm/test/tools/llvm-cov/zeroFunctionFile.c (+1-2)
  • (modified) llvm/tools/llvm-cov/CoverageReport.cpp (+31-11)
  • (modified) llvm/tools/llvm-cov/CoverageSummaryInfo.cpp (-26)
  • (modified) llvm/tools/llvm-cov/CoverageSummaryInfo.h (+13-38)
  • (modified) llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp (+13-3)
diff --git a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
index c51733b46a1894..64416fdba1b247 100644
--- a/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
+++ b/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h
@@ -1012,7 +1012,9 @@ class CoverageMapping {
   /// The given filename must be the name as recorded in the coverage
   /// information. That is, only names returned from getUniqueSourceFiles will
   /// yield a result.
-  CoverageData getCoverageForFile(StringRef Filename) const;
+  CoverageData getCoverageForFile(
+      StringRef Filename,
+      const DenseSet<const FunctionRecord *> &FilteredOutFunctions = {}) const;
 
   /// Get the coverage for a particular function.
   CoverageData getCoverageForFunction(const FunctionRecord &Function) const;
diff --git a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
index feededcd7d1eb5..e7780b465186df 100644
--- a/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
+++ b/llvm/lib/ProfileData/Coverage/CoverageMapping.cpp
@@ -1422,7 +1422,9 @@ static bool isExpansion(const CountedRegion &R, unsigned FileID) {
   return R.Kind == CounterMappingRegion::ExpansionRegion && R.FileID == FileID;
 }
 
-CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
+CoverageData CoverageMapping::getCoverageForFile(
+    StringRef Filename,
+    const DenseSet<const FunctionRecord *> &FilteredOutFunctions) const {
   assert(SingleByteCoverage);
   MergeableCoverageData FileCoverage(*SingleByteCoverage, Filename);
 
@@ -1432,6 +1434,8 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
       getImpreciseRecordIndicesForFilename(Filename);
   for (unsigned RecordIndex : RecordIndices) {
     const FunctionRecord &Function = Functions[RecordIndex];
+    if (FilteredOutFunctions.count(&Function))
+      continue;
     auto MainFileID = findMainViewFileID(Filename, Function);
     auto FileIDs = gatherFileIDs(Filename, Function);
     FileCoverage.addFunctionRegions(
diff --git a/llvm/test/tools/llvm-cov/branch-templates.test b/llvm/test/tools/llvm-cov/branch-templates.test
index d5535022239f5f..594a3ca533678b 100644
--- a/llvm/test/tools/llvm-cov/branch-templates.test
+++ b/llvm/test/tools/llvm-cov/branch-templates.test
@@ -26,6 +26,6 @@
 
 // REPORTFILE:      Filename                 Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
 // REPORTFILE-NEXT: ---
-// REPORTFILE-NEXT: branch-templates.cpp          12                 3    75.00%           2                 0   100.00%          17                 4    76.47%           8                 4    50.00%
+// REPORTFILE-NEXT: branch-templates.cpp          12                 2    83.33%           2                 0   100.00%          17                 3    82.35%          12                 6    50.00%
 // REPORTFILE-NEXT: ---
-// REPORTFILE-NEXT: TOTAL                         12                 3    75.00%           2                 0   100.00%          17                 4    76.47%           8                 4    50.00%
+// REPORTFILE-NEXT: TOTAL                         12                 2    83.33%           2                 0   100.00%          17                 3    82.35%          12                 6    50.00%
diff --git a/llvm/test/tools/llvm-cov/coverage_watermark.test b/llvm/test/tools/llvm-cov/coverage_watermark.test
index 5c48b4f0fb4bf4..818baa470bc38d 100644
--- a/llvm/test/tools/llvm-cov/coverage_watermark.test
+++ b/llvm/test/tools/llvm-cov/coverage_watermark.test
@@ -18,15 +18,15 @@ ORIGIN: <td class='column-entry-green'>
 ORIGIN: 100.00% (2/2)
 ORIGIN: <td class='column-entry-green'>
 ORIGIN: 100.00% (3/3)
-ORIGIN: <td class='column-entry-red'>
-ORIGIN: 75.00% (9/12)
-ORIGIN: <td class='column-entry-red'>
-ORIGIN: 66.67% (4/6)
+ORIGIN: <td class='column-entry-yellow'>
+ORIGIN: 83.33% (10/12)
+ORIGIN: <td class='column-entry-yellow'>
+ORIGIN: 83.33% (5/6)
 ORIGIN: <td class='column-entry-gray'>
 ORIGIN: - (0/0)
 ORIGIN: </tr>
 
-RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -format html -show-region-summary -show-instantiation-summary -o %t.html.dir -path-equivalence=/tmp,%S -coverage-watermark 80,70 %S/showTemplateInstantiations.cpp
+RUN: llvm-cov show %S/Inputs/templateInstantiations.covmapping -instr-profile %S/Inputs/templateInstantiations.profdata -format html -show-region-summary -show-instantiation-summary -o %t.html.dir -path-equivalence=/tmp,%S -coverage-watermark 90,70 %S/showTemplateInstantiations.cpp
 RUN: FileCheck -check-prefix=DOWNGRADE1 %s -input-file %t.html.dir/index.html
 
 DOWNGRADE:1 Totals
@@ -35,9 +35,9 @@ DOWNGRADE1: 100.00% (2/2)
 DOWNGRADE1: <td class='column-entry-green'>
 DOWNGRADE1: 100.00% (3/3)
 DOWNGRADE1: <td class='column-entry-yellow'>
-DOWNGRADE1: 75.00% (9/12)
-DOWNGRADE1: <td class='column-entry-red'>
-DOWNGRADE1: 66.67% (4/6)
+DOWNGRADE1: 83.33% (10/12)
+DOWNGRADE1: <td class='column-entry-yellow'>
+DOWNGRADE1: 83.33% (5/6)
 DOWNGRADE1: <td class='column-entry-gray'>
 DOWNGRADE1: - (0/0)
 DOWNGRADE1: </tr>
@@ -51,9 +51,9 @@ DOWNGRADE2: 100.00% (2/2)
 DOWNGRADE2: <td class='column-entry-green'>
 DOWNGRADE2: 100.00% (3/3)
 DOWNGRADE2: <td class='column-entry-green'>
-DOWNGRADE2: 75.00% (9/12)
-DOWNGRADE2: <td class='column-entry-yellow'>
-DOWNGRADE2: 66.67% (4/6)
+DOWNGRADE2: 83.33% (10/12)
+DOWNGRADE2: <td class='column-entry-green'>
+DOWNGRADE2: 83.33% (5/6)
 DOWNGRADE1: <td class='column-entry-gray'>
 DOWNGRADE1: - (0/0)
 DOWNGRADE1: </tr>
diff --git a/llvm/test/tools/llvm-cov/zeroFunctionFile.c b/llvm/test/tools/llvm-cov/zeroFunctionFile.c
index f463007fe7f60f..28caa5ac241650 100644
--- a/llvm/test/tools/llvm-cov/zeroFunctionFile.c
+++ b/llvm/test/tools/llvm-cov/zeroFunctionFile.c
@@ -16,5 +16,4 @@ int main() {
 // RUN: llvm-cov show -j 1 %S/Inputs/zeroFunctionFile.covmapping -format html -instr-profile %t.profdata -o %t.dir
 // RUN: FileCheck %s -input-file=%t.dir/index.html -check-prefix=HTML
 // HTML-NO: 0.00% (0/0)
-// HTML: Files which contain no functions
-// HTML: zeroFunctionFile.h
+// HTML-NOT: Files which contain no functions
diff --git a/llvm/tools/llvm-cov/CoverageReport.cpp b/llvm/tools/llvm-cov/CoverageReport.cpp
index 00aea4039bfdeb..0046b968756dd0 100644
--- a/llvm/tools/llvm-cov/CoverageReport.cpp
+++ b/llvm/tools/llvm-cov/CoverageReport.cpp
@@ -446,27 +446,47 @@ void CoverageReport::prepareSingleFileReport(const StringRef Filename,
     const coverage::CoverageMapping *Coverage,
     const CoverageViewOptions &Options, const unsigned LCP,
     FileCoverageSummary *FileReport, const CoverageFilter *Filters) {
+  DenseSet<const coverage::FunctionRecord *> FilteredOutFunctions;
+  assert(FileReport->empty());
   for (const auto &Group : Coverage->getInstantiationGroups(Filename)) {
-    std::vector<FunctionCoverageSummary> InstantiationSummaries;
+    bool Updated = false;
     for (const coverage::FunctionRecord *F : Group.getInstantiations()) {
-      if (!Filters->matches(*Coverage, *F))
+      if (!Filters->matches(*Coverage, *F)) {
+        FilteredOutFunctions.insert(F);
         continue;
-      auto InstantiationSummary = FunctionCoverageSummary::get(*Coverage, *F);
-      FileReport->addInstantiation(InstantiationSummary);
-      InstantiationSummaries.push_back(InstantiationSummary);
+      }
+      FileReport->InstantiationCoverage.addFunction(
+          /*Covered=*/F->ExecutionCount > 0);
+      Updated = true;
     }
-    if (InstantiationSummaries.empty())
+    if (!Updated)
       continue;
 
-    auto GroupSummary =
-        FunctionCoverageSummary::get(Group, InstantiationSummaries);
+    if (Options.Debug) {
+      std::string Name;
+      if (Group.hasName()) {
+        Name = std::string(Group.getName());
+      } else {
+        llvm::raw_string_ostream OS(Name);
+        OS << "Definition at line " << Group.getLine() << ", column "
+           << Group.getColumn();
+      }
 
-    if (Options.Debug)
-      outs() << "InstantiationGroup: " << GroupSummary.Name << " with "
+      outs() << "InstantiationGroup: " << Name << " with "
              << "size = " << Group.size() << "\n";
+    }
 
-    FileReport->addFunction(GroupSummary);
+    FileReport->FunctionCoverage.addFunction(
+        /*Covered=*/Group.getTotalExecutionCount() > 0);
   }
+
+  auto FileCoverage =
+      Coverage->getCoverageForFile(Filename, FilteredOutFunctions);
+  if (FileCoverage.empty())
+    return;
+
+  *static_cast<CoverageDataSummary *>(FileReport) +=
+      CoverageDataSummary(FileCoverage);
 }
 
 std::vector<FileCoverageSummary> CoverageReport::prepareFileReports(
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
index 86d11266ecdd7c..745a92103bccc9 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp
@@ -110,29 +110,3 @@ FunctionCoverageSummary::get(const CoverageMapping &CM,
 
   return Summary;
 }
-
-FunctionCoverageSummary
-FunctionCoverageSummary::get(const InstantiationGroup &Group,
-                             ArrayRef<FunctionCoverageSummary> Summaries) {
-  std::string Name;
-  if (Group.hasName()) {
-    Name = std::string(Group.getName());
-  } else {
-    llvm::raw_string_ostream OS(Name);
-    OS << "Definition at line " << Group.getLine() << ", column "
-       << Group.getColumn();
-  }
-
-  FunctionCoverageSummary Summary(Name, Group.getTotalExecutionCount());
-  Summary.RegionCoverage = Summaries[0].RegionCoverage;
-  Summary.LineCoverage = Summaries[0].LineCoverage;
-  Summary.BranchCoverage = Summaries[0].BranchCoverage;
-  Summary.MCDCCoverage = Summaries[0].MCDCCoverage;
-  for (const auto &FCS : Summaries.drop_front()) {
-    Summary.RegionCoverage.merge(FCS.RegionCoverage);
-    Summary.LineCoverage.merge(FCS.LineCoverage);
-    Summary.BranchCoverage.merge(FCS.BranchCoverage);
-    Summary.MCDCCoverage.merge(FCS.MCDCCoverage);
-  }
-  return Summary;
-}
diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
index 42398ee06100e2..09ceba5de72719 100644
--- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h
+++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h
@@ -41,11 +41,6 @@ class RegionCoverageInfo {
     return *this;
   }
 
-  void merge(const RegionCoverageInfo &RHS) {
-    Covered = std::max(Covered, RHS.Covered);
-    NumRegions = std::max(NumRegions, RHS.NumRegions);
-  }
-
   size_t getCovered() const { return Covered; }
 
   size_t getNumRegions() const { return NumRegions; }
@@ -82,11 +77,6 @@ class LineCoverageInfo {
     return *this;
   }
 
-  void merge(const LineCoverageInfo &RHS) {
-    Covered = std::max(Covered, RHS.Covered);
-    NumLines = std::max(NumLines, RHS.NumLines);
-  }
-
   size_t getCovered() const { return Covered; }
 
   size_t getNumLines() const { return NumLines; }
@@ -123,11 +113,6 @@ class BranchCoverageInfo {
     return *this;
   }
 
-  void merge(const BranchCoverageInfo &RHS) {
-    Covered = std::max(Covered, RHS.Covered);
-    NumBranches = std::max(NumBranches, RHS.NumBranches);
-  }
-
   size_t getCovered() const { return Covered; }
 
   size_t getNumBranches() const { return NumBranches; }
@@ -164,11 +149,6 @@ class MCDCCoverageInfo {
     return *this;
   }
 
-  void merge(const MCDCCoverageInfo &RHS) {
-    CoveredPairs = std::max(CoveredPairs, RHS.CoveredPairs);
-    NumPairs = std::max(NumPairs, RHS.NumPairs);
-  }
-
   size_t getCoveredPairs() const { return CoveredPairs; }
 
   size_t getNumPairs() const { return NumPairs; }
@@ -232,6 +212,13 @@ struct CoverageDataSummary {
   CoverageDataSummary() = default;
   CoverageDataSummary(const coverage::CoverageData &CD);
 
+  bool empty() const {
+    return (RegionCoverage.getNumRegions() == 0 &&
+            LineCoverage.getNumLines() == 0 &&
+            BranchCoverage.getNumBranches() == 0 &&
+            MCDCCoverage.getNumPairs() == 0);
+  }
+
   auto &operator+=(const CoverageDataSummary &RHS) {
     RegionCoverage += RHS.RegionCoverage;
     LineCoverage += RHS.LineCoverage;
@@ -253,12 +240,6 @@ struct FunctionCoverageSummary : CoverageDataSummary {
   /// mapping record.
   static FunctionCoverageSummary get(const coverage::CoverageMapping &CM,
                                      const coverage::FunctionRecord &Function);
-
-  /// Compute the code coverage summary for an instantiation group \p Group,
-  /// given a list of summaries for each instantiation in \p Summaries.
-  static FunctionCoverageSummary
-  get(const coverage::InstantiationGroup &Group,
-      ArrayRef<FunctionCoverageSummary> Summaries);
 };
 
 /// A summary of file's code coverage.
@@ -270,24 +251,18 @@ struct FileCoverageSummary : CoverageDataSummary {
   FileCoverageSummary() = default;
   FileCoverageSummary(StringRef Name) : Name(Name) {}
 
+  bool empty() const {
+    return (CoverageDataSummary::empty() &&
+            FunctionCoverage.getNumFunctions() == 0 &&
+            InstantiationCoverage.getNumFunctions() == 0);
+  }
+
   FileCoverageSummary &operator+=(const FileCoverageSummary &RHS) {
     *static_cast<CoverageDataSummary *>(this) += RHS;
     FunctionCoverage += RHS.FunctionCoverage;
     InstantiationCoverage += RHS.InstantiationCoverage;
     return *this;
   }
-
-  void addFunction(const FunctionCoverageSummary &Function) {
-    RegionCoverage += Function.RegionCoverage;
-    LineCoverage += Function.LineCoverage;
-    BranchCoverage += Function.BranchCoverage;
-    MCDCCoverage += Function.MCDCCoverage;
-    FunctionCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0);
-  }
-
-  void addInstantiation(const FunctionCoverageSummary &Function) {
-    InstantiationCoverage.addFunction(/*Covered=*/Function.ExecutionCount > 0);
-  }
 };
 
 /// A cache for demangled symbols.
diff --git a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
index c94d3853fc0143..cb0ea6e0cdafc3 100644
--- a/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
+++ b/llvm/tools/llvm-cov/SourceCoverageViewHTML.cpp
@@ -23,6 +23,16 @@ using namespace llvm;
 
 namespace {
 
+template <class SummaryTy>
+bool IsSummaryEmpty(const SummaryTy &Report, const CoverageViewOptions &Opts) {
+  return !(Report.FunctionCoverage.getNumFunctions() ||
+           (Opts.ShowInstantiationSummary &&
+            Report.InstantiationCoverage.getNumFunctions()) ||
+           (Opts.ShowRegionSummary && Report.RegionCoverage.getNumRegions()) ||
+           (Opts.ShowBranchSummary && Report.BranchCoverage.getNumBranches()) ||
+           (Opts.ShowMCDCSummary && Report.MCDCCoverage.getNumPairs()));
+}
+
 // Return a string with the special characters in \p Str escaped.
 std::string escape(StringRef Str, const CoverageViewOptions &Opts) {
   std::string TabExpandedResult;
@@ -666,7 +676,7 @@ Error CoveragePrinterHTML::createIndexFile(
       Coverage, Totals, SourceFiles, Opts, Filters);
   bool EmptyFiles = false;
   for (unsigned I = 0, E = FileReports.size(); I < E; ++I) {
-    if (FileReports[I].FunctionCoverage.getNumFunctions())
+    if (!IsSummaryEmpty(FileReports[I], Opts))
       emitFileSummary(OSRef, SourceFiles[I], FileReports[I]);
     else
       EmptyFiles = true;
@@ -734,7 +744,7 @@ struct CoveragePrinterHTMLDirectory::Reporter : public DirectoryCoverageReport {
     // Make directories at the top of the table.
     for (auto &&SubDir : SubDirs) {
       auto &Report = SubDir.second.first;
-      if (!Report.FunctionCoverage.getNumFunctions())
+      if (IsSummaryEmpty(Report, Printer.Opts))
         EmptyFiles.push_back(&Report);
       else
         emitTableRow(OSRef, Options, buildRelLinkToFile(Report.Name), Report,
@@ -743,7 +753,7 @@ struct CoveragePrinterHTMLDirectory::Reporter : public DirectoryCoverageReport {
 
     for (auto &&SubFile : SubFiles) {
       auto &Report = SubFile.second;
-      if (!Report.FunctionCoverage.getNumFunctions())
+      if (IsSummaryEmpty(Report, Printer.Opts))
         EmptyFiles.push_back(&Report);
       else
         emitTableRow(OSRef, Options, buildRelLinkToFile(Report.Name), Report,

@@ -23,6 +23,16 @@ using namespace llvm;

namespace {

template <class SummaryTy>
bool IsSummaryEmpty(const SummaryTy &Report, const CoverageViewOptions &Opts) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function name case should be isSummaryEmpty

@@ -23,6 +23,16 @@ using namespace llvm;

namespace {

template <class SummaryTy>
bool IsSummaryEmpty(const SummaryTy &Report, const CoverageViewOptions &Opts) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

case should be isSummaryEmpty

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@ornata
Copy link

ornata commented Jan 6, 2025

"Merge" facilities with std::max are removed as well for now.

why?

@@ -1432,6 +1434,8 @@ CoverageData CoverageMapping::getCoverageForFile(StringRef Filename) const {
getImpreciseRecordIndicesForFilename(Filename);
for (unsigned RecordIndex : RecordIndices) {
const FunctionRecord &Function = Functions[RecordIndex];
if (FilteredOutFunctions.count(&Function))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the commit message, it is not obvious to me why we are now filtering out functions. Can you explain?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The caller, llvm-cov, has the filter. I chose "blacklist" (rather than whitelist) since it is expected empty in usual cases.

@chapuni
Copy link
Contributor Author

chapuni commented Jan 6, 2025

"Merge" facilities with std::max are removed as well for now.

why?

They will be reintroduced later, "Any" in #121194 .
To be honest, I didn't imagine the way to preserve the old behavior.
For now, this change introduces "Merge" behavior partially.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

llvm-cov show HTML: Inconsistent results between per-file indices and each source file view
3 participants