diff options
Diffstat (limited to 'include/llvm/ProfileData')
-rw-r--r-- | include/llvm/ProfileData/CoverageMapping.h | 448 | ||||
-rw-r--r-- | include/llvm/ProfileData/CoverageMappingReader.h | 209 | ||||
-rw-r--r-- | include/llvm/ProfileData/CoverageMappingWriter.h | 63 | ||||
-rw-r--r-- | include/llvm/ProfileData/InstrProfReader.h | 59 | ||||
-rw-r--r-- | include/llvm/ProfileData/InstrProfWriter.h | 15 | ||||
-rw-r--r-- | include/llvm/ProfileData/SampleProf.h | 248 | ||||
-rw-r--r-- | include/llvm/ProfileData/SampleProfReader.h | 170 | ||||
-rw-r--r-- | include/llvm/ProfileData/SampleProfWriter.h | 110 |
8 files changed, 1287 insertions, 35 deletions
diff --git a/include/llvm/ProfileData/CoverageMapping.h b/include/llvm/ProfileData/CoverageMapping.h new file mode 100644 index 0000000..38fc8ca --- /dev/null +++ b/include/llvm/ProfileData/CoverageMapping.h @@ -0,0 +1,448 @@ +//=-- CoverageMapping.h - Code coverage mapping support ---------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Code coverage mapping data is generated by clang and read by +// llvm-cov to show code coverage statistics for a file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_H_ +#define LLVM_PROFILEDATA_COVERAGEMAPPING_H_ + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Hashing.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/raw_ostream.h" +#include <system_error> + +namespace llvm { +class IndexedInstrProfReader; +namespace coverage { + +class ObjectFileCoverageMappingReader; + +class CoverageMapping; +struct CounterExpressions; + +enum CoverageMappingVersion { CoverageMappingVersion1 }; + +/// \brief 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 }; + static const unsigned EncodingTagBits = 2; + static const unsigned EncodingTagMask = 0x3; + static const unsigned EncodingCounterTagAndExpansionRegionTagBits = + EncodingTagBits + 1; + +private: + CounterKind Kind; + unsigned ID; + + Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {} + +public: + Counter() : Kind(Zero), ID(0) {} + + CounterKind getKind() const { return Kind; } + + bool isZero() const { return Kind == Zero; } + + bool isExpression() const { return Kind == Expression; } + + unsigned getCounterID() const { return ID; } + + unsigned getExpressionID() const { return ID; } + + bool operator==(const Counter &Other) const { + return Kind == Other.Kind && ID == Other.ID; + } + + friend bool operator<(const Counter &LHS, const Counter &RHS) { + return std::tie(LHS.Kind, LHS.ID) < std::tie(RHS.Kind, RHS.ID); + } + + /// \brief Return the counter that represents the number zero. + static Counter getZero() { return Counter(); } + + /// \brief 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. + static Counter getExpression(unsigned ExpressionId) { + return Counter(Expression, ExpressionId); + } +}; + +/// \brief A Counter expression is a value that represents an arithmetic +/// operation with two counters. +struct CounterExpression { + enum ExprKind { Subtract, Add }; + ExprKind Kind; + Counter LHS, RHS; + + CounterExpression(ExprKind Kind, Counter LHS, Counter RHS) + : Kind(Kind), LHS(LHS), RHS(RHS) {} +}; + +/// \brief A Counter expression builder is used to construct the +/// counter expressions. It avoids unecessary duplication +/// and simplifies algebraic expressions. +class CounterExpressionBuilder { + /// \brief A list of all the counter expressions + std::vector<CounterExpression> Expressions; + /// \brief A lookup table for the index of a given expression. + llvm::DenseMap<CounterExpression, unsigned> ExpressionIndices; + + /// \brief 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 + /// expression is added to the builder's collection of expressions. + Counter get(const CounterExpression &E); + + /// \brief 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<std::pair<unsigned, int>> &Terms); + + /// \brief 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. + Counter add(Counter LHS, Counter RHS); + + /// \brief 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. +struct CounterMappingRegion { + enum RegionKind { + /// \brief 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. + ExpansionRegion, + + /// \brief A SkippedRegion represents a source range with code that + /// was skipped by a preprocessor or similar means. + SkippedRegion + }; + + static const unsigned EncodingHasCodeBeforeBits = 1; + + Counter Count; + unsigned FileID, ExpandedFileID; + unsigned LineStart, ColumnStart, LineEnd, ColumnEnd; + RegionKind Kind; + /// \brief A flag that is set to true when there is already code before + /// this region on the same line. + /// This is useful to accurately compute the execution counts for a line. + bool HasCodeBefore; + + CounterMappingRegion(Counter Count, unsigned FileID, unsigned LineStart, + unsigned ColumnStart, unsigned LineEnd, + unsigned ColumnEnd, bool HasCodeBefore = false, + RegionKind Kind = CodeRegion) + : Count(Count), FileID(FileID), ExpandedFileID(0), LineStart(LineStart), + ColumnStart(ColumnStart), LineEnd(LineEnd), ColumnEnd(ColumnEnd), + Kind(Kind), HasCodeBefore(HasCodeBefore) {} + + inline std::pair<unsigned, unsigned> startLoc() const { + return std::pair<unsigned, unsigned>(LineStart, ColumnStart); + } + + inline std::pair<unsigned, unsigned> endLoc() const { + return std::pair<unsigned, unsigned>(LineEnd, ColumnEnd); + } + + bool operator<(const CounterMappingRegion &Other) const { + if (FileID != Other.FileID) + return FileID < Other.FileID; + return startLoc() < Other.startLoc(); + } + + bool contains(const CounterMappingRegion &Other) const { + if (FileID != Other.FileID) + return false; + if (startLoc() > Other.startLoc()) + return false; + if (endLoc() < Other.endLoc()) + return false; + return true; + } +}; + +/// \brief Associates a source range with an execution count. +struct CountedRegion : public CounterMappingRegion { + uint64_t ExecutionCount; + + CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount) + : CounterMappingRegion(R), ExecutionCount(ExecutionCount) {} +}; + +/// \brief 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; + +public: + CounterMappingContext(ArrayRef<CounterExpression> Expressions, + ArrayRef<uint64_t> CounterValues = ArrayRef<uint64_t>()) + : Expressions(Expressions), CounterValues(CounterValues) {} + + void dump(const Counter &C, llvm::raw_ostream &OS) const; + void dump(const Counter &C) const { dump(C, llvm::outs()); } + + /// \brief Return the number of times that a region of code associated with + /// this counter was executed. + ErrorOr<int64_t> evaluate(const Counter &C) const; +}; + +/// \brief Code coverage information for a single function. +struct FunctionRecord { + /// \brief Raw function name. + std::string Name; + /// \brief Associated files. + std::vector<std::string> Filenames; + /// \brief Regions in the function along with their counts. + std::vector<CountedRegion> CountedRegions; + /// \brief The number of times this function was executed. + uint64_t ExecutionCount; + + FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames, + uint64_t ExecutionCount) + : Name(Name), Filenames(Filenames.begin(), Filenames.end()), + ExecutionCount(ExecutionCount) {} +}; + +/// \brief Iterator over Functions, optionally filtered to a single file. +class FunctionRecordIterator + : public iterator_facade_base<FunctionRecordIterator, + std::forward_iterator_tag, FunctionRecord> { + ArrayRef<FunctionRecord> Records; + ArrayRef<FunctionRecord>::iterator Current; + StringRef Filename; + + /// \brief Skip records whose primary file is not \c Filename. + void skipOtherFiles(); + +public: + FunctionRecordIterator(ArrayRef<FunctionRecord> Records_, + StringRef Filename = "") + : Records(Records_), Current(Records.begin()), Filename(Filename) { + skipOtherFiles(); + } + + FunctionRecordIterator() : Current(Records.begin()) {} + + bool operator==(const FunctionRecordIterator &RHS) const { + return Current == RHS.Current && Filename == RHS.Filename; + } + + const FunctionRecord &operator*() const { return *Current; } + + FunctionRecordIterator &operator++() { + assert(Current != Records.end() && "incremented past end"); + ++Current; + skipOtherFiles(); + return *this; + } +}; + +/// \brief 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. + unsigned FileID; + /// \brief The region that expands to this record. + const CountedRegion &Region; + /// \brief Coverage for the expansion. + const FunctionRecord &Function; + + ExpansionRecord(const CountedRegion &Region, + const FunctionRecord &Function) + : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {} +}; + +/// \brief 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. + unsigned Line; + /// \brief The column where this segment begins. + unsigned Col; + /// \brief The execution count, or zero if no count was recorded. + uint64_t Count; + /// \brief When false, the segment was uninstrumented or skipped. + bool HasCount; + /// \brief Whether this enters a new region or returns to a previous count. + bool IsRegionEntry; + + CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry) + : Line(Line), Col(Col), Count(0), HasCount(false), + IsRegionEntry(IsRegionEntry) {} + void setCount(uint64_t NewCount) { + Count = NewCount; + HasCount = true; + } + void addCount(uint64_t NewCount) { setCount(Count + NewCount); } +}; + +/// \brief 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 +/// list of expansions that can be further processed. +class CoverageData { + std::string Filename; + std::vector<CoverageSegment> Segments; + std::vector<ExpansionRecord> Expansions; + friend class CoverageMapping; + +public: + CoverageData() {} + + CoverageData(StringRef Filename) : Filename(Filename) {} + + CoverageData(CoverageData &&RHS) + : Filename(std::move(RHS.Filename)), Segments(std::move(RHS.Segments)), + Expansions(std::move(RHS.Expansions)) {} + + /// \brief Get the name of the file this data covers. + StringRef getFilename() { return Filename; } + + std::vector<CoverageSegment>::iterator begin() { return Segments.begin(); } + std::vector<CoverageSegment>::iterator end() { return Segments.end(); } + bool empty() { return Segments.empty(); } + + /// \brief Expansions that can be further processed. + std::vector<ExpansionRecord> getExpansions() { return Expansions; } +}; + +/// \brief 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 { + std::vector<FunctionRecord> Functions; + unsigned MismatchedFunctionCount; + + CoverageMapping() : MismatchedFunctionCount(0) {} + +public: + /// \brief Load the coverage mapping using the given readers. + static ErrorOr<std::unique_ptr<CoverageMapping>> + load(ObjectFileCoverageMappingReader &CoverageReader, + IndexedInstrProfReader &ProfileReader); + + /// \brief Load the coverage mapping from the given files. + static ErrorOr<std::unique_ptr<CoverageMapping>> + load(StringRef ObjectFilename, StringRef ProfileFilename); + + /// \brief 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; } + + /// \brief Returns the list of files that are covered. + std::vector<StringRef> getUniqueSourceFiles() const; + + /// \brief 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); + + /// \brief 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. + iterator_range<FunctionRecordIterator> + getCoveredFunctions(StringRef Filename) const { + return make_range(FunctionRecordIterator(Functions, Filename), + FunctionRecordIterator()); + } + + /// \brief Get the list of function instantiations in the file. + /// + /// Fucntions 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); + + /// \brief Get the coverage for a particular function. + CoverageData getCoverageForFunction(const FunctionRecord &Function); + + /// \brief Get the coverage for an expansion within a coverage set. + CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion); +}; + +} // end namespace coverage + +/// \brief Provide DenseMapInfo for CounterExpression +template<> struct DenseMapInfo<coverage::CounterExpression> { + static inline coverage::CounterExpression getEmptyKey() { + using namespace coverage; + return CounterExpression(CounterExpression::ExprKind::Subtract, + Counter::getCounter(~0U), + Counter::getCounter(~0U)); + } + + static inline coverage::CounterExpression getTombstoneKey() { + using namespace coverage; + return CounterExpression(CounterExpression::ExprKind::Add, + Counter::getCounter(~0U), + Counter::getCounter(~0U)); + } + + static unsigned getHashValue(const coverage::CounterExpression &V) { + return static_cast<unsigned>( + hash_combine(V.Kind, V.LHS.getKind(), V.LHS.getCounterID(), + V.RHS.getKind(), V.RHS.getCounterID())); + } + + static bool isEqual(const coverage::CounterExpression &LHS, + const coverage::CounterExpression &RHS) { + return LHS.Kind == RHS.Kind && LHS.LHS == RHS.LHS && LHS.RHS == RHS.RHS; + } +}; + + +} // end namespace llvm + +#endif // LLVM_PROFILEDATA_COVERAGEMAPPING_H_ diff --git a/include/llvm/ProfileData/CoverageMappingReader.h b/include/llvm/ProfileData/CoverageMappingReader.h new file mode 100644 index 0000000..73b0248 --- /dev/null +++ b/include/llvm/ProfileData/CoverageMappingReader.h @@ -0,0 +1,209 @@ +//=-- CoverageMappingReader.h - Code coverage mapping reader ------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for reading coverage mapping data for +// instrumentation based coverage. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PROFILEDATA_COVERAGEMAPPINGREADER_H +#define LLVM_PROFILEDATA_COVERAGEMAPPINGREADER_H + +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/ProfileData/CoverageMapping.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/FileSystem.h" + +#include <iterator> + +namespace llvm { +namespace coverage { + +class ObjectFileCoverageMappingReader; + +/// \brief Coverage mapping information for a single function. +struct CoverageMappingRecord { + StringRef FunctionName; + uint64_t FunctionHash; + ArrayRef<StringRef> Filenames; + ArrayRef<CounterExpression> Expressions; + ArrayRef<CounterMappingRegion> MappingRegions; +}; + +/// \brief A file format agnostic iterator over coverage mapping data. +class CoverageMappingIterator + : public std::iterator<std::input_iterator_tag, CoverageMappingRecord> { + ObjectFileCoverageMappingReader *Reader; + CoverageMappingRecord Record; + + void increment(); + +public: + CoverageMappingIterator() : Reader(nullptr) {} + CoverageMappingIterator(ObjectFileCoverageMappingReader *Reader) + : Reader(Reader) { + increment(); + } + + CoverageMappingIterator &operator++() { + increment(); + return *this; + } + bool operator==(const CoverageMappingIterator &RHS) { + return Reader == RHS.Reader; + } + bool operator!=(const CoverageMappingIterator &RHS) { + return Reader != RHS.Reader; + } + CoverageMappingRecord &operator*() { return Record; } + CoverageMappingRecord *operator->() { return &Record; } +}; + +/// \brief Base class for the raw coverage mapping and filenames data readers. +class RawCoverageReader { +protected: + StringRef Data; + + /// \brief Return the error code. + std::error_code error(std::error_code EC) { return EC; } + + /// \brief Clear the current error code and return a successful one. + std::error_code success() { return error(instrprof_error::success); } + + RawCoverageReader(StringRef Data) : Data(Data) {} + + std::error_code readULEB128(uint64_t &Result); + std::error_code readIntMax(uint64_t &Result, uint64_t MaxPlus1); + std::error_code readSize(uint64_t &Result); + std::error_code readString(StringRef &Result); +}; + +/// \brief Reader for the raw coverage filenames. +class RawCoverageFilenamesReader : public RawCoverageReader { + std::vector<StringRef> &Filenames; + + RawCoverageFilenamesReader(const RawCoverageFilenamesReader &) + LLVM_DELETED_FUNCTION; + RawCoverageFilenamesReader & + operator=(const RawCoverageFilenamesReader &) LLVM_DELETED_FUNCTION; + +public: + RawCoverageFilenamesReader(StringRef Data, std::vector<StringRef> &Filenames) + : RawCoverageReader(Data), Filenames(Filenames) {} + + std::error_code read(); +}; + +/// \brief Reader for the raw coverage mapping data. +class RawCoverageMappingReader : public RawCoverageReader { + StringRef FunctionName; + ArrayRef<StringRef> TranslationUnitFilenames; + std::vector<StringRef> &Filenames; + std::vector<CounterExpression> &Expressions; + std::vector<CounterMappingRegion> &MappingRegions; + + RawCoverageMappingReader(const RawCoverageMappingReader &) + LLVM_DELETED_FUNCTION; + RawCoverageMappingReader & + operator=(const RawCoverageMappingReader &) LLVM_DELETED_FUNCTION; + +public: + RawCoverageMappingReader(StringRef FunctionName, StringRef MappingData, + ArrayRef<StringRef> TranslationUnitFilenames, + std::vector<StringRef> &Filenames, + std::vector<CounterExpression> &Expressions, + std::vector<CounterMappingRegion> &MappingRegions) + : RawCoverageReader(MappingData), FunctionName(FunctionName), + TranslationUnitFilenames(TranslationUnitFilenames), + Filenames(Filenames), Expressions(Expressions), + MappingRegions(MappingRegions) {} + + std::error_code read(CoverageMappingRecord &Record); + +private: + std::error_code decodeCounter(unsigned Value, Counter &C); + std::error_code readCounter(Counter &C); + std::error_code + readMappingRegionsSubArray(std::vector<CounterMappingRegion> &MappingRegions, + unsigned InferredFileID, size_t NumFileIDs); +}; + +/// \brief Reader for the coverage mapping data that is emitted by the +/// frontend and stored in an object file. +class ObjectFileCoverageMappingReader { +public: + struct ProfileMappingRecord { + CoverageMappingVersion Version; + StringRef FunctionName; + uint64_t FunctionHash; + StringRef CoverageMapping; + size_t FilenamesBegin; + size_t FilenamesSize; + + ProfileMappingRecord(CoverageMappingVersion Version, StringRef FunctionName, + uint64_t FunctionHash, StringRef CoverageMapping, + size_t FilenamesBegin, size_t FilenamesSize) + : Version(Version), FunctionName(FunctionName), + FunctionHash(FunctionHash), CoverageMapping(CoverageMapping), + FilenamesBegin(FilenamesBegin), FilenamesSize(FilenamesSize) {} + }; + +private: + std::error_code LastError; + object::OwningBinary<object::ObjectFile> Object; + std::vector<StringRef> Filenames; + std::vector<ProfileMappingRecord> MappingRecords; + size_t CurrentRecord; + std::vector<StringRef> FunctionsFilenames; + std::vector<CounterExpression> Expressions; + std::vector<CounterMappingRegion> MappingRegions; + + ObjectFileCoverageMappingReader(const ObjectFileCoverageMappingReader &) + LLVM_DELETED_FUNCTION; + ObjectFileCoverageMappingReader & + operator=(const ObjectFileCoverageMappingReader &) LLVM_DELETED_FUNCTION; + + /// \brief Set the current error_code and return same. + std::error_code error(std::error_code EC) { + LastError = EC; + return EC; + } + + /// \brief Clear the current error code and return a successful one. + std::error_code success() { return error(instrprof_error::success); } + +public: + ObjectFileCoverageMappingReader(StringRef FileName); + ObjectFileCoverageMappingReader( + std::unique_ptr<MemoryBuffer> &ObjectBuffer, + sys::fs::file_magic Type = sys::fs::file_magic::unknown); + + std::error_code readHeader(); + std::error_code readNextRecord(CoverageMappingRecord &Record); + + /// Iterator over profile data. + CoverageMappingIterator begin() { return CoverageMappingIterator(this); } + CoverageMappingIterator end() { return CoverageMappingIterator(); } + + /// \brief Return true if the reader has finished reading the profile data. + bool isEOF() { return LastError == instrprof_error::eof; } + /// \brief Return true if the reader encountered an error reading profiling + /// data. + bool hasError() { return LastError && !isEOF(); } + /// \brief Get the current error code. + std::error_code getError() { return LastError; } +}; + +} // end namespace coverage +} // end namespace llvm + +#endif diff --git a/include/llvm/ProfileData/CoverageMappingWriter.h b/include/llvm/ProfileData/CoverageMappingWriter.h new file mode 100644 index 0000000..cf16140 --- /dev/null +++ b/include/llvm/ProfileData/CoverageMappingWriter.h @@ -0,0 +1,63 @@ +//=-- CoverageMappingWriter.h - Code coverage mapping writer ------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing coverage mapping data for +// instrumentation based coverage. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_PROFILEDATA_COVERAGEMAPPINGWRITER_H +#define LLVM_PROFILEDATA_COVERAGEMAPPINGWRITER_H + +#include "llvm/ProfileData/CoverageMapping.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace coverage { + +/// \brief Writer of the filenames section for the instrumentation +/// based code coverage. +class CoverageFilenamesSectionWriter { + ArrayRef<StringRef> Filenames; + +public: + CoverageFilenamesSectionWriter(ArrayRef<StringRef> Filenames) + : Filenames(Filenames) {} + + /// \brief Write encoded filenames to the given output stream. + void write(raw_ostream &OS); +}; + +/// \brief Writer for instrumentation based coverage mapping data. +class CoverageMappingWriter { + ArrayRef<unsigned> VirtualFileMapping; + ArrayRef<CounterExpression> Expressions; + MutableArrayRef<CounterMappingRegion> MappingRegions; + +public: + CoverageMappingWriter(ArrayRef<unsigned> VirtualFileMapping, + ArrayRef<CounterExpression> Expressions, + MutableArrayRef<CounterMappingRegion> MappingRegions) + : VirtualFileMapping(VirtualFileMapping), Expressions(Expressions), + MappingRegions(MappingRegions) {} + + CoverageMappingWriter(ArrayRef<CounterExpression> Expressions, + MutableArrayRef<CounterMappingRegion> MappingRegions) + : Expressions(Expressions), MappingRegions(MappingRegions) {} + + /// \brief Write encoded coverage mapping data to the given output stream. + void write(raw_ostream &OS); +}; + +} // end namespace coverage +} // end namespace llvm + +#endif diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h index 7a5a71d..38c5310 100644 --- a/include/llvm/ProfileData/InstrProfReader.h +++ b/include/llvm/ProfileData/InstrProfReader.h @@ -12,12 +12,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_PROFILEDATA_INSTRPROF_READER_H_ -#define LLVM_PROFILEDATA_INSTRPROF_READER_H_ +#ifndef LLVM_PROFILEDATA_INSTRPROFREADER_H +#define LLVM_PROFILEDATA_INSTRPROFREADER_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/EndianStream.h" @@ -94,8 +95,7 @@ public: /// Factory method to create an appropriately typed reader for the given /// instrprof file. - static std::error_code create(std::string Path, - std::unique_ptr<InstrProfReader> &Result); + static ErrorOr<std::unique_ptr<InstrProfReader>> create(std::string Path); }; /// Reader for the simple text based instrprof format. @@ -120,7 +120,7 @@ private: LLVM_DELETED_FUNCTION; public: TextInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer_) - : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, '#') {} + : DataBuffer(std::move(DataBuffer_)), Line(*DataBuffer, true, '#') {} /// Read the header. std::error_code readHeader() override { return success(); } @@ -206,12 +206,17 @@ enum class HashT : uint32_t; /// Trait for lookups into the on-disk hash table for the binary instrprof /// format. class InstrProfLookupTrait { - std::vector<uint64_t> CountBuffer; + std::vector<uint64_t> DataBuffer; IndexedInstrProf::HashT HashType; public: InstrProfLookupTrait(IndexedInstrProf::HashT HashType) : HashType(HashType) {} - typedef InstrProfRecord data_type; + struct data_type { + data_type(StringRef Name, ArrayRef<uint64_t> Data) + : Name(Name), Data(Data) {} + StringRef Name; + ArrayRef<uint64_t> Data; + }; typedef StringRef internal_key_type; typedef StringRef external_key_type; typedef uint64_t hash_value_type; @@ -234,25 +239,20 @@ public: return StringRef((const char *)D, N); } - InstrProfRecord ReadData(StringRef K, const unsigned char *D, offset_type N) { - if (N < 2 * sizeof(uint64_t) || N % sizeof(uint64_t)) { + data_type ReadData(StringRef K, const unsigned char *D, offset_type N) { + DataBuffer.clear(); + if (N % sizeof(uint64_t)) // The data is corrupt, don't try to read it. - CountBuffer.clear(); - return InstrProfRecord("", 0, CountBuffer); - } + return data_type("", DataBuffer); using namespace support; - - // The first stored value is the hash. - uint64_t Hash = endian::readNext<uint64_t, little, unaligned>(D); - // Each counter follows. - unsigned NumCounters = N / sizeof(uint64_t) - 1; - CountBuffer.clear(); - CountBuffer.reserve(NumCounters - 1); - for (unsigned I = 0; I < NumCounters; ++I) - CountBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D)); - - return InstrProfRecord(K, Hash, CountBuffer); + // We just treat the data as opaque here. It's simpler to handle in + // IndexedInstrProfReader. + unsigned NumEntries = N / sizeof(uint64_t); + DataBuffer.reserve(NumEntries); + for (unsigned I = 0; I < NumEntries; ++I) + DataBuffer.push_back(endian::readNext<uint64_t, little, unaligned>(D)); + return data_type(K, DataBuffer); } }; typedef OnDiskIterableChainedHashTable<InstrProfLookupTrait> @@ -267,7 +267,11 @@ private: std::unique_ptr<InstrProfReaderIndex> Index; /// Iterator over the profile data. InstrProfReaderIndex::data_iterator RecordIterator; - /// The maximal execution count among all fucntions. + /// Offset into our current data set. + size_t CurrentOffset; + /// The file format version of the profile data. + uint64_t FormatVersion; + /// The maximal execution count among all functions. uint64_t MaxFunctionCount; IndexedInstrProfReader(const IndexedInstrProfReader &) LLVM_DELETED_FUNCTION; @@ -275,8 +279,7 @@ private: LLVM_DELETED_FUNCTION; public: IndexedInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer) - : DataBuffer(std::move(DataBuffer)), Index(nullptr), - RecordIterator(InstrProfReaderIndex::data_iterator()) {} + : DataBuffer(std::move(DataBuffer)), Index(nullptr), CurrentOffset(0) {} /// Return true if the given buffer is in an indexed instrprof format. static bool hasFormat(const MemoryBuffer &DataBuffer); @@ -287,7 +290,7 @@ public: std::error_code readNextRecord(InstrProfRecord &Record) override; /// Fill Counts with the profile data for the given function name. - std::error_code getFunctionCounts(StringRef FuncName, uint64_t &FuncHash, + std::error_code getFunctionCounts(StringRef FuncName, uint64_t FuncHash, std::vector<uint64_t> &Counts); /// Return the maximum of all known function counts. uint64_t getMaximumFunctionCount() { return MaxFunctionCount; } @@ -299,4 +302,4 @@ public: } // end namespace llvm -#endif // LLVM_PROFILEDATA_INSTRPROF_READER_H_ +#endif diff --git a/include/llvm/ProfileData/InstrProfWriter.h b/include/llvm/ProfileData/InstrProfWriter.h index 6e68bee..e76f668 100644 --- a/include/llvm/ProfileData/InstrProfWriter.h +++ b/include/llvm/ProfileData/InstrProfWriter.h @@ -12,10 +12,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_PROFILEDATA_INSTRPROF_WRITER_H_ -#define LLVM_PROFILEDATA_INSTRPROF_WRITER_H_ +#ifndef LLVM_PROFILEDATA_INSTRPROFWRITER_H +#define LLVM_PROFILEDATA_INSTRPROFWRITER_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/DataTypes.h" @@ -28,13 +29,13 @@ namespace llvm { /// Writer for instrumentation based profile data. class InstrProfWriter { public: - struct CounterData { - uint64_t Hash; - std::vector<uint64_t> Counts; - }; + typedef SmallDenseMap<uint64_t, std::vector<uint64_t>, 1> CounterData; private: StringMap<CounterData> FunctionData; + uint64_t MaxFunctionCount; public: + InstrProfWriter() : MaxFunctionCount(0) {} + /// Add function counts for the given function. If there are already counts /// for this function and the hash and number of counts match, each counter is /// summed. @@ -47,4 +48,4 @@ public: } // end namespace llvm -#endif // LLVM_PROFILE_INSTRPROF_WRITER_H_ +#endif diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h new file mode 100644 index 0000000..5c70b31 --- /dev/null +++ b/include/llvm/ProfileData/SampleProf.h @@ -0,0 +1,248 @@ +//=-- SampleProf.h - Sampling profiling format support --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains common definitions used in the reading and writing of +// sample profile data. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_PROFILEDATA_SAMPLEPROF_H_ +#define LLVM_PROFILEDATA_SAMPLEPROF_H_ + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +#include <system_error> + +namespace llvm { + +const std::error_category &sampleprof_category(); + +enum class sampleprof_error { + success = 0, + bad_magic, + unsupported_version, + too_large, + truncated, + malformed, + unrecognized_format +}; + +inline std::error_code make_error_code(sampleprof_error E) { + return std::error_code(static_cast<int>(E), sampleprof_category()); +} + +} // end namespace llvm + +namespace std { +template <> +struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {}; +} + +namespace llvm { + +namespace sampleprof { + +static inline uint64_t SPMagic() { + return uint64_t('S') << (64 - 8) | uint64_t('P') << (64 - 16) | + uint64_t('R') << (64 - 24) | uint64_t('O') << (64 - 32) | + uint64_t('F') << (64 - 40) | uint64_t('4') << (64 - 48) | + uint64_t('2') << (64 - 56) | uint64_t(0xff); +} + +static inline uint64_t SPVersion() { return 100; } + +/// \brief Represents the relative location of an instruction. +/// +/// Instruction locations are specified by the line offset from the +/// beginning of the function (marked by the line where the function +/// header is) and the discriminator value within that line. +/// +/// The discriminator value is useful to distinguish instructions +/// that are on the same line but belong to different basic blocks +/// (e.g., the two post-increment instructions in "if (p) x++; else y++;"). +struct LineLocation { + LineLocation(int L, unsigned D) : LineOffset(L), Discriminator(D) {} + int LineOffset; + unsigned Discriminator; +}; + +} // End namespace sampleprof + +template <> struct DenseMapInfo<sampleprof::LineLocation> { + typedef DenseMapInfo<int> OffsetInfo; + typedef DenseMapInfo<unsigned> DiscriminatorInfo; + static inline sampleprof::LineLocation getEmptyKey() { + return sampleprof::LineLocation(OffsetInfo::getEmptyKey(), + DiscriminatorInfo::getEmptyKey()); + } + static inline sampleprof::LineLocation getTombstoneKey() { + return sampleprof::LineLocation(OffsetInfo::getTombstoneKey(), + DiscriminatorInfo::getTombstoneKey()); + } + static inline unsigned getHashValue(sampleprof::LineLocation Val) { + return DenseMapInfo<std::pair<int, unsigned>>::getHashValue( + std::pair<int, unsigned>(Val.LineOffset, Val.Discriminator)); + } + static inline bool isEqual(sampleprof::LineLocation LHS, + sampleprof::LineLocation RHS) { + return LHS.LineOffset == RHS.LineOffset && + LHS.Discriminator == RHS.Discriminator; + } +}; + +namespace sampleprof { + +/// \brief Representation of a single sample record. +/// +/// A sample record is represented by a positive integer value, which +/// indicates how frequently was the associated line location executed. +/// +/// Additionally, if the associated location contains a function call, +/// the record will hold a list of all the possible called targets. For +/// direct calls, this will be the exact function being invoked. For +/// indirect calls (function pointers, virtual table dispatch), this +/// will be a list of one or more functions. +class SampleRecord { +public: + typedef StringMap<unsigned> CallTargetMap; + + SampleRecord() : NumSamples(0), CallTargets() {} + + /// \brief Increment the number of samples for this record by \p S. + /// + /// Sample counts accumulate using saturating arithmetic, to avoid wrapping + /// around unsigned integers. + void addSamples(unsigned S) { + if (NumSamples <= std::numeric_limits<unsigned>::max() - S) + NumSamples += S; + else + NumSamples = std::numeric_limits<unsigned>::max(); + } + + /// \brief Add called function \p F with samples \p S. + /// + /// Sample counts accumulate using saturating arithmetic, to avoid wrapping + /// around unsigned integers. + void addCalledTarget(StringRef F, unsigned S) { + unsigned &TargetSamples = CallTargets[F]; + if (TargetSamples <= std::numeric_limits<unsigned>::max() - S) + TargetSamples += S; + else + TargetSamples = std::numeric_limits<unsigned>::max(); + } + + /// \brief Return true if this sample record contains function calls. + bool hasCalls() const { return CallTargets.size() > 0; } + + unsigned getSamples() const { return NumSamples; } + const CallTargetMap &getCallTargets() const { return CallTargets; } + + /// \brief Merge the samples in \p Other into this record. + void merge(const SampleRecord &Other) { + addSamples(Other.getSamples()); + for (const auto &I : Other.getCallTargets()) + addCalledTarget(I.first(), I.second); + } + +private: + unsigned NumSamples; + CallTargetMap CallTargets; +}; + +typedef DenseMap<LineLocation, SampleRecord> BodySampleMap; + +/// \brief Representation of the samples collected for a function. +/// +/// This data structure contains all the collected samples for the body +/// of a function. Each sample corresponds to a LineLocation instance +/// within the body of the function. +class FunctionSamples { +public: + FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {} + void print(raw_ostream &OS = dbgs()); + void addTotalSamples(unsigned Num) { TotalSamples += Num; } + void addHeadSamples(unsigned Num) { TotalHeadSamples += Num; } + void addBodySamples(int LineOffset, unsigned Discriminator, unsigned Num) { + assert(LineOffset >= 0); + // When dealing with instruction weights, we use the value + // zero to indicate the absence of a sample. If we read an + // actual zero from the profile file, use the value 1 to + // avoid the confusion later on. + if (Num == 0) + Num = 1; + BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num); + } + void addCalledTargetSamples(int LineOffset, unsigned Discriminator, + std::string FName, unsigned Num) { + assert(LineOffset >= 0); + BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(FName, + Num); + } + + /// \brief Return the sample record at the given location. + /// Each location is specified by \p LineOffset and \p Discriminator. + SampleRecord &sampleRecordAt(const LineLocation &Loc) { + return BodySamples[Loc]; + } + + /// \brief Return the number of samples collected at the given location. + /// Each location is specified by \p LineOffset and \p Discriminator. + unsigned samplesAt(int LineOffset, unsigned Discriminator) { + return sampleRecordAt(LineLocation(LineOffset, Discriminator)).getSamples(); + } + + bool empty() const { return BodySamples.empty(); } + + /// \brief Return the total number of samples collected inside the function. + unsigned getTotalSamples() const { return TotalSamples; } + + /// \brief Return the total number of samples collected at the head of the + /// function. + unsigned getHeadSamples() const { return TotalHeadSamples; } + + /// \brief Return all the samples collected in the body of the function. + const BodySampleMap &getBodySamples() const { return BodySamples; } + + /// \brief Merge the samples in \p Other into this one. + void merge(const FunctionSamples &Other) { + addTotalSamples(Other.getTotalSamples()); + addHeadSamples(Other.getHeadSamples()); + for (const auto &I : Other.getBodySamples()) { + const LineLocation &Loc = I.first; + const SampleRecord &Rec = I.second; + sampleRecordAt(Loc).merge(Rec); + } + } + +private: + /// \brief Total number of samples collected inside this function. + /// + /// Samples are cumulative, they include all the samples collected + /// inside this function and all its inlined callees. + unsigned TotalSamples; + + /// \brief Total number of samples collected at the head of the function. + unsigned TotalHeadSamples; + + /// \brief Map instruction locations to collected samples. + /// + /// Each entry in this map contains the number of samples + /// collected at the corresponding line offset. All line locations + /// are an offset from the start of the function. + BodySampleMap BodySamples; +}; + +} // End namespace sampleprof + +} // End namespace llvm + +#endif // LLVM_PROFILEDATA_SAMPLEPROF_H_ diff --git a/include/llvm/ProfileData/SampleProfReader.h b/include/llvm/ProfileData/SampleProfReader.h new file mode 100644 index 0000000..c20b815 --- /dev/null +++ b/include/llvm/ProfileData/SampleProfReader.h @@ -0,0 +1,170 @@ +//===- SampleProfReader.h - Read LLVM sample profile data -----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains definitions needed for reading sample profiles. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_PROFILEDATA_SAMPLEPROFREADER_H +#define LLVM_PROFILEDATA_SAMPLEPROFREADER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/ProfileData/SampleProf.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +namespace sampleprof { + +/// \brief Sample-based profile reader. +/// +/// Each profile contains sample counts for all the functions +/// executed. Inside each function, statements are annotated with the +/// collected samples on all the instructions associated with that +/// statement. +/// +/// For this to produce meaningful data, the program needs to be +/// compiled with some debug information (at minimum, line numbers: +/// -gline-tables-only). Otherwise, it will be impossible to match IR +/// instructions to the line numbers collected by the profiler. +/// +/// From the profile file, we are interested in collecting the +/// following information: +/// +/// * A list of functions included in the profile (mangled names). +/// +/// * For each function F: +/// 1. The total number of samples collected in F. +/// +/// 2. The samples collected at each line in F. To provide some +/// protection against source code shuffling, line numbers should +/// be relative to the start of the function. +/// +/// The reader supports two file formats: text and binary. The text format +/// is useful for debugging and testing, while the binary format is more +/// compact. They can both be used interchangeably. +class SampleProfileReader { +public: + SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) + : Profiles(0), Ctx(C), Buffer(std::move(B)) {} + + virtual ~SampleProfileReader() {} + + /// \brief Read and validate the file header. + virtual std::error_code readHeader() = 0; + + /// \brief Read sample profiles from the associated file. + virtual std::error_code read() = 0; + + /// \brief Print the profile for \p FName on stream \p OS. + void dumpFunctionProfile(StringRef FName, raw_ostream &OS = dbgs()); + + /// \brief Print all the profiles on stream \p OS. + void dump(raw_ostream &OS = dbgs()); + + /// \brief Return the samples collected for function \p F. + FunctionSamples *getSamplesFor(const Function &F) { + return &Profiles[F.getName()]; + } + + /// \brief Return all the profiles. + StringMap<FunctionSamples> &getProfiles() { return Profiles; } + + /// \brief Report a parse error message. + void reportParseError(int64_t LineNumber, Twine Msg) const { + Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(), + LineNumber, Msg)); + } + + /// \brief Create a sample profile reader appropriate to the file format. + static ErrorOr<std::unique_ptr<SampleProfileReader>> + create(StringRef Filename, LLVMContext &C); + +protected: + /// \brief Map every function to its associated profile. + /// + /// The profile of every function executed at runtime is collected + /// in the structure FunctionSamples. This maps function objects + /// to their corresponding profiles. + StringMap<FunctionSamples> Profiles; + + /// \brief LLVM context used to emit diagnostics. + LLVMContext &Ctx; + + /// \brief Memory buffer holding the profile file. + std::unique_ptr<MemoryBuffer> Buffer; +}; + +class SampleProfileReaderText : public SampleProfileReader { +public: + SampleProfileReaderText(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) + : SampleProfileReader(std::move(B), C) {} + + /// \brief Read and validate the file header. + std::error_code readHeader() override { return sampleprof_error::success; } + + /// \brief Read sample profiles from the associated file. + std::error_code read() override; +}; + +class SampleProfileReaderBinary : public SampleProfileReader { +public: + SampleProfileReaderBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) + : SampleProfileReader(std::move(B), C), Data(nullptr), End(nullptr) {} + + /// \brief Read and validate the file header. + std::error_code readHeader() override; + + /// \brief Read sample profiles from the associated file. + std::error_code read() override; + + /// \brief Return true if \p Buffer is in the format supported by this class. + static bool hasFormat(const MemoryBuffer &Buffer); + +protected: + /// \brief Read a numeric value of type T from the profile. + /// + /// If an error occurs during decoding, a diagnostic message is emitted and + /// EC is set. + /// + /// \returns the read value. + template <typename T> ErrorOr<T> readNumber(); + + /// \brief Read a string from the profile. + /// + /// If an error occurs during decoding, a diagnostic message is emitted and + /// EC is set. + /// + /// \returns the read value. + ErrorOr<StringRef> readString(); + + /// \brief Return true if we've reached the end of file. + bool at_eof() const { return Data >= End; } + + /// \brief Points to the current location in the buffer. + const uint8_t *Data; + + /// \brief Points to the end of the buffer. + const uint8_t *End; +}; + +} // End namespace sampleprof + +} // End namespace llvm + +#endif // LLVM_PROFILEDATA_SAMPLEPROFREADER_H diff --git a/include/llvm/ProfileData/SampleProfWriter.h b/include/llvm/ProfileData/SampleProfWriter.h new file mode 100644 index 0000000..302a82d --- /dev/null +++ b/include/llvm/ProfileData/SampleProfWriter.h @@ -0,0 +1,110 @@ +//===- SampleProfWriter.h - Write LLVM sample profile data ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains definitions needed for writing sample profiles. +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_PROFILEDATA_SAMPLEPROFWRITER_H +#define LLVM_PROFILEDATA_SAMPLEPROFWRITER_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Module.h" +#include "llvm/ProfileData/SampleProf.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { + +namespace sampleprof { + +enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC }; + +/// \brief Sample-based profile writer. Base class. +class SampleProfileWriter { +public: + SampleProfileWriter(StringRef Filename, std::error_code &EC, + sys::fs::OpenFlags Flags) + : OS(Filename, EC, Flags) {} + virtual ~SampleProfileWriter() {} + + /// \brief Write sample profiles in \p S for function \p FName. + /// + /// \returns true if the file was updated successfully. False, otherwise. + virtual bool write(StringRef FName, const FunctionSamples &S) = 0; + + /// \brief Write sample profiles in \p S for function \p F. + bool write(const Function &F, const FunctionSamples &S) { + return write(F.getName(), S); + } + + /// \brief Write all the sample profiles for all the functions in \p M. + /// + /// \returns true if the file was updated successfully. False, otherwise. + bool write(const Module &M, StringMap<FunctionSamples> &P) { + for (const auto &F : M) { + StringRef Name = F.getName(); + if (!write(Name, P[Name])) + return false; + } + return true; + } + + /// \brief Write all the sample profiles in the given map of samples. + /// + /// \returns true if the file was updated successfully. False, otherwise. + bool write(StringMap<FunctionSamples> &ProfileMap) { + for (auto &I : ProfileMap) { + StringRef FName = I.first(); + FunctionSamples &Profile = I.second; + if (!write(FName, Profile)) + return false; + } + return true; + } + + /// \brief Profile writer factory. Create a new writer based on the value of + /// \p Format. + static ErrorOr<std::unique_ptr<SampleProfileWriter>> + create(StringRef Filename, SampleProfileFormat Format); + +protected: + /// \brief Output stream where to emit the profile to. + raw_fd_ostream OS; +}; + +/// \brief Sample-based profile writer (text format). +class SampleProfileWriterText : public SampleProfileWriter { +public: + SampleProfileWriterText(StringRef F, std::error_code &EC) + : SampleProfileWriter(F, EC, sys::fs::F_Text) {} + + bool write(StringRef FName, const FunctionSamples &S) override; + bool write(const Module &M, StringMap<FunctionSamples> &P) { + return SampleProfileWriter::write(M, P); + } +}; + +/// \brief Sample-based profile writer (binary format). +class SampleProfileWriterBinary : public SampleProfileWriter { +public: + SampleProfileWriterBinary(StringRef F, std::error_code &EC); + + bool write(StringRef F, const FunctionSamples &S) override; + bool write(const Module &M, StringMap<FunctionSamples> &P) { + return SampleProfileWriter::write(M, P); + } +}; + +} // End namespace sampleprof + +} // End namespace llvm + +#endif // LLVM_PROFILEDATA_SAMPLEPROFWRITER_H |