[llvm] r309904 - [Coverage] Add an API to retrive all instantiations of a function (NFC)

Vedant Kumar via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 2 16:35:25 PDT 2017


Author: vedantk
Date: Wed Aug  2 16:35:25 2017
New Revision: 309904

URL: http://llvm.org/viewvc/llvm-project?rev=309904&view=rev
Log:
[Coverage] Add an API to retrive all instantiations of a function (NFC)

The CoverageMapping::getInstantiations() API retrieved all function
records corresponding to functions with more than one instantiation (e.g
template functions with multiple specializations). However, there was no
simple way to determine *which* function a given record was an
instantiation of. This was an oversight, since it's useful to aggregate
coverage information over all instantiations of a function.

llvm-cov works around this by building a mapping of source locations to
instantiation sets, but this duplicates logic that libCoverage already
has (see FunctionInstantiationSetCollector).

This change adds a new API, CoverageMapping::getInstantiationGroups(),
which returns a list of InstantiationGroups. A group contains records
for each instantiation of some particular function, and also provides
utilities to get the total execution count within the group, the source
location of the common definition, etc.

This lets removes some hacky logic in llvm-cov by reusing
FunctionInstantiationSetCollector and makes the CoverageMapping API
friendlier for other clients.

Modified:
    llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h
    llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp
    llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
    llvm/trunk/tools/llvm-cov/CoverageReport.cpp
    llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp
    llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h
    llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp

Modified: llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h?rev=309904&r1=309903&r2=309904&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h (original)
+++ llvm/trunk/include/llvm/ProfileData/Coverage/CoverageMapping.h Wed Aug  2 16:35:25 2017
@@ -396,6 +396,63 @@ struct CoverageSegment {
   }
 };
 
+/// An instantiation group contains a \c FunctionRecord list, such that each
+/// record corresponds to a distinct instantiation of the same function.
+///
+/// Note that it's possible for a function to have more than one instantiation
+/// (consider C++ template specializations or static inline functions).
+class InstantiationGroup {
+  friend class CoverageMapping;
+
+  unsigned Line;
+  unsigned Col;
+  std::vector<const FunctionRecord *> Instantiations;
+
+  InstantiationGroup(unsigned Line, unsigned Col,
+                     std::vector<const FunctionRecord *> Instantiations)
+      : Line(Line), Col(Col), Instantiations(std::move(Instantiations)) {}
+
+public:
+  InstantiationGroup(const InstantiationGroup &) = delete;
+  InstantiationGroup(InstantiationGroup &&) = default;
+
+  /// Get the number of instantiations in this group.
+  size_t size() const { return Instantiations.size(); }
+
+  /// Get the line where the common function was defined.
+  unsigned getLine() const { return Line; }
+
+  /// Get the column where the common function was defined.
+  unsigned getColumn() const { return Col; }
+
+  /// Check if the instantiations in this group have a common mangled name.
+  bool hasName() const {
+    for (unsigned I = 1, E = Instantiations.size(); I < E; ++I)
+      if (Instantiations[I]->Name != Instantiations[0]->Name)
+        return false;
+    return true;
+  }
+
+  /// Get the common mangled name for instantiations in this group.
+  StringRef getName() const {
+    assert(hasName() && "Instantiations don't have a shared name");
+    return Instantiations[0]->Name;
+  }
+
+  /// Get the total execution count of all instantiations in this group.
+  uint64_t getTotalExecutionCount() const {
+    uint64_t Count = 0;
+    for (const FunctionRecord *F : Instantiations)
+      Count += F->ExecutionCount;
+    return Count;
+  }
+
+  /// Get the instantiations in this group.
+  ArrayRef<const FunctionRecord *> getInstantiations() const {
+    return Instantiations;
+  }
+};
+
 /// \brief Coverage information to be processed or displayed.
 ///
 /// This represents the coverage of an entire file, expansion, or function. It
@@ -490,12 +547,12 @@ public:
                       FunctionRecordIterator());
   }
 
-  /// \brief Get the list of function instantiations in the file.
+  /// Get the list of function instantiation groups in a particular file.
   ///
-  /// Functions that are instantiated more than once, such as C++ template
-  /// specializations, have distinct coverage records for each instantiation.
-  std::vector<const FunctionRecord *>
-  getInstantiations(StringRef Filename) const;
+  /// Every instantiation group in a program is attributed to exactly one file:
+  /// the file in which the definition for the common function begins.
+  std::vector<InstantiationGroup>
+  getInstantiationGroups(StringRef Filename) const;
 
   /// \brief Get the coverage for a particular function.
   CoverageData getCoverageForFunction(const FunctionRecord &Function) const;

Modified: llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp?rev=309904&r1=309903&r2=309904&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp (original)
+++ llvm/trunk/lib/ProfileData/Coverage/CoverageMapping.cpp Wed Aug  2 16:35:25 2017
@@ -510,8 +510,8 @@ CoverageData CoverageMapping::getCoverag
   return FileCoverage;
 }
 
