diff options
Diffstat (limited to 'include/llvm/ProfileData/Coverage')
-rw-r--r-- | include/llvm/ProfileData/Coverage/CoverageMapping.h | 346 | ||||
-rw-r--r-- | include/llvm/ProfileData/Coverage/CoverageMappingReader.h | 32 |
2 files changed, 289 insertions, 89 deletions
diff --git a/include/llvm/ProfileData/Coverage/CoverageMapping.h b/include/llvm/ProfileData/Coverage/CoverageMapping.h index fa9a87aed6806..5a4098cf666c4 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -85,7 +85,7 @@ private: coveragemap_error Err; }; -/// \brief A Counter is an abstract value that describes how to compute the +/// A Counter is an abstract value that describes how to compute the /// execution count for a region of code using the collected profile count data. struct Counter { enum CounterKind { Zero, CounterValueReference, Expression }; @@ -125,23 +125,23 @@ public: return std::tie(LHS.Kind, LHS.ID) < std::tie(RHS.Kind, RHS.ID); } - /// \brief Return the counter that represents the number zero. + /// Return the counter that represents the number zero. static Counter getZero() { return Counter(); } - /// \brief Return the counter that corresponds to a specific profile counter. + /// Return the counter that corresponds to a specific profile counter. static Counter getCounter(unsigned CounterId) { return Counter(CounterValueReference, CounterId); } - /// \brief Return the counter that corresponds to a specific - /// addition counter expression. + /// Return the counter that corresponds to a specific addition counter + /// expression. static Counter getExpression(unsigned ExpressionId) { return Counter(Expression, ExpressionId); } }; -/// \brief A Counter expression is a value that represents an arithmetic -/// operation with two counters. +/// A Counter expression is a value that represents an arithmetic operation +/// with two counters. struct CounterExpression { enum ExprKind { Subtract, Add }; ExprKind Kind; @@ -151,17 +151,16 @@ struct CounterExpression { : Kind(Kind), LHS(LHS), RHS(RHS) {} }; -/// \brief A Counter expression builder is used to construct the -/// counter expressions. It avoids unnecessary duplication -/// and simplifies algebraic expressions. +/// A Counter expression builder is used to construct the counter expressions. +/// It avoids unnecessary duplication and simplifies algebraic expressions. class CounterExpressionBuilder { - /// \brief A list of all the counter expressions + /// A list of all the counter expressions std::vector<CounterExpression> Expressions; - /// \brief A lookup table for the index of a given expression. + /// A lookup table for the index of a given expression. DenseMap<CounterExpression, unsigned> ExpressionIndices; - /// \brief Return the counter which corresponds to the given expression. + /// Return the counter which corresponds to the given expression. /// /// If the given expression is already stored in the builder, a counter /// that references that expression is returned. Otherwise, the given @@ -177,44 +176,48 @@ class CounterExpressionBuilder { : CounterID(CounterID), Factor(Factor) {} }; - /// \brief Gather the terms of the expression tree for processing. + /// Gather the terms of the expression tree for processing. /// /// This collects each addition and subtraction referenced by the counter into /// a sequence that can be sorted and combined to build a simplified counter /// expression. void extractTerms(Counter C, int Sign, SmallVectorImpl<Term> &Terms); - /// \brief Simplifies the given expression tree + /// Simplifies the given expression tree /// by getting rid of algebraically redundant operations. Counter simplify(Counter ExpressionTree); public: ArrayRef<CounterExpression> getExpressions() const { return Expressions; } - /// \brief Return a counter that represents the expression - /// that adds LHS and RHS. + /// Return a counter that represents the expression that adds LHS and RHS. Counter add(Counter LHS, Counter RHS); - /// \brief Return a counter that represents the expression - /// that subtracts RHS from LHS. + /// Return a counter that represents the expression that subtracts RHS from + /// LHS. Counter subtract(Counter LHS, Counter RHS); }; -/// \brief A Counter mapping region associates a source range with -/// a specific counter. +using LineColPair = std::pair<unsigned, unsigned>; + +/// A Counter mapping region associates a source range with a specific counter. struct CounterMappingRegion { enum RegionKind { - /// \brief A CodeRegion associates some code with a counter + /// A CodeRegion associates some code with a counter CodeRegion, - /// \brief An ExpansionRegion represents a file expansion region that - /// associates a source range with the expansion of a virtual source file, - /// such as for a macro instantiation or #include file. + /// An ExpansionRegion represents a file expansion region that associates + /// a source range with the expansion of a virtual source file, such as + /// for a macro instantiation or #include file. ExpansionRegion, - /// \brief A SkippedRegion represents a source range with code that - /// was skipped by a preprocessor or similar means. - SkippedRegion + /// A SkippedRegion represents a source range with code that was skipped + /// by a preprocessor or similar means. + SkippedRegion, + + /// A GapRegion is like a CodeRegion, but its count is only set as the + /// line execution count when its the only region in the line. + GapRegion }; Counter Count; @@ -251,16 +254,21 @@ struct CounterMappingRegion { LineEnd, ColumnEnd, SkippedRegion); } - inline std::pair<unsigned, unsigned> startLoc() const { - return std::pair<unsigned, unsigned>(LineStart, ColumnStart); + static CounterMappingRegion + makeGapRegion(Counter Count, unsigned FileID, unsigned LineStart, + unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { + return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart, + LineEnd, (1U << 31) | ColumnEnd, GapRegion); } - inline std::pair<unsigned, unsigned> endLoc() const { - return std::pair<unsigned, unsigned>(LineEnd, ColumnEnd); + inline LineColPair startLoc() const { + return LineColPair(LineStart, ColumnStart); } + + inline LineColPair endLoc() const { return LineColPair(LineEnd, ColumnEnd); } }; -/// \brief Associates a source range with an execution count. +/// Associates a source range with an execution count. struct CountedRegion : public CounterMappingRegion { uint64_t ExecutionCount; @@ -268,8 +276,8 @@ struct CountedRegion : public CounterMappingRegion { : CounterMappingRegion(R), ExecutionCount(ExecutionCount) {} }; -/// \brief A Counter mapping context is used to connect the counters, -/// expressions and the obtained counter values. +/// A Counter mapping context is used to connect the counters, expressions +/// and the obtained counter values. class CounterMappingContext { ArrayRef<CounterExpression> Expressions; ArrayRef<uint64_t> CounterValues; @@ -284,20 +292,20 @@ public: void dump(const Counter &C, raw_ostream &OS) const; void dump(const Counter &C) const { dump(C, dbgs()); } - /// \brief Return the number of times that a region of code associated with - /// this counter was executed. + /// Return the number of times that a region of code associated with this + /// counter was executed. Expected<int64_t> evaluate(const Counter &C) const; }; -/// \brief Code coverage information for a single function. +/// Code coverage information for a single function. struct FunctionRecord { - /// \brief Raw function name. + /// Raw function name. std::string Name; - /// \brief Associated files. + /// Associated files. std::vector<std::string> Filenames; - /// \brief Regions in the function along with their counts. + /// Regions in the function along with their counts. std::vector<CountedRegion> CountedRegions; - /// \brief The number of times this function was executed. + /// The number of times this function was executed. uint64_t ExecutionCount; FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames) @@ -313,7 +321,7 @@ struct FunctionRecord { } }; -/// \brief Iterator over Functions, optionally filtered to a single file. +/// Iterator over Functions, optionally filtered to a single file. class FunctionRecordIterator : public iterator_facade_base<FunctionRecordIterator, std::forward_iterator_tag, FunctionRecord> { @@ -321,7 +329,7 @@ class FunctionRecordIterator ArrayRef<FunctionRecord>::iterator Current; StringRef Filename; - /// \brief Skip records whose primary file is not \c Filename. + /// Skip records whose primary file is not \c Filename. void skipOtherFiles(); public: @@ -347,17 +355,17 @@ public: } }; -/// \brief Coverage information for a macro expansion or #included file. +/// Coverage information for a macro expansion or #included file. /// /// When covered code has pieces that can be expanded for more detail, such as a /// preprocessor macro use and its definition, these are represented as /// expansions whose coverage can be looked up independently. struct ExpansionRecord { - /// \brief The abstract file this expansion covers. + /// The abstract file this expansion covers. unsigned FileID; - /// \brief The region that expands to this record. + /// The region that expands to this record. const CountedRegion &Region; - /// \brief Coverage for the expansion. + /// Coverage for the expansion. const FunctionRecord &Function; ExpansionRecord(const CountedRegion &Region, @@ -365,38 +373,99 @@ struct ExpansionRecord { : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {} }; -/// \brief The execution count information starting at a point in a file. +/// The execution count information starting at a point in a file. /// /// A sequence of CoverageSegments gives execution counts for a file in format /// that's simple to iterate through for processing. struct CoverageSegment { - /// \brief The line where this segment begins. + /// The line where this segment begins. unsigned Line; - /// \brief The column where this segment begins. + /// The column where this segment begins. unsigned Col; - /// \brief The execution count, or zero if no count was recorded. + /// The execution count, or zero if no count was recorded. uint64_t Count; - /// \brief When false, the segment was uninstrumented or skipped. + /// When false, the segment was uninstrumented or skipped. bool HasCount; - /// \brief Whether this enters a new region or returns to a previous count. + /// Whether this enters a new region or returns to a previous count. bool IsRegionEntry; + /// Whether this enters a gap region. + bool IsGapRegion; CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry) : Line(Line), Col(Col), Count(0), HasCount(false), - IsRegionEntry(IsRegionEntry) {} + IsRegionEntry(IsRegionEntry), IsGapRegion(false) {} CoverageSegment(unsigned Line, unsigned Col, uint64_t Count, - bool IsRegionEntry) + bool IsRegionEntry, bool IsGapRegion = false) : Line(Line), Col(Col), Count(Count), HasCount(true), - IsRegionEntry(IsRegionEntry) {} + IsRegionEntry(IsRegionEntry), IsGapRegion(IsGapRegion) {} friend bool operator==(const CoverageSegment &L, const CoverageSegment &R) { - return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry) == - std::tie(R.Line, R.Col, R.Count, R.HasCount, R.IsRegionEntry); + return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry, + L.IsGapRegion) == std::tie(R.Line, R.Col, R.Count, + R.HasCount, R.IsRegionEntry, + R.IsGapRegion); } }; -/// \brief Coverage information to be processed or displayed. +/// 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; + } +}; + +/// Coverage information to be processed or displayed. /// /// This represents the coverage of an entire file, expansion, or function. It /// provides a sequence of CoverageSegments to iterate through, as well as the @@ -413,9 +482,11 @@ public: CoverageData(StringRef Filename) : Filename(Filename) {} - /// \brief Get the name of the file this data covers. + /// Get the name of the file this data covers. StringRef getFilename() const { return Filename; } + /// Get an iterator over the coverage segments for this object. The segments + /// are guaranteed to be uniqued and sorted by location. std::vector<CoverageSegment>::const_iterator begin() const { return Segments.begin(); } @@ -426,22 +497,23 @@ public: bool empty() const { return Segments.empty(); } - /// \brief Expansions that can be further processed. + /// Expansions that can be further processed. ArrayRef<ExpansionRecord> getExpansions() const { return Expansions; } }; -/// \brief The mapping of profile information to coverage data. +/// The mapping of profile information to coverage data. /// /// This is the main interface to get coverage information, using a profile to /// fill out execution counts. class CoverageMapping { StringSet<> FunctionNames; std::vector<FunctionRecord> Functions; - unsigned MismatchedFunctionCount = 0; + std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches; + std::vector<std::pair<std::string, uint64_t>> FuncCounterMismatches; CoverageMapping() = default; - /// \brief Add a function record corresponding to \p Record. + /// Add a function record corresponding to \p Record. Error loadFunctionRecord(const CoverageMappingRecord &Record, IndexedInstrProfReader &ProfileReader); @@ -449,59 +521,162 @@ public: CoverageMapping(const CoverageMapping &) = delete; CoverageMapping &operator=(const CoverageMapping &) = delete; - /// \brief Load the coverage mapping using the given readers. + /// Load the coverage mapping using the given readers. static Expected<std::unique_ptr<CoverageMapping>> load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, IndexedInstrProfReader &ProfileReader); + /// Load the coverage mapping from the given object files and profile. If + /// \p Arches is non-empty, it must specify an architecture for each object. static Expected<std::unique_ptr<CoverageMapping>> load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename, - StringRef Arch = StringRef()); + ArrayRef<StringRef> Arches = None); - /// \brief The number of functions that couldn't have their profiles mapped. + /// The number of functions that couldn't have their profiles mapped. /// /// This is a count of functions whose profile is out of date or otherwise /// can't be associated with any coverage information. - unsigned getMismatchedCount() { return MismatchedFunctionCount; } + unsigned getMismatchedCount() const { + return FuncHashMismatches.size() + FuncCounterMismatches.size(); + } + + /// A hash mismatch occurs when a profile record for a symbol does not have + /// the same hash as a coverage mapping record for the same symbol. This + /// returns a list of hash mismatches, where each mismatch is a pair of the + /// symbol name and its coverage mapping hash. + ArrayRef<std::pair<std::string, uint64_t>> getHashMismatches() const { + return FuncHashMismatches; + } - /// \brief Returns a lexicographically sorted, unique list of files that are + /// A counter mismatch occurs when there is an error when evaluating the + /// counter expressions in a coverage mapping record. This returns a list of + /// counter mismatches, where each mismatch is a pair of the symbol name and + /// the number of valid evaluated counter expressions. + ArrayRef<std::pair<std::string, uint64_t>> getCounterMismatches() const { + return FuncCounterMismatches; + } + + /// Returns a lexicographically sorted, unique list of files that are /// covered. std::vector<StringRef> getUniqueSourceFiles() const; - /// \brief Get the coverage for a particular file. + /// Get the coverage for a particular file. /// /// 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; - /// \brief Gets all of the functions covered by this profile. + /// Get the coverage for a particular function. + CoverageData getCoverageForFunction(const FunctionRecord &Function) const; + + /// Get the coverage for an expansion within a coverage set. + CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const; + + /// Gets all of the functions covered by this profile. iterator_range<FunctionRecordIterator> getCoveredFunctions() const { return make_range(FunctionRecordIterator(Functions), FunctionRecordIterator()); } - /// \brief Gets all of the functions in a particular file. + /// Gets all of the functions in a particular file. iterator_range<FunctionRecordIterator> getCoveredFunctions(StringRef Filename) const { return make_range(FunctionRecordIterator(Functions, Filename), 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; +/// Coverage statistics for a single line. +class LineCoverageStats { + uint64_t ExecutionCount; + bool HasMultipleRegions; + bool Mapped; + unsigned Line; + ArrayRef<const CoverageSegment *> LineSegments; + const CoverageSegment *WrappedSegment; - /// \brief Get the coverage for an expansion within a coverage set. - CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const; + 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] @@ -602,7 +777,10 @@ enum CovMapVersion { // name string pointer to MD5 to support name section compression. Name // section is also compressed. Version2 = 1, - // The current version is Version2 + // A new interpretation of the columnEnd field is added in order to mark + // regions as gap areas. + Version3 = 2, + // The current version is Version3 CurrentVersion = INSTR_PROF_COVMAP_VERSION }; @@ -618,7 +796,7 @@ template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version1, IntPtrT> { } // end namespace coverage -/// \brief Provide DenseMapInfo for CounterExpression +/// Provide DenseMapInfo for CounterExpression template<> struct DenseMapInfo<coverage::CounterExpression> { static inline coverage::CounterExpression getEmptyKey() { using namespace coverage; diff --git a/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h index 5b372252a9ac9..633e51565cd2a 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMappingReader.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -44,18 +44,26 @@ struct CoverageMappingRecord { /// \brief A file format agnostic iterator over coverage mapping data. class CoverageMappingIterator : public std::iterator<std::input_iterator_tag, CoverageMappingRecord> { - CoverageMappingReader *Reader = nullptr; + CoverageMappingReader *Reader; CoverageMappingRecord Record; + coveragemap_error ReadErr; void increment(); public: - CoverageMappingIterator() = default; + CoverageMappingIterator() + : Reader(nullptr), Record(), ReadErr(coveragemap_error::success) {} - CoverageMappingIterator(CoverageMappingReader *Reader) : Reader(Reader) { + CoverageMappingIterator(CoverageMappingReader *Reader) + : Reader(Reader), Record(), ReadErr(coveragemap_error::success) { increment(); } + ~CoverageMappingIterator() { + if (ReadErr != coveragemap_error::success) + llvm_unreachable("Unexpected error in coverage mapping iterator"); + } + CoverageMappingIterator &operator++() { increment(); return *this; @@ -66,8 +74,22 @@ public: bool operator!=(const CoverageMappingIterator &RHS) { return Reader != RHS.Reader; } - CoverageMappingRecord &operator*() { return Record; } - CoverageMappingRecord *operator->() { return &Record; } + Expected<CoverageMappingRecord &> operator*() { + if (ReadErr != coveragemap_error::success) { + auto E = make_error<CoverageMapError>(ReadErr); + ReadErr = coveragemap_error::success; + return std::move(E); + } + return Record; + } + Expected<CoverageMappingRecord *> operator->() { + if (ReadErr != coveragemap_error::success) { + auto E = make_error<CoverageMapError>(ReadErr); + ReadErr = coveragemap_error::success; + return std::move(E); + } + return &Record; + } }; class CoverageMappingReader { |