diff options
Diffstat (limited to 'include/llvm/ProfileData')
-rw-r--r-- | include/llvm/ProfileData/Coverage/CoverageMapping.h | 3 | ||||
-rw-r--r-- | include/llvm/ProfileData/Coverage/CoverageMappingReader.h | 14 | ||||
-rw-r--r-- | include/llvm/ProfileData/Coverage/CoverageMappingWriter.h | 8 | ||||
-rw-r--r-- | include/llvm/ProfileData/GCOV.h | 5 | ||||
-rw-r--r-- | include/llvm/ProfileData/InstrProf.h | 62 | ||||
-rw-r--r-- | include/llvm/ProfileData/InstrProfData.inc | 22 | ||||
-rw-r--r-- | include/llvm/ProfileData/InstrProfReader.h | 4 | ||||
-rw-r--r-- | include/llvm/ProfileData/ProfileCommon.h | 2 | ||||
-rw-r--r-- | include/llvm/ProfileData/SampleProf.h | 44 | ||||
-rw-r--r-- | include/llvm/ProfileData/SampleProfReader.h | 140 | ||||
-rw-r--r-- | include/llvm/ProfileData/SampleProfWriter.h | 46 |
11 files changed, 238 insertions, 112 deletions
diff --git a/include/llvm/ProfileData/Coverage/CoverageMapping.h b/include/llvm/ProfileData/Coverage/CoverageMapping.h index 5a4098cf666c..1ca56dcaf9c5 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMapping.h +++ b/include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -17,6 +17,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/None.h" #include "llvm/ADT/StringRef.h" @@ -506,7 +507,7 @@ public: /// This is the main interface to get coverage information, using a profile to /// fill out execution counts. class CoverageMapping { - StringSet<> FunctionNames; + DenseMap<size_t, DenseSet<size_t>> RecordProvenance; std::vector<FunctionRecord> Functions; std::vector<std::pair<std::string, uint64_t>> FuncHashMismatches; std::vector<std::pair<std::string, uint64_t>> FuncCounterMismatches; diff --git a/include/llvm/ProfileData/Coverage/CoverageMappingReader.h b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h index 633e51565cd2..c88c71a6d6f4 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMappingReader.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingReader.h @@ -32,7 +32,7 @@ namespace coverage { class CoverageMappingReader; -/// \brief Coverage mapping information for a single function. +/// Coverage mapping information for a single function. struct CoverageMappingRecord { StringRef FunctionName; uint64_t FunctionHash; @@ -41,7 +41,7 @@ struct CoverageMappingRecord { ArrayRef<CounterMappingRegion> MappingRegions; }; -/// \brief A file format agnostic iterator over coverage mapping data. +/// A file format agnostic iterator over coverage mapping data. class CoverageMappingIterator : public std::iterator<std::input_iterator_tag, CoverageMappingRecord> { CoverageMappingReader *Reader; @@ -101,7 +101,7 @@ public: CoverageMappingIterator end() { return CoverageMappingIterator(); } }; -/// \brief Base class for the raw coverage mapping and filenames data readers. +/// Base class for the raw coverage mapping and filenames data readers. class RawCoverageReader { protected: StringRef Data; @@ -114,7 +114,7 @@ protected: Error readString(StringRef &Result); }; -/// \brief Reader for the raw coverage filenames. +/// Reader for the raw coverage filenames. class RawCoverageFilenamesReader : public RawCoverageReader { std::vector<StringRef> &Filenames; @@ -128,7 +128,7 @@ public: Error read(); }; -/// \brief Checks if the given coverage mapping data is exported for +/// Checks if the given coverage mapping data is exported for /// an unused function. class RawCoverageMappingDummyChecker : public RawCoverageReader { public: @@ -138,7 +138,7 @@ public: Expected<bool> isDummy(); }; -/// \brief Reader for the raw coverage mapping data. +/// Reader for the raw coverage mapping data. class RawCoverageMappingReader : public RawCoverageReader { ArrayRef<StringRef> TranslationUnitFilenames; std::vector<StringRef> &Filenames; @@ -169,7 +169,7 @@ private: unsigned InferredFileID, size_t NumFileIDs); }; -/// \brief Reader for the coverage mapping data that is emitted by the +/// Reader for the coverage mapping data that is emitted by the /// frontend and stored in an object file. class BinaryCoverageReader : public CoverageMappingReader { public: diff --git a/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h b/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h index b6f864ab3de3..86fb1bdf1773 100644 --- a/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h +++ b/include/llvm/ProfileData/Coverage/CoverageMappingWriter.h @@ -25,7 +25,7 @@ class raw_ostream; namespace coverage { -/// \brief Writer of the filenames section for the instrumentation +/// Writer of the filenames section for the instrumentation /// based code coverage. class CoverageFilenamesSectionWriter { ArrayRef<StringRef> Filenames; @@ -34,11 +34,11 @@ public: CoverageFilenamesSectionWriter(ArrayRef<StringRef> Filenames) : Filenames(Filenames) {} - /// \brief Write encoded filenames to the given output stream. + /// Write encoded filenames to the given output stream. void write(raw_ostream &OS); }; -/// \brief Writer for instrumentation based coverage mapping data. +/// Writer for instrumentation based coverage mapping data. class CoverageMappingWriter { ArrayRef<unsigned> VirtualFileMapping; ArrayRef<CounterExpression> Expressions; @@ -51,7 +51,7 @@ public: : VirtualFileMapping(VirtualFileMapping), Expressions(Expressions), MappingRegions(MappingRegions) {} - /// \brief Write encoded coverage mapping data to the given output stream. + /// Write encoded coverage mapping data to the given output stream. void write(raw_ostream &OS); }; diff --git a/include/llvm/ProfileData/GCOV.h b/include/llvm/ProfileData/GCOV.h index 497f80b87b26..8500401e44ad 100644 --- a/include/llvm/ProfileData/GCOV.h +++ b/include/llvm/ProfileData/GCOV.h @@ -41,7 +41,7 @@ namespace GCOV { enum GCOVVersion { V402, V404, V704 }; -/// \brief A struct for passing gcov options between functions. +/// A struct for passing gcov options between functions. struct Options { Options(bool A, bool B, bool C, bool F, bool P, bool U, bool L, bool N) : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F), @@ -376,6 +376,7 @@ private: }; class FileInfo { +protected: // It is unlikely--but possible--for multiple functions to be on the same // line. // Therefore this typedef allows LineData.Functions to store multiple @@ -428,7 +429,7 @@ public: void print(raw_ostream &OS, StringRef MainFilename, StringRef GCNOFile, StringRef GCDAFile); -private: +protected: std::string getCoveragePath(StringRef Filename, StringRef MainFilename); std::unique_ptr<raw_ostream> openCoveragePath(StringRef CoveragePath); void printFunctionSummary(raw_ostream &OS, const FunctionVector &Funcs) const; diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h index b08b78cd593c..206142b3565a 100644 --- a/include/llvm/ProfileData/InstrProf.h +++ b/include/llvm/ProfileData/InstrProf.h @@ -425,9 +425,20 @@ private: // A map from function runtime address to function name MD5 hash. // This map is only populated and used by raw instr profile reader. AddrHashMap AddrToMD5Map; + bool Sorted = false; + + static StringRef getExternalSymbol() { + return "** External Symbol **"; + } + + // If the symtab is created by a series of calls to \c addFuncName, \c + // finalizeSymtab needs to be called before looking up function names. + // This is required because the underlying map is a vector (for space + // efficiency) which needs to be sorted. + inline void finalizeSymtab(); public: - InstrProfSymtab() = default; + InstrProfSymtab() = default; /// Create InstrProfSymtab from an object file section which /// contains function PGO names. When section may contain raw @@ -456,21 +467,17 @@ public: /// \p IterRange. This interface is used by IndexedProfReader. template <typename NameIterRange> Error create(const NameIterRange &IterRange); - // If the symtab is created by a series of calls to \c addFuncName, \c - // finalizeSymtab needs to be called before looking up function names. - // This is required because the underlying map is a vector (for space - // efficiency) which needs to be sorted. - inline void finalizeSymtab(); - /// Update the symtab by adding \p FuncName to the table. This interface /// is used by the raw and text profile readers. Error addFuncName(StringRef FuncName) { if (FuncName.empty()) return make_error<InstrProfError>(instrprof_error::malformed); auto Ins = NameTab.insert(FuncName); - if (Ins.second) + if (Ins.second) { MD5NameMap.push_back(std::make_pair( IndexedInstrProf::ComputeHash(FuncName), Ins.first->getKey())); + Sorted = false; + } return Error::success(); } @@ -480,7 +487,8 @@ public: AddrToMD5Map.push_back(std::make_pair(Addr, MD5Val)); } - AddrHashMap &getAddrHashMap() { return AddrToMD5Map; } + /// Return a function's hash, or 0, if the function isn't in this SymTab. + uint64_t getFunctionHashFromAddress(uint64_t Address); /// Return function's PGO name from the function name's symbol /// address in the object file. If an error occurs, return @@ -491,6 +499,16 @@ public: /// If not found, return an empty string. inline StringRef getFuncName(uint64_t FuncMD5Hash); + /// Just like getFuncName, except that it will return a non-empty StringRef + /// if the function is external to this symbol table. All such cases + /// will be represented using the same StringRef value. + inline StringRef getFuncNameOrExternalSymbol(uint64_t FuncMD5Hash); + + /// True if Symbol is the value used to represent external symbols. + static bool isExternalSymbol(const StringRef &Symbol) { + return Symbol == InstrProfSymtab::getExternalSymbol(); + } + /// Return function from the name's md5 hash. Return nullptr if not found. inline Function *getFunction(uint64_t FuncMD5Hash); @@ -524,14 +542,25 @@ Error InstrProfSymtab::create(const NameIterRange &IterRange) { } void InstrProfSymtab::finalizeSymtab() { - std::sort(MD5NameMap.begin(), MD5NameMap.end(), less_first()); - std::sort(MD5FuncMap.begin(), MD5FuncMap.end(), less_first()); - std::sort(AddrToMD5Map.begin(), AddrToMD5Map.end(), less_first()); + if (Sorted) + return; + llvm::sort(MD5NameMap.begin(), MD5NameMap.end(), less_first()); + llvm::sort(MD5FuncMap.begin(), MD5FuncMap.end(), less_first()); + llvm::sort(AddrToMD5Map.begin(), AddrToMD5Map.end(), less_first()); AddrToMD5Map.erase(std::unique(AddrToMD5Map.begin(), AddrToMD5Map.end()), AddrToMD5Map.end()); + Sorted = true; +} + +StringRef InstrProfSymtab::getFuncNameOrExternalSymbol(uint64_t FuncMD5Hash) { + StringRef ret = getFuncName(FuncMD5Hash); + if (ret.empty()) + return InstrProfSymtab::getExternalSymbol(); + return ret; } StringRef InstrProfSymtab::getFuncName(uint64_t FuncMD5Hash) { + finalizeSymtab(); auto Result = std::lower_bound(MD5NameMap.begin(), MD5NameMap.end(), FuncMD5Hash, [](const std::pair<uint64_t, std::string> &LHS, @@ -542,6 +571,7 @@ StringRef InstrProfSymtab::getFuncName(uint64_t FuncMD5Hash) { } Function* InstrProfSymtab::getFunction(uint64_t FuncMD5Hash) { + finalizeSymtab(); auto Result = std::lower_bound(MD5FuncMap.begin(), MD5FuncMap.end(), FuncMD5Hash, [](const std::pair<uint64_t, Function*> &LHS, @@ -614,8 +644,6 @@ struct InstrProfRecord { return *this; } - using ValueMapType = std::vector<std::pair<uint64_t, uint64_t>>; - /// Return the number of value profile kinds with non-zero number /// of profile sites. inline uint32_t getNumValueKinds() const; @@ -649,7 +677,7 @@ struct InstrProfRecord { /// Add ValueData for ValueKind at value Site. void addValueData(uint32_t ValueKind, uint32_t Site, InstrProfValueData *VData, uint32_t N, - ValueMapType *ValueMap); + InstrProfSymtab *SymTab); /// Merge the counts in \p Other into this one. /// Optionally scale merged counts by \p Weight. @@ -723,7 +751,7 @@ private: // Map indirect call target name hash to name string. uint64_t remapValue(uint64_t Value, uint32_t ValueKind, - ValueMapType *HashKeys); + InstrProfSymtab *SymTab); // Merge Value Profile data from Src record to this record for ValueKind. // Scale merged value counts by \p Weight. @@ -993,7 +1021,7 @@ template <> inline uint64_t getMagic<uint32_t>() { // compiler-rt/lib/profile/InstrProfiling.h. // It should also match the synthesized type in // Transforms/Instrumentation/InstrProfiling.cpp:getOrCreateRegionCounters. -template <class IntPtrT> struct LLVM_ALIGNAS(8) ProfileData { +template <class IntPtrT> struct alignas(8) ProfileData { #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Type Name; #include "llvm/ProfileData/InstrProfData.inc" }; diff --git a/include/llvm/ProfileData/InstrProfData.inc b/include/llvm/ProfileData/InstrProfData.inc index 6a98dc7b9b85..454620ed997a 100644 --- a/include/llvm/ProfileData/InstrProfData.inc +++ b/include/llvm/ProfileData/InstrProfData.inc @@ -178,7 +178,7 @@ VALUE_PROF_FUNC_PARAM(uint64_t, LargeValue, Type::getInt64Ty(Ctx)) * functions are profiled by the instrumented code. The target addresses are * written in the raw profile data and converted to target function name's MD5 * hash by the profile reader during deserialization. Typically, this happens - * when the the raw profile data is read during profile merging. + * when the raw profile data is read during profile merging. * * For this remapping the ProfData is used. ProfData contains both the function * name hash and the function address. @@ -308,14 +308,14 @@ typedef struct ValueProfRecord { #ifdef __cplusplus /*! - * \brief Return the number of value sites. + * Return the number of value sites. */ uint32_t getNumValueSites() const { return NumValueSites; } /*! - * \brief Read data from this record and save it to Record. + * Read data from this record and save it to Record. */ void deserializeTo(InstrProfRecord &Record, - InstrProfRecord::ValueMapType *VMap); + InstrProfSymtab *SymTab); /* * In-place byte swap: * Do byte swap for this instance. \c Old is the original order before @@ -393,7 +393,7 @@ typedef struct ValueProfData { * Read data from this data and save it to \c Record. */ void deserializeTo(InstrProfRecord &Record, - InstrProfRecord::ValueMapType *VMap); + InstrProfSymtab *SymTab); void operator delete(void *ptr) { ::operator delete(ptr); } #endif } ValueProfData; @@ -458,7 +458,7 @@ getValueProfRecordHeaderSize(uint32_t NumValueSites); #endif /*! - * \brief Return the \c ValueProfRecord header size including the + * Return the \c ValueProfRecord header size including the * padding bytes. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE @@ -471,7 +471,7 @@ uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { } /*! - * \brief Return the total size of the value profile record including the + * Return the total size of the value profile record including the * header and the value data. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE @@ -482,7 +482,7 @@ uint32_t getValueProfRecordSize(uint32_t NumValueSites, } /*! - * \brief Return the pointer to the start of value data array. + * Return the pointer to the start of value data array. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { @@ -491,7 +491,7 @@ InstrProfValueData *getValueProfRecordValueData(ValueProfRecord *This) { } /*! - * \brief Return the total number of value data for \c This record. + * Return the total number of value data for \c This record. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { @@ -503,7 +503,7 @@ uint32_t getValueProfRecordNumValueData(ValueProfRecord *This) { } /*! - * \brief Use this method to advance to the next \c This \c ValueProfRecord. + * Use this method to advance to the next \c This \c ValueProfRecord. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { @@ -514,7 +514,7 @@ ValueProfRecord *getValueProfRecordNext(ValueProfRecord *This) { } /*! - * \brief Return the first \c ValueProfRecord instance. + * Return the first \c ValueProfRecord instance. */ INSTR_PROF_VISIBILITY INSTR_PROF_INLINE ValueProfRecord *getFirstValueProfRecord(ValueProfData *This) { diff --git a/include/llvm/ProfileData/InstrProfReader.h b/include/llvm/ProfileData/InstrProfReader.h index aa58ead1eda1..efc22dcd0d9a 100644 --- a/include/llvm/ProfileData/InstrProfReader.h +++ b/include/llvm/ProfileData/InstrProfReader.h @@ -101,7 +101,7 @@ protected: return make_error<InstrProfError>(Err); } - Error error(Error E) { return error(InstrProfError::take(std::move(E))); } + Error error(Error &&E) { return error(InstrProfError::take(std::move(E))); } /// Clear the current error and return a successful one. Error success() { return error(instrprof_error::success); } @@ -199,8 +199,6 @@ private: uint32_t ValueKindLast; uint32_t CurValueDataSize; - InstrProfRecord::ValueMapType FunctionPtrToNameMap; - public: RawInstrProfReader(std::unique_ptr<MemoryBuffer> DataBuffer) : DataBuffer(std::move(DataBuffer)) {} diff --git a/include/llvm/ProfileData/ProfileCommon.h b/include/llvm/ProfileData/ProfileCommon.h index 51b065bcdb70..087588f06340 100644 --- a/include/llvm/ProfileData/ProfileCommon.h +++ b/include/llvm/ProfileData/ProfileCommon.h @@ -61,7 +61,7 @@ protected: void computeDetailedSummary(); public: - /// \brief A vector of useful cutoff values for detailed summary. + /// A vector of useful cutoff values for detailed summary. static const ArrayRef<uint32_t> DefaultCutoffs; }; diff --git a/include/llvm/ProfileData/SampleProf.h b/include/llvm/ProfileData/SampleProf.h index 641631cc4ec9..0cd6dd2c2c0e 100644 --- a/include/llvm/ProfileData/SampleProf.h +++ b/include/llvm/ProfileData/SampleProf.h @@ -78,11 +78,29 @@ struct is_error_code_enum<llvm::sampleprof_error> : std::true_type {}; namespace llvm { namespace sampleprof { -static inline uint64_t SPMagic() { +enum SampleProfileFormat { + SPF_None = 0, + SPF_Text = 0x1, + SPF_Compact_Binary = 0x2, + SPF_GCC = 0x3, + SPF_Binary = 0xff +}; + +static inline uint64_t SPMagic(SampleProfileFormat Format = SPF_Binary) { 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); + uint64_t('2') << (64 - 56) | uint64_t(Format); +} + +// Get the proper representation of a string in the input Format. +static inline StringRef getRepInFormat(StringRef Name, + SampleProfileFormat Format, + std::string &GUIDBuf) { + if (Name.empty()) + return Name; + GUIDBuf = std::to_string(Function::getGUID(Name)); + return (Format == SPF_Compact_Binary) ? StringRef(GUIDBuf) : Name; } static inline uint64_t SPVersion() { return 103; } @@ -359,7 +377,7 @@ public: /// GUID to \p S. Also traverse the BodySamples to add hot CallTarget's GUID /// to \p S. void findInlinedFunctions(DenseSet<GlobalValue::GUID> &S, const Module *M, - uint64_t Threshold) const { + uint64_t Threshold, bool isCompact) const { if (TotalSamples <= Threshold) return; S.insert(Function::getGUID(Name)); @@ -370,11 +388,12 @@ public: if (TS.getValue() > Threshold) { Function *Callee = M->getFunction(TS.getKey()); if (!Callee || !Callee->getSubprogram()) - S.insert(Function::getGUID(TS.getKey())); + S.insert(isCompact ? std::stol(TS.getKey().data()) + : Function::getGUID(TS.getKey())); } for (const auto &CS : CallsiteSamples) for (const auto &NameFS : CS.second) - NameFS.second.findInlinedFunctions(S, M, Threshold); + NameFS.second.findInlinedFunctions(S, M, Threshold, isCompact); } /// Set the name of the function. @@ -383,6 +402,21 @@ public: /// Return the function name. const StringRef &getName() const { return Name; } + /// Returns the line offset to the start line of the subprogram. + /// We assume that a single function will not exceed 65535 LOC. + static unsigned getOffset(const DILocation *DIL); + + /// Get the FunctionSamples of the inline instance where DIL originates + /// from. + /// + /// The FunctionSamples of the instruction (Machine or IR) associated to + /// \p DIL is the inlined instance in which that instruction is coming from. + /// We traverse the inline stack of that instruction, and match it with the + /// tree nodes in the profile. + /// + /// \returns the FunctionSamples pointer to the inlined instance. + const FunctionSamples *findFunctionSamples(const DILocation *DIL) const; + private: /// Mangled name of the function. StringRef Name; diff --git a/include/llvm/ProfileData/SampleProfReader.h b/include/llvm/ProfileData/SampleProfReader.h index 0e9ab2dc60ee..0617b05e8d4f 100644 --- a/include/llvm/ProfileData/SampleProfReader.h +++ b/include/llvm/ProfileData/SampleProfReader.h @@ -235,7 +235,7 @@ class raw_ostream; namespace sampleprof { -/// \brief Sample-based profile reader. +/// Sample-based profile reader. /// /// Each profile contains sample counts for all the functions /// executed. Inside each function, statements are annotated with the @@ -264,105 +264,113 @@ namespace sampleprof { /// compact and I/O efficient. 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)) {} + SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C, + SampleProfileFormat Format = SPF_None) + : Profiles(0), Ctx(C), Buffer(std::move(B)), Format(Format) {} virtual ~SampleProfileReader() = default; - /// \brief Read and validate the file header. + /// Read and validate the file header. virtual std::error_code readHeader() = 0; - /// \brief Read sample profiles from the associated file. + /// Read sample profiles from the associated file. virtual std::error_code read() = 0; - /// \brief Print the profile for \p FName on stream \p OS. + /// 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. + /// Print all the profiles on stream \p OS. void dump(raw_ostream &OS = dbgs()); - /// \brief Return the samples collected for function \p F. + /// Return the samples collected for function \p F. FunctionSamples *getSamplesFor(const Function &F) { // The function name may have been updated by adding suffix. In sample // profile, the function names are all stripped, so we need to strip // the function name suffix before matching with profile. - if (Profiles.count(F.getName().split('.').first)) - return &Profiles[(F.getName().split('.').first)]; + StringRef Fname = F.getName().split('.').first; + std::string FGUID; + Fname = getRepInFormat(Fname, getFormat(), FGUID); + if (Profiles.count(Fname)) + return &Profiles[Fname]; return nullptr; } - /// \brief Return all the profiles. + /// Return all the profiles. StringMap<FunctionSamples> &getProfiles() { return Profiles; } - /// \brief Report a parse error message. + /// Report a parse error message. void reportError(int64_t LineNumber, Twine Msg) const { Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(), LineNumber, Msg)); } - /// \brief Create a sample profile reader appropriate to the file format. + /// Create a sample profile reader appropriate to the file format. static ErrorOr<std::unique_ptr<SampleProfileReader>> create(const Twine &Filename, LLVMContext &C); - /// \brief Create a sample profile reader from the supplied memory buffer. + /// Create a sample profile reader from the supplied memory buffer. static ErrorOr<std::unique_ptr<SampleProfileReader>> create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C); - /// \brief Return the profile summary. + /// Return the profile summary. ProfileSummary &getSummary() { return *(Summary.get()); } + /// \brief Return the profile format. + SampleProfileFormat getFormat() { return Format; } + protected: - /// \brief Map every function to its associated profile. + /// 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. + /// LLVM context used to emit diagnostics. LLVMContext &Ctx; - /// \brief Memory buffer holding the profile file. + /// Memory buffer holding the profile file. std::unique_ptr<MemoryBuffer> Buffer; - /// \brief Profile summary information. + /// Profile summary information. std::unique_ptr<ProfileSummary> Summary; - /// \brief Compute summary for this profile. + /// Compute summary for this profile. void computeSummary(); + + /// \brief The format of sample. + SampleProfileFormat Format = SPF_None; }; class SampleProfileReaderText : public SampleProfileReader { public: SampleProfileReaderText(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) - : SampleProfileReader(std::move(B), C) {} + : SampleProfileReader(std::move(B), C, SPF_Text) {} - /// \brief Read and validate the file header. + /// Read and validate the file header. std::error_code readHeader() override { return sampleprof_error::success; } - /// \brief Read sample profiles from the associated file. + /// 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. + /// Return true if \p Buffer is in the format supported by this class. static bool hasFormat(const MemoryBuffer &Buffer); }; class SampleProfileReaderBinary : public SampleProfileReader { public: - SampleProfileReaderBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) - : SampleProfileReader(std::move(B), C) {} + SampleProfileReaderBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C, + SampleProfileFormat Format = SPF_None) + : SampleProfileReader(std::move(B), C, Format) {} - /// \brief Read and validate the file header. + /// Read and validate the file header. std::error_code readHeader() override; - /// \brief Read sample profiles from the associated file. + /// 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. + /// 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. @@ -370,7 +378,7 @@ protected: /// \returns the read value. template <typename T> ErrorOr<T> readNumber(); - /// \brief Read a string from the profile. + /// Read a string from the profile. /// /// If an error occurs during decoding, a diagnostic message is emitted and /// EC is set. @@ -378,29 +386,68 @@ protected: /// \returns the read value. ErrorOr<StringRef> readString(); - /// Read a string indirectly via the name table. - ErrorOr<StringRef> readStringFromTable(); + /// Read the string index and check whether it overflows the table. + template <typename T> inline ErrorOr<uint32_t> readStringIndex(T &Table); - /// \brief Return true if we've reached the end of file. + /// Return true if we've reached the end of file. bool at_eof() const { return Data >= End; } /// Read the contents of the given profile instance. std::error_code readProfile(FunctionSamples &FProfile); - /// \brief Points to the current location in the buffer. + /// Points to the current location in the buffer. const uint8_t *Data = nullptr; - /// \brief Points to the end of the buffer. + /// Points to the end of the buffer. const uint8_t *End = nullptr; +private: + std::error_code readSummaryEntry(std::vector<ProfileSummaryEntry> &Entries); + virtual std::error_code verifySPMagic(uint64_t Magic) = 0; + + /// Read profile summary. + std::error_code readSummary(); + + /// Read the whole name table. + virtual std::error_code readNameTable() = 0; + + /// Read a string indirectly via the name table. + virtual ErrorOr<StringRef> readStringFromTable() = 0; +}; + +class SampleProfileReaderRawBinary : public SampleProfileReaderBinary { +private: /// Function name table. std::vector<StringRef> NameTable; + virtual std::error_code verifySPMagic(uint64_t Magic) override; + virtual std::error_code readNameTable() override; + /// Read a string indirectly via the name table. + virtual ErrorOr<StringRef> readStringFromTable() override; + +public: + SampleProfileReaderRawBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) + : SampleProfileReaderBinary(std::move(B), C, SPF_Binary) {} + + /// \brief Return true if \p Buffer is in the format supported by this class. + static bool hasFormat(const MemoryBuffer &Buffer); +}; +class SampleProfileReaderCompactBinary : public SampleProfileReaderBinary { private: - std::error_code readSummaryEntry(std::vector<ProfileSummaryEntry> &Entries); + /// Function name table. + std::vector<std::string> NameTable; + virtual std::error_code verifySPMagic(uint64_t Magic) override; + virtual std::error_code readNameTable() override; + /// Read a string indirectly via the name table. + virtual ErrorOr<StringRef> readStringFromTable() override; - /// \brief Read profile summary. - std::error_code readSummary(); +public: + SampleProfileReaderCompactBinary(std::unique_ptr<MemoryBuffer> B, + LLVMContext &C) + : SampleProfileReaderBinary(std::move(B), C, SPF_Compact_Binary) {} + + /// \brief Return true if \p Buffer is in the format supported by this class. + static bool hasFormat(const MemoryBuffer &Buffer); }; using InlineCallStack = SmallVector<FunctionSamples *, 10>; @@ -421,15 +468,16 @@ enum HistType { class SampleProfileReaderGCC : public SampleProfileReader { public: SampleProfileReaderGCC(std::unique_ptr<MemoryBuffer> B, LLVMContext &C) - : SampleProfileReader(std::move(B), C), GcovBuffer(Buffer.get()) {} + : SampleProfileReader(std::move(B), C, SPF_GCC), + GcovBuffer(Buffer.get()) {} - /// \brief Read and validate the file header. + /// Read and validate the file header. std::error_code readHeader() override; - /// \brief Read sample profiles from the associated file. + /// 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. + /// Return true if \p Buffer is in the format supported by this class. static bool hasFormat(const MemoryBuffer &Buffer); protected: @@ -441,7 +489,7 @@ protected: template <typename T> ErrorOr<T> readNumber(); ErrorOr<StringRef> readString(); - /// \brief Read the section tag and check that it's the same as \p Expected. + /// Read the section tag and check that it's the same as \p Expected. std::error_code readSectionTag(uint32_t Expected); /// GCOV buffer containing the profile. diff --git a/include/llvm/ProfileData/SampleProfWriter.h b/include/llvm/ProfileData/SampleProfWriter.h index 86af1038d74e..74dc839ff049 100644 --- a/include/llvm/ProfileData/SampleProfWriter.h +++ b/include/llvm/ProfileData/SampleProfWriter.h @@ -23,14 +23,13 @@ #include <algorithm> #include <cstdint> #include <memory> +#include <set> #include <system_error> namespace llvm { namespace sampleprof { -enum SampleProfileFormat { SPF_None = 0, SPF_Text, SPF_Binary, SPF_GCC }; - -/// \brief Sample-based profile writer. Base class. +/// Sample-based profile writer. Base class. class SampleProfileWriter { public: virtual ~SampleProfileWriter() = default; @@ -62,21 +61,21 @@ protected: SampleProfileWriter(std::unique_ptr<raw_ostream> &OS) : OutputStream(std::move(OS)) {} - /// \brief Write a file header for the profile file. + /// Write a file header for the profile file. virtual std::error_code writeHeader(const StringMap<FunctionSamples> &ProfileMap) = 0; - /// \brief Output stream where to emit the profile to. + /// Output stream where to emit the profile to. std::unique_ptr<raw_ostream> OutputStream; - /// \brief Profile summary. + /// Profile summary. std::unique_ptr<ProfileSummary> Summary; - /// \brief Compute summary for this profile. + /// Compute summary for this profile. void computeSummary(const StringMap<FunctionSamples> &ProfileMap); }; -/// \brief Sample-based profile writer (text format). +/// Sample-based profile writer (text format). class SampleProfileWriterText : public SampleProfileWriter { public: std::error_code write(const FunctionSamples &S) override; @@ -101,32 +100,49 @@ private: SampleProfileFormat Format); }; -/// \brief Sample-based profile writer (binary format). +/// Sample-based profile writer (binary format). class SampleProfileWriterBinary : public SampleProfileWriter { public: std::error_code write(const FunctionSamples &S) override; - -protected: SampleProfileWriterBinary(std::unique_ptr<raw_ostream> &OS) : SampleProfileWriter(OS) {} - std::error_code - writeHeader(const StringMap<FunctionSamples> &ProfileMap) override; +protected: + virtual std::error_code writeNameTable() = 0; + virtual std::error_code writeMagicIdent() = 0; + std::error_code writeHeader(const StringMap<FunctionSamples> &ProfileMap) override; std::error_code writeSummary(); std::error_code writeNameIdx(StringRef FName); std::error_code writeBody(const FunctionSamples &S); + inline void stablizeNameTable(std::set<StringRef> &V); + + MapVector<StringRef, uint32_t> NameTable; private: void addName(StringRef FName); void addNames(const FunctionSamples &S); - MapVector<StringRef, uint32_t> NameTable; - friend ErrorOr<std::unique_ptr<SampleProfileWriter>> SampleProfileWriter::create(std::unique_ptr<raw_ostream> &OS, SampleProfileFormat Format); }; +class SampleProfileWriterRawBinary : public SampleProfileWriterBinary { + using SampleProfileWriterBinary::SampleProfileWriterBinary; + +protected: + virtual std::error_code writeNameTable() override; + virtual std::error_code writeMagicIdent() override; +}; + +class SampleProfileWriterCompactBinary : public SampleProfileWriterBinary { + using SampleProfileWriterBinary::SampleProfileWriterBinary; + +protected: + virtual std::error_code writeNameTable() override; + virtual std::error_code writeMagicIdent() override; +}; + } // end namespace sampleprof } // end namespace llvm |