diff options
-rw-r--r-- | include/llvm/ProfileData/Coverage/CoverageMapping.h | 83 | ||||
-rw-r--r-- | lib/ProfileData/Coverage/CoverageMapping.cpp | 53 | ||||
-rw-r--r-- | tools/llvm-cov/CoverageSummaryInfo.cpp | 53 | ||||
-rw-r--r-- | tools/llvm-cov/CoverageSummaryInfo.h | 89 | ||||
-rw-r--r-- | unittests/ProfileData/CoverageMappingTest.cpp | 57 |
5 files changed, 193 insertions, 142 deletions
diff --git a/include/llvm/ProfileData/Coverage/CoverageMapping.h b/include/llvm/ProfileData/Coverage/CoverageMapping.h index 22286f6d468..5a4098cf666 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -594,6 +594,89 @@ public: getInstantiationGroups(StringRef Filename) const; }; +/// Coverage statistics for a single line. +class LineCoverageStats { + uint64_t ExecutionCount; + bool HasMultipleRegions; + bool Mapped; + unsigned Line; + ArrayRef<const CoverageSegment *> LineSegments; + const CoverageSegment *WrappedSegment; + + friend class LineCoverageIterator; + LineCoverageStats() = default; + +public: + LineCoverageStats(ArrayRef<const CoverageSegment *> LineSegments, + const CoverageSegment *WrappedSegment, unsigned Line); + + uint64_t getExecutionCount() const { return ExecutionCount; } + + bool hasMultipleRegions() const { return HasMultipleRegions; } + + bool isMapped() const { return Mapped; } + + unsigned getLine() const { return Line; } + + ArrayRef<const CoverageSegment *> getLineSegments() const { + return LineSegments; + } + + const CoverageSegment *getWrappedSegment() const { return WrappedSegment; } +}; + +/// An iterator over the \c LineCoverageStats objects for lines described by +/// a \c CoverageData instance. +class LineCoverageIterator + : public iterator_facade_base< + LineCoverageIterator, std::forward_iterator_tag, LineCoverageStats> { +public: + LineCoverageIterator(const CoverageData &CD) + : LineCoverageIterator(CD, CD.begin()->Line) {} + + LineCoverageIterator(const CoverageData &CD, unsigned Line) + : CD(CD), WrappedSegment(nullptr), Next(CD.begin()), Ended(false), + Line(Line), Segments(), Stats() { + this->operator++(); + } + + LineCoverageIterator &operator=(const LineCoverageIterator &R) = default; + + bool operator==(const LineCoverageIterator &R) const { + return &CD == &R.CD && Next == R.Next && Ended == R.Ended; + } + + const LineCoverageStats &operator*() const { return Stats; } + + LineCoverageStats &operator*() { return Stats; } + + LineCoverageIterator &operator++(); + + LineCoverageIterator getEnd() const { + auto EndIt = *this; + EndIt.Next = CD.end(); + EndIt.Ended = true; + return EndIt; + } + +private: + const CoverageData &CD; + const CoverageSegment *WrappedSegment; + std::vector<CoverageSegment>::const_iterator Next; + bool Ended; + unsigned Line; + SmallVector<const CoverageSegment *, 4> Segments; + LineCoverageStats Stats; +}; + +/// Get a \c LineCoverageIterator range for the lines described by \p CD. +static inline iterator_range<LineCoverageIterator> +getLineCoverageStats(const coverage::CoverageData &CD) { + auto Begin = LineCoverageIterator(CD); + auto End = Begin.getEnd(); + return make_range(Begin, End); +} + // Profile coverage map has the following layout: // [CoverageMapFileHeader] // [ArrayStart] diff --git a/lib/ProfileData/Coverage/CoverageMapping.cpp b/lib/ProfileData/Coverage/CoverageMapping.cpp index 52f9447aa3e..bda61768e7b 100644 --- a/lib/ProfileData/Coverage/CoverageMapping.cpp +++ b/lib/ProfileData/Coverage/CoverageMapping.cpp @@ -671,6 +671,59 @@ CoverageData CoverageMapping::getCoverageForExpansion( return ExpansionCoverage; } +LineCoverageStats::LineCoverageStats( + ArrayRef<const coverage::CoverageSegment *> LineSegments, + const coverage::CoverageSegment *WrappedSegment, unsigned Line) + : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line), + LineSegments(LineSegments), WrappedSegment(WrappedSegment) { + // Find the minimum number of regions which start in this line. + unsigned MinRegionCount = 0; + auto isStartOfRegion = [](const coverage::CoverageSegment *S) { + return !S->IsGapRegion && S->HasCount && S->IsRegionEntry; + }; + for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I) + if (isStartOfRegion(LineSegments[I])) + ++MinRegionCount; + + bool StartOfSkippedRegion = !LineSegments.empty() && + !LineSegments.front()->HasCount && + LineSegments.front()->IsRegionEntry; + + HasMultipleRegions = MinRegionCount > 1; + Mapped = + !StartOfSkippedRegion && + ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0)); + + if (!Mapped) + return; + + // Pick the max count from the non-gap, region entry segments. If there + // aren't any, use the wrapped count. + if (!MinRegionCount) { + ExecutionCount = WrappedSegment->Count; + return; + } + for (const auto *LS : LineSegments) + if (isStartOfRegion(LS)) + ExecutionCount = std::max(ExecutionCount, LS->Count); +} + +LineCoverageIterator &LineCoverageIterator::operator++() { + if (Next == CD.end()) { + Stats = LineCoverageStats(); + Ended = true; + return *this; + } + if (Segments.size()) + WrappedSegment = Segments.back(); + Segments.clear(); + while (Next != CD.end() && Next->Line == Line) + Segments.push_back(&*Next++); + Stats = LineCoverageStats(Segments, WrappedSegment, Line); + ++Line; + return *this; +} + static std::string getCoverageMapErrString(coveragemap_error Err) { switch (Err) { case coveragemap_error::success: diff --git a/tools/llvm-cov/CoverageSummaryInfo.cpp b/tools/llvm-cov/CoverageSummaryInfo.cpp index d1fcef4299d..7847a2abf48 100644 --- a/tools/llvm-cov/CoverageSummaryInfo.cpp +++ b/tools/llvm-cov/CoverageSummaryInfo.cpp @@ -17,59 +17,6 @@ using namespace llvm; using namespace coverage; -LineCoverageStats::LineCoverageStats( - ArrayRef<const coverage::CoverageSegment *> LineSegments, - const coverage::CoverageSegment *WrappedSegment, unsigned Line) - : ExecutionCount(0), HasMultipleRegions(false), Mapped(false), Line(Line), - LineSegments(LineSegments), WrappedSegment(WrappedSegment) { - // Find the minimum number of regions which start in this line. - unsigned MinRegionCount = 0; - auto isStartOfRegion = [](const coverage::CoverageSegment *S) { - return !S->IsGapRegion && S->HasCount && S->IsRegionEntry; - }; - for (unsigned I = 0; I < LineSegments.size() && MinRegionCount < 2; ++I) - if (isStartOfRegion(LineSegments[I])) - ++MinRegionCount; - - bool StartOfSkippedRegion = !LineSegments.empty() && - !LineSegments.front()->HasCount && - LineSegments.front()->IsRegionEntry; - - HasMultipleRegions = MinRegionCount > 1; - Mapped = - !StartOfSkippedRegion && - ((WrappedSegment && WrappedSegment->HasCount) || (MinRegionCount > 0)); - - if (!Mapped) - return; - - // Pick the max count from the non-gap, region entry segments. If there - // aren't any, use the wrapped count. - if (!MinRegionCount) { - ExecutionCount = WrappedSegment->Count; - return; - } - for (const auto *LS : LineSegments) - if (isStartOfRegion(LS)) - ExecutionCount = std::max(ExecutionCount, LS->Count); -} - -LineCoverageIterator &LineCoverageIterator::operator++() { - if (Next == CD.end()) { - Stats = LineCoverageStats(); - Ended = true; - return *this; - } - if (Segments.size()) - WrappedSegment = Segments.back(); - Segments.clear(); - while (Next != CD.end() && Next->Line == Line) - Segments.push_back(&*Next++); - Stats = LineCoverageStats(Segments, WrappedSegment, Line); - ++Line; - return *this; -} - FunctionCoverageSummary FunctionCoverageSummary::get(const CoverageMapping &CM, const coverage::FunctionRecord &Function) { diff --git a/tools/llvm-cov/CoverageSummaryInfo.h b/tools/llvm-cov/CoverageSummaryInfo.h index d3f43d19104..8eae0b7fec9 100644 --- a/tools/llvm-cov/CoverageSummaryInfo.h +++ b/tools/llvm-cov/CoverageSummaryInfo.h @@ -15,8 +15,6 @@ #ifndef LLVM_COV_COVERAGESUMMARYINFO_H #define LLVM_COV_COVERAGESUMMARYINFO_H -#include "llvm/ADT/iterator.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/Support/raw_ostream.h" @@ -138,93 +136,6 @@ public: } }; -/// \brief Coverage statistics for a single line. -class LineCoverageStats { - uint64_t ExecutionCount; - bool HasMultipleRegions; - bool Mapped; - unsigned Line; - ArrayRef<const coverage::CoverageSegment *> LineSegments; - const coverage::CoverageSegment *WrappedSegment; - - friend class LineCoverageIterator; - LineCoverageStats() = default; - -public: - LineCoverageStats(ArrayRef<const coverage::CoverageSegment *> LineSegments, - const coverage::CoverageSegment *WrappedSegment, - unsigned Line); - - uint64_t getExecutionCount() const { return ExecutionCount; } - - bool hasMultipleRegions() const { return HasMultipleRegions; } - - bool isMapped() const { return Mapped; } - - unsigned getLine() const { return Line; } - - ArrayRef<const coverage::CoverageSegment *> getLineSegments() const { - return LineSegments; - } - - const coverage::CoverageSegment *getWrappedSegment() const { - return WrappedSegment; - } -}; - -/// Iterates over LineCoverageStats for each line described by a CoverageData -/// object. -class LineCoverageIterator - : public iterator_facade_base< - LineCoverageIterator, std::forward_iterator_tag, LineCoverageStats> { -public: - LineCoverageIterator(const coverage::CoverageData &CD) - : LineCoverageIterator(CD, CD.begin()->Line) {} - - LineCoverageIterator(const coverage::CoverageData &CD, unsigned Line) - : CD(CD), WrappedSegment(nullptr), Next(CD.begin()), Ended(false), - Line(Line), Segments(), Stats() { - this->operator++(); - } - - LineCoverageIterator &operator=(const LineCoverageIterator &R) = default; - - bool operator==(const LineCoverageIterator &R) const { - return &CD == &R.CD && Next == R.Next && Ended == R.Ended; - } - - const LineCoverageStats &operator*() const { return Stats; } - - LineCoverageStats &operator*() { return Stats; } - - LineCoverageIterator &operator++(); - - LineCoverageIterator getEnd() const { - auto EndIt = *this; - EndIt.Next = CD.end(); - EndIt.Ended = true; - return EndIt; - } - -private: - const coverage::CoverageData &CD; - const coverage::CoverageSegment *WrappedSegment; - std::vector<coverage::CoverageSegment>::const_iterator Next; - bool Ended; - unsigned Line; - SmallVector<const coverage::CoverageSegment *, 4> Segments; - LineCoverageStats Stats; -}; - -/// Get a range of LineCoverageStats for each line described by a CoverageData -/// object. -static inline iterator_range<LineCoverageIterator> -getLineCoverageStats(const coverage::CoverageData &CD) { - auto Begin = LineCoverageIterator(CD); - auto End = Begin.getEnd(); - return make_range(Begin, End); -} - /// \brief A summary of function's code coverage. struct FunctionCoverageSummary { std::string Name; diff --git a/unittests/ProfileData/CoverageMappingTest.cpp b/unittests/ProfileData/CoverageMappingTest.cpp index 8c9c8c48234..ad0a0cfb873 100644 --- a/unittests/ProfileData/CoverageMappingTest.cpp +++ b/unittests/ProfileData/CoverageMappingTest.cpp @@ -635,6 +635,63 @@ TEST_P(CoverageMappingTest, basic_coverage_iteration) { ASSERT_EQ(CoverageSegment(11, 11, false), Segments[6]); } +TEST_P(CoverageMappingTest, test_line_coverage_iterator) { + ProfileWriter.addRecord({"func", 0x1234, {30, 20, 10, 0}}, Err); + + startFunction("func", 0x1234); + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(1), "file1", 1, 1, 4, 7); + addCMR(Counter::getCounter(2), "file1", 5, 8, 9, 1); + addCMR(Counter::getCounter(3), "file1", 10, 10, 11, 11); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); + + CoverageData Data = LoadedCoverage->getCoverageForFile("file1"); + + unsigned NumLineStats = 0; + for (const auto &LCS : getLineCoverageStats(Data)) { + ++NumLineStats; + (void)LCS; + } + ASSERT_EQ(11U, NumLineStats); + + LineCoverageIterator LCI{Data}; + + ASSERT_EQ(1U, LCI->getLine()); + ASSERT_EQ(20ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(2U, LCI->getLine()); + ASSERT_EQ(20ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(3U, LCI->getLine()); + ASSERT_EQ(20ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(4U, LCI->getLine()); + ASSERT_EQ(20ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(5U, LCI->getLine()); + ASSERT_EQ(10ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(6U, LCI->getLine()); + ASSERT_EQ(10ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(7U, LCI->getLine()); + ASSERT_EQ(10ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(8U, LCI->getLine()); + ASSERT_EQ(10ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(9U, LCI->getLine()); + ASSERT_EQ(10ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(10U, LCI->getLine()); + ASSERT_EQ(0ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(11U, LCI->getLine()); + ASSERT_EQ(0ULL, LCI->getExecutionCount()); + ++LCI; + ASSERT_EQ(LCI, LCI.getEnd()); +} + TEST_P(CoverageMappingTest, uncovered_function) { startFunction("func", 0x1234); addCMR(Counter::getZero(), "file1", 1, 2, 3, 4); |