X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=include%2Fllvm%2FProfileData%2FInstrProf.h;h=f0c89200f28c2b32c8e2820d20038410f31b162e;hp=d4119ed55c4ca4270708ab75d3bec4c4786c5167;hb=ef33c40723046558059b97dccf6ba0c98ff6ad1b;hpb=0bf62648ad5e726ce5bf165b50bf2a86bdaa74bf diff --git a/include/llvm/ProfileData/InstrProf.h b/include/llvm/ProfileData/InstrProf.h index d4119ed55c4..f0c89200f28 100644 --- a/include/llvm/ProfileData/InstrProf.h +++ b/include/llvm/ProfileData/InstrProf.h @@ -18,8 +18,12 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/ProfileData/InstrProfData.inc" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MD5.h" #include #include @@ -28,21 +32,34 @@ namespace llvm { +class Function; +class GlobalVariable; +class Module; + /// Return the name of data section containing profile counter variables. inline StringRef getInstrProfCountersSectionName(bool AddSegment) { - return AddSegment ? "__DATA,__llvm_prf_cnts" : "__llvm_prf_cnts"; + return AddSegment ? "__DATA," INSTR_PROF_CNTS_SECT_NAME_STR + : INSTR_PROF_CNTS_SECT_NAME_STR; } /// Return the name of data section containing names of instrumented /// functions. inline StringRef getInstrProfNameSectionName(bool AddSegment) { - return AddSegment ? "__DATA,__llvm_prf_names" : "__llvm_prf_names"; + return AddSegment ? "__DATA," INSTR_PROF_NAME_SECT_NAME_STR + : INSTR_PROF_NAME_SECT_NAME_STR; } /// Return the name of the data section containing per-function control /// data. inline StringRef getInstrProfDataSectionName(bool AddSegment) { - return AddSegment ? "__DATA,__llvm_prf_data" : "__llvm_prf_data"; + return AddSegment ? "__DATA," INSTR_PROF_DATA_SECT_NAME_STR + : INSTR_PROF_DATA_SECT_NAME_STR; +} + +/// Return the name profile runtime entry point to do value profiling +/// for a given site. +inline StringRef getInstrProfValueProfFuncName() { + return INSTR_PROF_VALUE_PROF_FUNC_STR; } /// Return the name of the section containing function coverage mapping @@ -66,7 +83,7 @@ inline StringRef getInstrProfCountersVarPrefix() { /// associated with a COMDAT function. inline StringRef getInstrProfComdatPrefix() { return "__llvm_profile_vars_"; } -/// Return the name of a covarage mapping variable (internal linkage) +/// Return the name of a covarage mapping variable (internal linkage) /// for each instrumented source module. Such variables are allocated /// in the __llvm_covmap section. inline StringRef getCoverageMappingVarName() { @@ -113,11 +130,37 @@ inline StringRef getInstrProfFileOverriderFuncName() { return "__llvm_profile_override_default_filename"; } +/// Return the modified name for function \c F suitable to be +/// used the key for profile lookup. +std::string getPGOFuncName(const Function &F); + +/// Return the modified name for a function suitable to be +/// used the key for profile lookup. The function's original +/// name is \c RawFuncName and has linkage of type \c Linkage. +/// The function is defined in module \c FileName. +std::string getPGOFuncName(StringRef RawFuncName, + GlobalValue::LinkageTypes Linkage, + StringRef FileName); + +/// Create and return the global variable for function name used in PGO +/// instrumentation. \c FuncName is the name of the function returned +/// by \c getPGOFuncName call. +GlobalVariable *createPGOFuncNameVar(Function &F, StringRef FuncName); + +/// Create and return the global variable for function name used in PGO +/// instrumentation. /// \c FuncName is the name of the function +/// returned by \c getPGOFuncName call, \c M is the owning module, +/// and \c Linkage is the linkage of the instrumented function. +GlobalVariable *createPGOFuncNameVar(Module &M, + GlobalValue::LinkageTypes Linkage, + StringRef FuncName); + const std::error_category &instrprof_category(); enum class instrprof_error { success = 0, eof, + unrecognized_format, bad_magic, bad_header, unsupported_version, @@ -137,10 +180,8 @@ inline std::error_code make_error_code(instrprof_error E) { } enum InstrProfValueKind : uint32_t { - IPVK_IndirectCallTarget = 0, - - IPVK_First = IPVK_IndirectCallTarget, - IPVK_Last = IPVK_IndirectCallTarget +#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value, +#include "llvm/ProfileData/InstrProfData.inc" }; struct InstrProfStringTable { @@ -159,13 +200,6 @@ struct InstrProfStringTable { } }; -struct InstrProfValueData { - // Profiled value. - uint64_t Value; - // Number of times the value appears in the training run. - uint64_t Count; -}; - struct InstrProfValueSiteRecord { /// Value profiling data pairs at a given value site. std::list ValueData; @@ -191,9 +225,10 @@ struct InstrProfValueSiteRecord { auto IE = ValueData.end(); for (auto J = Input.ValueData.begin(), JE = Input.ValueData.end(); J != JE; ++J) { - while (I != IE && I->Value < J->Value) ++I; + while (I != IE && I->Value < J->Value) + ++I; if (I != IE && I->Value == J->Value) { - I->Count += J->Count; + I->Count = SaturatingAdd(I->Count, J->Count); ++I; continue; } @@ -224,23 +259,34 @@ struct InstrProfRecord { /// site: Site. inline uint32_t getNumValueDataForSite(uint32_t ValueKind, uint32_t Site) const; - inline std::unique_ptr getValueForSite( - uint32_t ValueKind, uint32_t Site) const; + /// Return the array of profiled values at \p Site. + inline std::unique_ptr + getValueForSite(uint32_t ValueKind, uint32_t Site, + uint64_t (*ValueMapper)(uint32_t, uint64_t) = 0) const; + inline void + getValueForSite(InstrProfValueData Dest[], uint32_t ValueKind, uint32_t Site, + uint64_t (*ValueMapper)(uint32_t, uint64_t) = 0) const; /// Reserve space for NumValueSites sites. inline void reserveSites(uint32_t ValueKind, uint32_t NumValueSites); /// Add ValueData for ValueKind at value Site. inline void addValueData(uint32_t ValueKind, uint32_t Site, InstrProfValueData *VData, uint32_t N, ValueMapType *HashKeys); - /// Merge Value Profile ddata from Src record to this record for ValueKind. - inline instrprof_error mergeValueProfData(uint32_t ValueKind, - InstrProfRecord &Src); + + /// Merge the counts in \p Other into this one. + inline instrprof_error merge(InstrProfRecord &Other); /// Used by InstrProfWriter: update the value strings to commoned strings in /// the writer instance. inline void updateStrings(InstrProfStringTable *StrTab); - private: + /// Clear value data entries + inline void clearValueData() { + for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) + getValueSitesForKind(Kind).clear(); + } + +private: std::vector IndirectCallSites; const std::vector & getValueSitesForKind(uint32_t ValueKind) const { @@ -259,24 +305,40 @@ struct InstrProfRecord { const_cast(this) ->getValueSitesForKind(ValueKind)); } + // Map indirect call target name hash to name string. uint64_t remapValue(uint64_t Value, uint32_t ValueKind, ValueMapType *HashKeys) { - if (!HashKeys) return Value; + if (!HashKeys) + return Value; switch (ValueKind) { - case IPVK_IndirectCallTarget: { - auto Result = - std::lower_bound(HashKeys->begin(), HashKeys->end(), Value, - [](const std::pair &LHS, - uint64_t RHS) { return LHS.first < RHS; }); - assert(Result != HashKeys->end() && - "Hash does not match any known keys\n"); + case IPVK_IndirectCallTarget: { + auto Result = + std::lower_bound(HashKeys->begin(), HashKeys->end(), Value, + [](const std::pair &LHS, + uint64_t RHS) { return LHS.first < RHS; }); + if (Result != HashKeys->end()) Value = (uint64_t)Result->second; - break; - } + break; + } } return Value; } + + // Merge Value Profile data from Src record to this record for ValueKind. + instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src) { + uint32_t ThisNumValueSites = getNumValueSites(ValueKind); + uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind); + if (ThisNumValueSites != OtherNumValueSites) + return instrprof_error::value_site_count_mismatch; + std::vector &ThisSiteRecords = + getValueSitesForKind(ValueKind); + std::vector &OtherSiteRecords = + Src.getValueSitesForKind(ValueKind); + for (uint32_t I = 0; I < ThisNumValueSites; I++) + ThisSiteRecords[I].mergeValueData(OtherSiteRecords[I]); + return instrprof_error::success; + } }; uint32_t InstrProfRecord::getNumValueKinds() const { @@ -286,6 +348,16 @@ uint32_t InstrProfRecord::getNumValueKinds() const { return NumValueKinds; } +uint32_t InstrProfRecord::getNumValueData(uint32_t ValueKind) const { + uint32_t N = 0; + const std::vector &SiteRecords = + getValueSitesForKind(ValueKind); + for (auto &SR : SiteRecords) { + N += SR.ValueData.size(); + } + return N; +} + uint32_t InstrProfRecord::getNumValueSites(uint32_t ValueKind) const { return getValueSitesForKind(ValueKind).size(); } @@ -296,19 +368,28 @@ uint32_t InstrProfRecord::getNumValueDataForSite(uint32_t ValueKind, } std::unique_ptr InstrProfRecord::getValueForSite( - uint32_t ValueKind, uint32_t Site) const { + uint32_t ValueKind, uint32_t Site, + uint64_t (*ValueMapper)(uint32_t, uint64_t)) const { uint32_t N = getNumValueDataForSite(ValueKind, Site); - if (N == 0) return std::unique_ptr(nullptr); + if (N == 0) + return std::unique_ptr(nullptr); + + auto VD = llvm::make_unique(N); + getValueForSite(VD.get(), ValueKind, Site, ValueMapper); + + return VD; +} - std::unique_ptr VD(new InstrProfValueData[N]); +void InstrProfRecord::getValueForSite(InstrProfValueData Dest[], + uint32_t ValueKind, uint32_t Site, + uint64_t (*ValueMapper)(uint32_t, + uint64_t)) const { uint32_t I = 0; for (auto V : getValueSitesForKind(ValueKind)[Site].ValueData) { - VD[I] = V; + Dest[I].Value = ValueMapper ? ValueMapper(ValueKind, V.Value) : V.Value; + Dest[I].Count = V.Count; I++; } - assert(I == N); - - return VD; } void InstrProfRecord::addValueData(uint32_t ValueKind, uint32_t Site, @@ -331,23 +412,9 @@ void InstrProfRecord::reserveSites(uint32_t ValueKind, uint32_t NumValueSites) { ValueSites.reserve(NumValueSites); } -instrprof_error InstrProfRecord::mergeValueProfData(uint32_t ValueKind, - InstrProfRecord &Src) { - uint32_t ThisNumValueSites = getNumValueSites(ValueKind); - uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind); - if (ThisNumValueSites != OtherNumValueSites) - return instrprof_error::value_site_count_mismatch; - std::vector &ThisSiteRecords = - getValueSitesForKind(ValueKind); - std::vector &OtherSiteRecords = - Src.getValueSitesForKind(ValueKind); - for (uint32_t I = 0; I < ThisNumValueSites; I++) - ThisSiteRecords[I].mergeValueData(OtherSiteRecords[I]); - return instrprof_error::success; -} - void InstrProfRecord::updateStrings(InstrProfStringTable *StrTab) { - if (!StrTab) return; + if (!StrTab) + return; Name = StrTab->insertString(Name); for (auto &VSite : IndirectCallSites) @@ -355,7 +422,176 @@ void InstrProfRecord::updateStrings(InstrProfStringTable *StrTab) { VData.Value = (uint64_t)StrTab->insertString((const char *)VData.Value); } +instrprof_error InstrProfRecord::merge(InstrProfRecord &Other) { + // If the number of counters doesn't match we either have bad data + // or a hash collision. + if (Counts.size() != Other.Counts.size()) + return instrprof_error::count_mismatch; + + for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) { + if (Counts[I] + Other.Counts[I] < Counts[I]) + return instrprof_error::counter_overflow; + Counts[I] += Other.Counts[I]; + } + + for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) { + instrprof_error result = mergeValueProfData(Kind, Other); + if (result != instrprof_error::success) + return result; + } + + return instrprof_error::success; +} + +inline support::endianness getHostEndianness() { + return sys::IsLittleEndianHost ? support::little : support::big; +} + +/// Return the \c ValueProfRecord header size including the padding bytes. +uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites); +/// Return the total size of the value profile record including the +/// header and the value data. +uint32_t getValueProfRecordSize(uint32_t NumValueSites, uint32_t NumValueData); + +/// This is the header of the data structure that defines the on-disk +/// layout of the value profile data of a particular kind for one function. +typedef struct ValueProfRecord { + // The kind of the value profile record. + uint32_t Kind; + // The number of value profile sites. It is guaranteed to be non-zero; + // otherwise the record for this kind won't be emitted. + uint32_t NumValueSites; + // The first element of the array that stores the number of profiled + // values for each value site. The size of the array is NumValueSites. + // Since NumValueSites is greater than zero, there is at least one + // element in the array. + uint8_t SiteCountArray[1]; + + // The fake declaration is for documentation purpose only. + // Align the start of next field to be on 8 byte boundaries. + // uint8_t Padding[X]; + + // The array of value profile data. The size of the array is the sum + // of all elements in SiteCountArray[]. + // InstrProfValueData ValueData[]; + + /// Return the total size of the value profile record including the + /// header and the value data. + uint32_t getSize() const { + return getValueProfRecordSize(NumValueSites, getNumValueData()); + } + /// Use this method to advance to the next \c ValueProfRecord. + ValueProfRecord *getNext(); + /// Return the pointer to the first value profile data. + InstrProfValueData *getValueData(); + /// Return the number of value sites. + uint32_t getNumValueSites() const { return NumValueSites; } + /// Return the number of value data. + uint32_t getNumValueData() const; + /// Read data from this record and save it to Record. + void deserializeTo(InstrProfRecord &Record, + InstrProfRecord::ValueMapType *VMap); + /// Extract data from \c Record and serialize into this instance. + void serializeFrom(const InstrProfRecord &Record, uint32_t ValueKind, + uint32_t NumValueSites); + /// In-place byte swap: + /// Do byte swap for this instance. \c Old is the original order before + /// the swap, and \c New is the New byte order. + void swapBytes(support::endianness Old, support::endianness New); +} ValueProfRecord; + +/// Per-function header/control data structure for value profiling +/// data in indexed format. +typedef struct ValueProfData { + // Total size in bytes including this field. It must be a multiple + // of sizeof(uint64_t). + uint32_t TotalSize; + // The number of value profile kinds that has value profile data. + // In this implementation, a value profile kind is considered to + // have profile data if the number of value profile sites for the + // kind is not zero. More aggressively, the implementation can + // choose to check the actual data value: if none of the value sites + // has any profiled values, the kind can be skipped. + uint32_t NumValueKinds; + + // Following are a sequence of variable length records. The prefix/header + // of each record is defined by ValueProfRecord type. The number of + // records is NumValueKinds. + // ValueProfRecord Record_1; + // ValueProfRecord Record_N; + + /// Return the total size in bytes of the on-disk value profile data + /// given the data stored in Record. + static uint32_t getSize(const InstrProfRecord &Record); + /// Return a pointer to \c ValueProfData instance ready to be streamed. + static std::unique_ptr + serializeFrom(const InstrProfRecord &Record); + /// Return a pointer to \c ValueProfileData instance ready to be read. + /// All data in the instance are properly byte swapped. The input + /// data is assumed to be in little endian order. + static ErrorOr> + getValueProfData(const unsigned char *D, const unsigned char *const BufferEnd, + support::endianness SrcDataEndianness); + /// Swap byte order from \c Endianness order to host byte order. + void swapBytesToHost(support::endianness Endianness); + /// Swap byte order from host byte order to \c Endianness order. + void swapBytesFromHost(support::endianness Endianness); + /// Return the total size of \c ValueProfileData. + uint32_t getSize() const { return TotalSize; } + /// Read data from this data and save it to \c Record. + void deserializeTo(InstrProfRecord &Record, + InstrProfRecord::ValueMapType *VMap); + /// Return the first \c ValueProfRecord instance. + ValueProfRecord *getFirstValueProfRecord(); +} ValueProfData; + +/* The closure is designed to abstact away two types of value profile data: + * - InstrProfRecord which is the primary data structure used to + * represent profile data in host tools (reader, writer, and profile-use) + * - value profile runtime data structure suitable to be used by C + * runtime library. + * + * Both sources of data need to serialize to disk/memory-buffer in common + * format: ValueProfData. The abstraction allows compiler-rt's raw profiler + * writer to share * the same code with indexed profile writer. + * + * For documentation of the member methods below, refer to corresponding methods + * in class InstrProfRecord. + */ +typedef struct ValueProfRecordClosure { + void *Record; + uint32_t (*GetNumValueKinds)(void *Record); + uint32_t (*GetNumValueSites)(void *Record, uint32_t VKind); + uint32_t (*GetNumValueData)(void *Record, uint32_t VKind); + uint32_t (*GetNumValueDataForSite)(void *R, uint32_t VK, uint32_t S); + + /* After extracting the value profile data from the value profile record, + * this method is used to map the in-memory value to on-disk value. If + * the method is null, value will be written out untranslated. + */ + uint64_t (*RemapValueData)(uint32_t, uint64_t Value); + void (*GetValueForSite)(InstrProfValueData *Dst, void *R, uint32_t K, + uint32_t S, uint64_t (*Mapper)(uint32_t, uint64_t)); + + ValueProfData *(*AllocateValueProfData)(size_t TotalSizeInBytes); +} ValueProfRecordClosure; + +inline uint32_t getValueProfRecordHeaderSize(uint32_t NumValueSites) { + uint32_t Size = offsetof(ValueProfRecord, SiteCountArray) + + sizeof(uint8_t) * NumValueSites; + // Round the size to multiple of 8 bytes. + Size = (Size + 7) & ~7; + return Size; +} + +inline uint32_t getValueProfRecordSize(uint32_t NumValueSites, + uint32_t NumValueData) { + return getValueProfRecordHeaderSize(NumValueSites) + + sizeof(InstrProfValueData) * NumValueData; +} + namespace IndexedInstrProf { + enum class HashT : uint32_t { MD5, @@ -375,16 +611,18 @@ static inline uint64_t MD5Hash(StringRef Str) { static inline uint64_t ComputeHash(HashT Type, StringRef K) { switch (Type) { - case HashT::MD5: - return IndexedInstrProf::MD5Hash(K); + case HashT::MD5: + return IndexedInstrProf::MD5Hash(K); } llvm_unreachable("Unhandled hash type"); } -const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81" +const uint64_t Magic = 0x8169666f72706cff; // "\xfflprofi\x81" const uint64_t Version = 3; const HashT HashType = HashT::MD5; +// This structure defines the file header of the LLVM profile +// data file in indexed-format. struct Header { uint64_t Magic; uint64_t Version; @@ -393,69 +631,54 @@ struct Header { uint64_t HashOffset; }; -} // end namespace IndexedInstrProf +} // end namespace IndexedInstrProf namespace RawInstrProf { -const uint64_t Version = 1; - -// Magic number to detect file format and endianness. -// Use 255 at one end, since no UTF-8 file can use that character. Avoid 0, -// so that utilities, like strings, don't grab it as a string. 129 is also -// invalid UTF-8, and high enough to be interesting. -// Use "lprofr" in the centre to stand for "LLVM Profile Raw", or "lprofR" -// for 32-bit platforms. -// The magic and version need to be kept in sync with -// projects/compiler-rt/lib/profile/InstrProfiling.c +const uint64_t Version = INSTR_PROF_RAW_VERSION; -template -inline uint64_t getMagic(); -template <> -inline uint64_t getMagic() { - return uint64_t(255) << 56 | uint64_t('l') << 48 | uint64_t('p') << 40 | - uint64_t('r') << 32 | uint64_t('o') << 24 | uint64_t('f') << 16 | - uint64_t('r') << 8 | uint64_t(129); +template inline uint64_t getMagic(); +template <> inline uint64_t getMagic() { + return INSTR_PROF_RAW_MAGIC_64; } -template <> -inline uint64_t getMagic() { - return uint64_t(255) << 56 | uint64_t('l') << 48 | uint64_t('p') << 40 | - uint64_t('r') << 32 | uint64_t('o') << 24 | uint64_t('f') << 16 | - uint64_t('R') << 8 | uint64_t(129); +template <> inline uint64_t getMagic() { + return INSTR_PROF_RAW_MAGIC_32; } +// Per-function profile data header/control structure. // The definition should match the structure defined in // compiler-rt/lib/profile/InstrProfiling.h. // It should also match the synthesized type in // Transforms/Instrumentation/InstrProfiling.cpp:getOrCreateRegionCounters. - -template -struct ProfileData { +template struct LLVM_ALIGNAS(8) ProfileData { #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Type Name; #include "llvm/ProfileData/InstrProfData.inc" }; +// File header structure of the LLVM profile data in raw format. // The definition should match the header referenced in // compiler-rt/lib/profile/InstrProfilingFile.c and // InstrProfilingBuffer.c. - struct Header { - const uint64_t Magic; - const uint64_t Version; - const uint64_t DataSize; - const uint64_t CountersSize; - const uint64_t NamesSize; - const uint64_t CountersDelta; - const uint64_t NamesDelta; +#define INSTR_PROF_RAW_HEADER(Type, Name, Init) const Type Name; +#include "llvm/ProfileData/InstrProfData.inc" }; } // end namespace RawInstrProf namespace coverage { +// Profile coverage map has the following layout: +// [CoverageMapFileHeader] +// [ArrayStart] +// [CovMapFunctionRecord] +// [CovMapFunctionRecord] +// ... +// [ArrayEnd] +// [Encoded Region Mapping Data] LLVM_PACKED_START -template -struct CovMapFunctionRecord { +template struct CovMapFunctionRecord { #define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; #include "llvm/ProfileData/InstrProfData.inc" };