-std::vector<const FunctionRecord *>
-CoverageMapping::getInstantiations(StringRef Filename) const {
+std::vector<InstantiationGroup>
+CoverageMapping::getInstantiationGroups(StringRef Filename) const {
   FunctionInstantiationSetCollector InstantiationSetCollector;
   for (const auto &Function : Functions) {
     auto MainFileID = findMainViewFileID(Filename, Function);
@@ -520,12 +520,12 @@ CoverageMapping::getInstantiations(Strin
     InstantiationSetCollector.insert(Function, *MainFileID);
   }
 
-  std::vector<const FunctionRecord *> Result;
+  std::vector<InstantiationGroup> Result;
   for (const auto &InstantiationSet : InstantiationSetCollector) {
-    if (InstantiationSet.second.size() < 2)
-      continue;
-    Result.insert(Result.end(), InstantiationSet.second.begin(),
-                  InstantiationSet.second.end());
+    InstantiationGroup IG{InstantiationSet.first.first,
+                          InstantiationSet.first.second,
+                          std::move(InstantiationSet.second)};
+    Result.emplace_back(std::move(IG));
   }
   return Result;
 }

Modified: llvm/trunk/tools/llvm-cov/CodeCoverage.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CodeCoverage.cpp?rev=309904&r1=309903&r2=309904&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CodeCoverage.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CodeCoverage.cpp Wed Aug  2 16:35:25 2017
@@ -291,25 +291,31 @@ CodeCoverageTool::createSourceFileView(S
   if (!ViewOpts.ShowFunctionInstantiations)
     return View;
 
-  for (const auto *Function : Coverage.getInstantiations(SourceFile)) {
-    std::unique_ptr<SourceCoverageView> SubView{nullptr};
+  for (const auto &Group : Coverage.getInstantiationGroups(SourceFile)) {
+    // Skip functions which have a single instantiation.
+    if (Group.size() < 2)
+      continue;
 
-    StringRef Funcname = DC.demangle(Function->Name);
+    for (const FunctionRecord *Function : Group.getInstantiations()) {
+      std::unique_ptr<SourceCoverageView> SubView{nullptr};
 
-    if (Function->ExecutionCount > 0) {
-      auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
-      auto SubViewExpansions = SubViewCoverage.getExpansions();
-      SubView = SourceCoverageView::create(
-          Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
-      attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
-    }
+      StringRef Funcname = DC.demangle(Function->Name);
+
+      if (Function->ExecutionCount > 0) {
+        auto SubViewCoverage = Coverage.getCoverageForFunction(*Function);
+        auto SubViewExpansions = SubViewCoverage.getExpansions();
+        SubView = SourceCoverageView::create(
+            Funcname, SourceBuffer.get(), ViewOpts, std::move(SubViewCoverage));
+        attachExpansionSubViews(*SubView, SubViewExpansions, Coverage);
+      }
 
-    unsigned FileID = Function->CountedRegions.front().FileID;
-    unsigned Line = 0;
-    for (const auto &CR : Function->CountedRegions)
-      if (CR.FileID == FileID)
-        Line = std::max(CR.LineEnd, Line);
-    View->addInstantiation(Funcname, Line, std::move(SubView));
+      unsigned FileID = Function->CountedRegions.front().FileID;
+      unsigned Line = 0;
+      for (const auto &CR : Function->CountedRegions)
+        if (CR.FileID == FileID)
+          Line = std::max(CR.LineEnd, Line);
+      View->addInstantiation(Funcname, Line, std::move(SubView));
+    }
   }
   return View;
 }

Modified: llvm/trunk/tools/llvm-cov/CoverageReport.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageReport.cpp?rev=309904&r1=309903&r2=309904&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageReport.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CoverageReport.cpp Wed Aug  2 16:35:25 2017
@@ -317,25 +317,19 @@ CoverageReport::prepareFileReports(const
   for (StringRef Filename : Files) {
     FileCoverageSummary Summary(Filename.drop_front(LCP));
 
-    // Map source locations to aggregate function coverage summaries.
-    DenseMap<std::pair<unsigned, unsigned>, FunctionCoverageSummary> Summaries;
-
-    for (const auto &F : Coverage.getCoveredFunctions(Filename)) {
-      FunctionCoverageSummary Function = FunctionCoverageSummary::get(F);
-      auto StartLoc = F.CountedRegions[0].startLoc();
-
-      auto UniquedSummary = Summaries.insert({StartLoc, Function});
-      if (!UniquedSummary.second)
-        UniquedSummary.first->second.update(Function);
-
-      Summary.addInstantiation(Function);
-      Totals.addInstantiation(Function);
-    }
-
-    for (const auto &UniquedSummary : Summaries) {
-      const FunctionCoverageSummary &FCS = UniquedSummary.second;
-      Summary.addFunction(FCS);
-      Totals.addFunction(FCS);
+    for (const auto &Group : Coverage.getInstantiationGroups(Filename)) {
+      std::vector<FunctionCoverageSummary> InstantiationSummaries;
+      for (const coverage::FunctionRecord *F : Group.getInstantiations()) {
+        auto InstantiationSummary = FunctionCoverageSummary::get(*F);
+        Summary.addInstantiation(InstantiationSummary);
+        Totals.addInstantiation(InstantiationSummary);
+        InstantiationSummaries.push_back(InstantiationSummary);
+      }
+
+      auto GroupSummary =
+          FunctionCoverageSummary::get(Group, InstantiationSummaries);
+      Summary.addFunction(GroupSummary);
+      Totals.addFunction(GroupSummary);
     }
 
     FileReports.push_back(Summary);

Modified: llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp?rev=309904&r1=309903&r2=309904&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp (original)
+++ llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.cpp Wed Aug  2 16:35:25 2017
@@ -70,14 +70,31 @@ FunctionCoverageSummary::get(const cover
       LineCoverageInfo(CoveredLines, NumLines));
 }
 
-void FunctionCoverageSummary::update(const FunctionCoverageSummary &Summary) {
-  ExecutionCount += Summary.ExecutionCount;
-  RegionCoverage.Covered =
-      std::max(RegionCoverage.Covered, Summary.RegionCoverage.Covered);
-  RegionCoverage.NotCovered =
-      std::min(RegionCoverage.NotCovered, Summary.RegionCoverage.NotCovered);
-  LineCoverage.Covered =
-      std::max(LineCoverage.Covered, Summary.LineCoverage.Covered);
-  LineCoverage.NotCovered =
-      std::min(LineCoverage.NotCovered, Summary.LineCoverage.NotCovered);
+FunctionCoverageSummary
+FunctionCoverageSummary::get(const InstantiationGroup &Group,
+                             ArrayRef<FunctionCoverageSummary> Summaries) {
+  std::string Name;
+  if (Group.hasName()) {
+    Name = Group.getName();
+  } else {
+    llvm::raw_string_ostream OS(Name);
+    OS << "Definition at line " << Group.getLine() << ", column "
+       << Group.getColumn();
+  }
+
+  FunctionCoverageSummary Summary(std::move(Name));
+  Summary.ExecutionCount = Group.getTotalExecutionCount();
+  Summary.RegionCoverage = Summaries[0].RegionCoverage;
+  Summary.LineCoverage = Summaries[0].LineCoverage;
+  for (const auto &FCS : Summaries.drop_front()) {
+    Summary.RegionCoverage.Covered =
+        std::max(FCS.RegionCoverage.Covered, Summary.RegionCoverage.Covered);
+    Summary.RegionCoverage.NotCovered = std::min(
+        FCS.RegionCoverage.NotCovered, Summary.RegionCoverage.NotCovered);
+    Summary.LineCoverage.Covered =
+        std::max(FCS.LineCoverage.Covered, Summary.LineCoverage.Covered);
+    Summary.LineCoverage.NotCovered =
+        std::min(FCS.LineCoverage.NotCovered, Summary.LineCoverage.NotCovered);
+  }
+  return Summary;
 }

Modified: llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h?rev=309904&r1=309903&r2=309904&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h (original)
+++ llvm/trunk/tools/llvm-cov/CoverageSummaryInfo.h Wed Aug  2 16:35:25 2017
@@ -115,7 +115,7 @@ struct FunctionCoverageInfo {
 
 /// \brief A summary of function's code coverage.
 struct FunctionCoverageSummary {
-  StringRef Name;
+  std::string Name;
   uint64_t ExecutionCount;
   RegionCoverageInfo RegionCoverage;
   LineCoverageInfo LineCoverage;
@@ -134,9 +134,11 @@ struct FunctionCoverageSummary {
   static FunctionCoverageSummary
   get(const coverage::FunctionRecord &Function);
 
-  /// \brief Update the summary with information from another instantiation
-  /// of this function.
-  void update(const FunctionCoverageSummary &Summary);
+  /// 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);
 };
 
 /// \brief A summary of file's code coverage.

Modified: llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp?rev=309904&r1=309903&r2=309904&view=diff
==============================================================================
--- llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp (original)
+++ llvm/trunk/unittests/ProfileData/CoverageMappingTest.cpp Wed Aug  2 16:35:25 2017
@@ -548,9 +548,10 @@ TEST_P(CoverageMappingTest, dont_detect_
 
   EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded());
 
-  std::vector<const FunctionRecord *> Instantiations =
-      LoadedCoverage->getInstantiations("expanded");
-  ASSERT_TRUE(Instantiations.empty());
+  std::vector<InstantiationGroup> InstantiationGroups =
+      LoadedCoverage->getInstantiationGroups("expanded");
+  for (const auto &Group : InstantiationGroups)
+    ASSERT_EQ(Group.size(), 1U);
 }
 
 TEST_P(CoverageMappingTest, load_coverage_for_expanded_file) {




More information about the llvm-commits mailing list