#ifndef LLVM_PROFILEDATA_INSTRPROF_H_
#define LLVM_PROFILEDATA_INSTRPROF_H_
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Metadata.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 "llvm/Support/MathExtras.h"
#include <cstdint>
#include <list>
#include <map>
#include <system_error>
#include <vector>
namespace llvm {
class Function;
class GlobalVariable;
class Module;
inline StringRef getInstrProfCountersSectionName(bool AddSegment) {
return AddSegment ? "__DATA," INSTR_PROF_CNTS_SECT_NAME_STR
: INSTR_PROF_CNTS_SECT_NAME_STR;
}
inline StringRef getInstrProfNameSectionName(bool AddSegment) {
return AddSegment ? "__DATA," INSTR_PROF_NAME_SECT_NAME_STR
: INSTR_PROF_NAME_SECT_NAME_STR;
}
inline StringRef getInstrProfDataSectionName(bool AddSegment) {
return AddSegment ? "__DATA," INSTR_PROF_DATA_SECT_NAME_STR
: INSTR_PROF_DATA_SECT_NAME_STR;
}
inline StringRef getInstrProfValueProfFuncName() {
return INSTR_PROF_VALUE_PROF_FUNC_STR;
}
inline StringRef getInstrProfCoverageSectionName(bool AddSegment) {
return AddSegment ? "__DATA," INSTR_PROF_COVMAP_SECT_NAME_STR
: INSTR_PROF_COVMAP_SECT_NAME_STR;
}
inline StringRef getInstrProfNameVarPrefix() { return "__profn_"; }
inline StringRef getInstrProfDataVarPrefix() { return "__profd_"; }
inline StringRef getInstrProfCountersVarPrefix() { return "__profc_"; }
inline StringRef getInstrProfComdatPrefix() { return "__profv_"; }
inline StringRef getInstrProfNamesVarName() {
return "__llvm_prf_nm";
}
inline StringRef getCoverageMappingVarName() {
return "__llvm_coverage_mapping";
}
inline StringRef getCoverageUnusedNamesVarName() {
return "__llvm_coverage_names";
}
inline StringRef getInstrProfRegFuncsName() {
return "__llvm_profile_register_functions";
}
inline StringRef getInstrProfRegFuncName() {
return "__llvm_profile_register_function";
}
inline StringRef getInstrProfNamesRegFuncName() {
return "__llvm_profile_register_names_function";
}
inline StringRef getInstrProfInitFuncName() { return "__llvm_profile_init"; }
inline StringRef getInstrProfRuntimeHookVarName() {
return "__llvm_profile_runtime";
}
inline StringRef getInstrProfRuntimeHookVarUseFuncName() {
return "__llvm_profile_runtime_user";
}
inline StringRef getInstrProfFileOverriderFuncName() {
return "__llvm_profile_override_default_filename";
}
inline StringRef getInstrProfNameSeparator() { return "\01"; }
std::string getPGOFuncName(const Function &F, bool InLTO = false,
uint64_t Version = INSTR_PROF_INDEX_VERSION);
std::string getPGOFuncName(StringRef RawFuncName,
GlobalValue::LinkageTypes Linkage,
StringRef FileName,
uint64_t Version = INSTR_PROF_INDEX_VERSION);
std::string getPGOFuncNameVarName(StringRef FuncName,
GlobalValue::LinkageTypes Linkage);
GlobalVariable *createPGOFuncNameVar(Function &F, StringRef PGOFuncName);
GlobalVariable *createPGOFuncNameVar(Module &M,
GlobalValue::LinkageTypes Linkage,
StringRef PGOFuncName);
StringRef getPGOFuncNameVarInitializer(GlobalVariable *NameVar);
StringRef getFuncNameWithoutPrefix(StringRef PGOFuncName,
StringRef FileName = "<unknown>");
std::error_code
collectPGOFuncNameStrings(const std::vector<std::string> &NameStrs,
bool doCompression, std::string &Result);
std::error_code
collectPGOFuncNameStrings(const std::vector<GlobalVariable *> &NameVars,
std::string &Result, bool doCompression = true);
class InstrProfSymtab;
std::error_code readPGOFuncNameStrings(StringRef NameStrings,
InstrProfSymtab &Symtab);
enum InstrProfValueKind : uint32_t {
#define VALUE_PROF_KIND(Enumerator, Value) Enumerator = Value,
#include "llvm/ProfileData/InstrProfData.inc"
};
struct InstrProfRecord;
void annotateValueSite(Module &M, Instruction &Inst,
const InstrProfRecord &InstrProfR,
InstrProfValueKind ValueKind, uint32_t SiteIndx,
uint32_t MaxMDCount = 3);
void annotateValueSite(Module &M, Instruction &Inst,
ArrayRef<InstrProfValueData> VDs,
uint64_t Sum, InstrProfValueKind ValueKind,
uint32_t MaxMDCount);
bool getValueProfDataFromInst(const Instruction &Inst,
InstrProfValueKind ValueKind,
uint32_t MaxNumValueData,
InstrProfValueData ValueData[],
uint32_t &ActualNumValueData, uint64_t &TotalC);
inline StringRef getPGOFuncNameMetadataName() { return "PGOFuncName"; }
inline MDNode *getPGOFuncNameMetadata(const Function &F) {
return F.getMetadata(getPGOFuncNameMetadataName());
}
void createPGOFuncNameMetadata(Function &F, const std::string &PGOFuncName);
const std::error_category &instrprof_category();
enum class instrprof_error {
success = 0,
eof,
unrecognized_format,
bad_magic,
bad_header,
unsupported_version,
unsupported_hash_type,
too_large,
truncated,
malformed,
unknown_function,
hash_mismatch,
count_mismatch,
counter_overflow,
value_site_count_mismatch,
compress_failed,
uncompress_failed
};
inline std::error_code make_error_code(instrprof_error E) {
return std::error_code(static_cast<int>(E), instrprof_category());
}
inline instrprof_error MergeResult(instrprof_error &Accumulator,
instrprof_error Result) {
if (Accumulator == instrprof_error::success &&
Result != instrprof_error::success)
Accumulator = Result;
return Accumulator;
}
namespace object {
class SectionRef;
}
namespace IndexedInstrProf {
uint64_t ComputeHash(StringRef K);
}
class InstrProfSymtab {
public:
typedef std::vector<std::pair<uint64_t, uint64_t>> AddrHashMap;
private:
StringRef Data;
uint64_t Address;
StringSet<> NameTab;
std::vector<std::pair<uint64_t, StringRef>> MD5NameMap;
std::vector<std::pair<uint64_t, Function *>> MD5FuncMap;
AddrHashMap AddrToMD5Map;
public:
InstrProfSymtab()
: Data(), Address(0), NameTab(), MD5NameMap(), MD5FuncMap(),
AddrToMD5Map() {}
std::error_code create(object::SectionRef &Section);
inline std::error_code create(StringRef D, uint64_t BaseAddr);
inline std::error_code create(StringRef NameStrings);
void create(Module &M, bool InLTO = false);
template <typename NameIterRange> void create(const NameIterRange &IterRange);
inline void finalizeSymtab();
void addFuncName(StringRef FuncName) {
auto ins = NameTab.insert(FuncName);
if (ins.second)
MD5NameMap.push_back(std::make_pair(
IndexedInstrProf::ComputeHash(FuncName), ins.first->getKey()));
}
void mapAddress(uint64_t Addr, uint64_t MD5Val) {
AddrToMD5Map.push_back(std::make_pair(Addr, MD5Val));
}
AddrHashMap &getAddrHashMap() { return AddrToMD5Map; }
StringRef getFuncName(uint64_t FuncNameAddress, size_t NameSize);
inline StringRef getFuncName(uint64_t FuncMD5Hash);
inline Function *getFunction(uint64_t FuncMD5Hash);
inline StringRef getOrigFuncName(uint64_t FuncMD5Hash);
inline StringRef getNameData() const { return Data; }
};
std::error_code InstrProfSymtab::create(StringRef D, uint64_t BaseAddr) {
Data = D;
Address = BaseAddr;
return std::error_code();
}
std::error_code InstrProfSymtab::create(StringRef NameStrings) {
return readPGOFuncNameStrings(NameStrings, *this);
}
template <typename NameIterRange>
void InstrProfSymtab::create(const NameIterRange &IterRange) {
for (auto Name : IterRange)
addFuncName(Name);
finalizeSymtab();
}
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());
AddrToMD5Map.erase(std::unique(AddrToMD5Map.begin(), AddrToMD5Map.end()),
AddrToMD5Map.end());
}
StringRef InstrProfSymtab::getFuncName(uint64_t FuncMD5Hash) {
auto Result =
std::lower_bound(MD5NameMap.begin(), MD5NameMap.end(), FuncMD5Hash,
[](const std::pair<uint64_t, std::string> &LHS,
uint64_t RHS) { return LHS.first < RHS; });
if (Result != MD5NameMap.end() && Result->first == FuncMD5Hash)
return Result->second;
return StringRef();
}
Function* InstrProfSymtab::getFunction(uint64_t FuncMD5Hash) {
auto Result =
std::lower_bound(MD5FuncMap.begin(), MD5FuncMap.end(), FuncMD5Hash,
[](const std::pair<uint64_t, Function*> &LHS,
uint64_t RHS) { return LHS.first < RHS; });
if (Result != MD5FuncMap.end() && Result->first == FuncMD5Hash)
return Result->second;
return nullptr;
}
StringRef InstrProfSymtab::getOrigFuncName(uint64_t FuncMD5Hash) {
StringRef PGOName = getFuncName(FuncMD5Hash);
size_t S = PGOName.find_first_of(':');
if (S == StringRef::npos)
return PGOName;
return PGOName.drop_front(S + 1);
}
struct InstrProfValueSiteRecord {
std::list<InstrProfValueData> ValueData;
InstrProfValueSiteRecord() { ValueData.clear(); }
template <class InputIterator>
InstrProfValueSiteRecord(InputIterator F, InputIterator L)
: ValueData(F, L) {}
void sortByTargetValues() {
ValueData.sort(
[](const InstrProfValueData &left, const InstrProfValueData &right) {
return left.Value < right.Value;
});
}
inline void sortByCount();
instrprof_error merge(InstrProfValueSiteRecord &Input, uint64_t Weight = 1);
instrprof_error scale(uint64_t Weight);
};
struct InstrProfRecord {
InstrProfRecord() {}
InstrProfRecord(StringRef Name, uint64_t Hash, std::vector<uint64_t> Counts)
: Name(Name), Hash(Hash), Counts(std::move(Counts)) {}
StringRef Name;
uint64_t Hash;
std::vector<uint64_t> Counts;
typedef std::vector<std::pair<uint64_t, uint64_t>> ValueMapType;
inline uint32_t getNumValueKinds() const;
inline uint32_t getNumValueSites(uint32_t ValueKind) const;
inline uint32_t getNumValueData(uint32_t ValueKind) const;
inline uint32_t getNumValueDataForSite(uint32_t ValueKind,
uint32_t Site) const;
inline std::unique_ptr<InstrProfValueData[]>
getValueForSite(uint32_t ValueKind, uint32_t Site,
uint64_t *TotalC = 0) const;
inline uint64_t getValueForSite(InstrProfValueData Dest[], uint32_t ValueKind,
uint32_t Site) const;
inline void reserveSites(uint32_t ValueKind, uint32_t NumValueSites);
void addValueData(uint32_t ValueKind, uint32_t Site,
InstrProfValueData *VData, uint32_t N,
ValueMapType *ValueMap);
instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1);
instrprof_error scale(uint64_t Weight);
void sortValueData() {
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
std::vector<InstrProfValueSiteRecord> &SiteRecords =
getValueSitesForKind(Kind);
for (auto &SR : SiteRecords)
SR.sortByCount();
}
}
void clearValueData() {
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
getValueSitesForKind(Kind).clear();
}
private:
std::vector<InstrProfValueSiteRecord> IndirectCallSites;
const std::vector<InstrProfValueSiteRecord> &
getValueSitesForKind(uint32_t ValueKind) const {
switch (ValueKind) {
case IPVK_IndirectCallTarget:
return IndirectCallSites;
default:
llvm_unreachable("Unknown value kind!");
}
return IndirectCallSites;
}
std::vector<InstrProfValueSiteRecord> &
getValueSitesForKind(uint32_t ValueKind) {
return const_cast<std::vector<InstrProfValueSiteRecord> &>(
const_cast<const InstrProfRecord *>(this)
->getValueSitesForKind(ValueKind));
}
uint64_t remapValue(uint64_t Value, uint32_t ValueKind,
ValueMapType *HashKeys);
instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
uint64_t Weight);
instrprof_error scaleValueProfData(uint32_t ValueKind, uint64_t Weight);
};
uint32_t InstrProfRecord::getNumValueKinds() const {
uint32_t NumValueKinds = 0;
for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind)
NumValueKinds += !(getValueSitesForKind(Kind).empty());
return NumValueKinds;
}
uint32_t InstrProfRecord::getNumValueData(uint32_t ValueKind) const {
uint32_t N = 0;
const std::vector<InstrProfValueSiteRecord> &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();
}
uint32_t InstrProfRecord::getNumValueDataForSite(uint32_t ValueKind,
uint32_t Site) const {
return getValueSitesForKind(ValueKind)[Site].ValueData.size();
}
std::unique_ptr<InstrProfValueData[]>
InstrProfRecord::getValueForSite(uint32_t ValueKind, uint32_t Site,
uint64_t *TotalC) const {
uint64_t Dummy;
uint64_t &TotalCount = (TotalC == 0 ? Dummy : *TotalC);
uint32_t N = getNumValueDataForSite(ValueKind, Site);
if (N == 0) {
TotalCount = 0;
return std::unique_ptr<InstrProfValueData[]>(nullptr);
}
auto VD = llvm::make_unique<InstrProfValueData[]>(N);
TotalCount = getValueForSite(VD.get(), ValueKind, Site);
return VD;
}
uint64_t InstrProfRecord::getValueForSite(InstrProfValueData Dest[],
uint32_t ValueKind,
uint32_t Site) const {
uint32_t I = 0;
uint64_t TotalCount = 0;
for (auto V : getValueSitesForKind(ValueKind)[Site].ValueData) {
Dest[I].Value = V.Value;
Dest[I].Count = V.Count;
TotalCount = SaturatingAdd(TotalCount, V.Count);
I++;
}
return TotalCount;
}
void InstrProfRecord::reserveSites(uint32_t ValueKind, uint32_t NumValueSites) {
std::vector<InstrProfValueSiteRecord> &ValueSites =
getValueSitesForKind(ValueKind);
ValueSites.reserve(NumValueSites);
}
inline support::endianness getHostEndianness() {
return sys::IsLittleEndianHost ? support::little : support::big;
}
#define INSTR_PROF_VALUE_PROF_DATA
#include "llvm/ProfileData/InstrProfData.inc"
void InstrProfValueSiteRecord::sortByCount() {
ValueData.sort(
[](const InstrProfValueData &left, const InstrProfValueData &right) {
return left.Count > right.Count;
});
size_t max_s = INSTR_PROF_MAX_NUM_VAL_PER_SITE;
if (ValueData.size() > max_s)
ValueData.resize(max_s);
}
int initializeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord,
const uint16_t *NumValueSites,
ValueProfNode **Nodes);
void finalizeValueProfRuntimeRecord(ValueProfRuntimeRecord *RuntimeRecord);
uint32_t getValueProfDataSizeRT(const ValueProfRuntimeRecord *Record);
ValueProfData *
serializeValueProfDataFromRT(const ValueProfRuntimeRecord *Record,
ValueProfData *Dst);
namespace IndexedInstrProf {
struct Summary;
}
struct ProfileSummaryEntry {
uint32_t Cutoff; uint64_t MinBlockCount; uint64_t NumBlocks; ProfileSummaryEntry(uint32_t TheCutoff, uint64_t TheMinBlockCount,
uint64_t TheNumBlocks)
: Cutoff(TheCutoff), MinBlockCount(TheMinBlockCount),
NumBlocks(TheNumBlocks) {}
};
class ProfileSummary {
std::map<uint64_t, uint32_t, std::greater<uint64_t>> CountFrequencies;
std::vector<ProfileSummaryEntry> DetailedSummary;
std::vector<uint32_t> DetailedSummaryCutoffs;
uint64_t TotalCount;
uint64_t MaxBlockCount, MaxInternalBlockCount, MaxFunctionCount;
uint32_t NumBlocks, NumFunctions;
inline void addCount(uint64_t Count, bool IsEntry);
public:
static const int Scale = 1000000;
ProfileSummary(std::vector<uint32_t> Cutoffs)
: DetailedSummaryCutoffs(Cutoffs), TotalCount(0), MaxBlockCount(0),
MaxInternalBlockCount(0), MaxFunctionCount(0), NumBlocks(0),
NumFunctions(0) {}
ProfileSummary(const IndexedInstrProf::Summary &S);
inline void addRecord(const InstrProfRecord &);
inline std::vector<ProfileSummaryEntry> &getDetailedSummary();
void computeDetailedSummary();
uint32_t getNumBlocks() { return NumBlocks; }
uint64_t getTotalCount() { return TotalCount; }
uint32_t getNumFunctions() { return NumFunctions; }
uint64_t getMaxFunctionCount() { return MaxFunctionCount; }
uint64_t getMaxBlockCount() { return MaxBlockCount; }
uint64_t getMaxInternalBlockCount() { return MaxInternalBlockCount; }
};
void ProfileSummary::addCount(uint64_t Count, bool IsEntry) {
TotalCount += Count;
if (Count > MaxBlockCount)
MaxBlockCount = Count;
if (!IsEntry && Count > MaxInternalBlockCount)
MaxInternalBlockCount = Count;
NumBlocks++;
CountFrequencies[Count]++;
}
void ProfileSummary::addRecord(const InstrProfRecord &R) {
NumFunctions++;
if (R.Counts[0] > MaxFunctionCount)
MaxFunctionCount = R.Counts[0];
for (size_t I = 0, E = R.Counts.size(); I < E; ++I)
addCount(R.Counts[I], (I == 0));
}
std::vector<ProfileSummaryEntry> &ProfileSummary::getDetailedSummary() {
if (!DetailedSummaryCutoffs.empty() && DetailedSummary.empty())
computeDetailedSummary();
return DetailedSummary;
}
namespace IndexedInstrProf {
enum class HashT : uint32_t {
MD5,
Last = MD5
};
inline uint64_t ComputeHash(HashT Type, StringRef K) {
switch (Type) {
case HashT::MD5:
return MD5Hash(K);
}
llvm_unreachable("Unhandled hash type");
}
const uint64_t Magic = 0x8169666f72706cff;
enum ProfVersion {
Version1 = 1,
Version2 = 2,
Version3 = 3,
Version4 = 4,
CurrentVersion = INSTR_PROF_INDEX_VERSION
};
const uint64_t Version = ProfVersion::CurrentVersion;
const HashT HashType = HashT::MD5;
inline uint64_t ComputeHash(StringRef K) { return ComputeHash(HashType, K); }
struct Header {
uint64_t Magic;
uint64_t Version;
uint64_t Unused; uint64_t HashType;
uint64_t HashOffset;
};
static const uint32_t SummaryCutoffs[] = {
10000,
100000,
200000, 300000, 400000, 500000, 600000, 500000, 600000, 700000,
800000, 900000, 950000, 990000, 999000, 999900, 999990, 999999};
static const uint32_t NumSummaryCutoffs =
sizeof(SummaryCutoffs) / sizeof(*SummaryCutoffs);
struct Summary {
struct Entry {
uint64_t Cutoff; uint64_t
MinBlockCount; uint64_t NumBlocks; };
enum SummaryFieldKind {
TotalNumFunctions = 0,
TotalNumBlocks = 1,
MaxFunctionCount = 2,
MaxBlockCount = 3,
MaxInternalBlockCount = 4,
TotalBlockCount = 5,
NumKinds = TotalBlockCount + 1
};
uint64_t NumSummaryFields;
uint64_t NumCutoffEntries;
static uint32_t getSize(uint32_t NumSumFields, uint32_t NumCutoffEntries) {
return sizeof(Summary) + NumCutoffEntries * sizeof(Entry) +
NumSumFields * sizeof(uint64_t);
}
const uint64_t *getSummaryDataBase() const {
return reinterpret_cast<const uint64_t *>(this + 1);
}
uint64_t *getSummaryDataBase() {
return reinterpret_cast<uint64_t *>(this + 1);
}
const Entry *getCutoffEntryBase() const {
return reinterpret_cast<const Entry *>(
&getSummaryDataBase()[NumSummaryFields]);
}
Entry *getCutoffEntryBase() {
return reinterpret_cast<Entry *>(&getSummaryDataBase()[NumSummaryFields]);
}
uint64_t get(SummaryFieldKind K) const {
return getSummaryDataBase()[K];
}
void set(SummaryFieldKind K, uint64_t V) {
getSummaryDataBase()[K] = V;
}
const Entry &getEntry(uint32_t I) const { return getCutoffEntryBase()[I]; }
void setEntry(uint32_t I, const ProfileSummaryEntry &E) {
Entry &ER = getCutoffEntryBase()[I];
ER.Cutoff = E.Cutoff;
ER.MinBlockCount = E.MinBlockCount;
ER.NumBlocks = E.NumBlocks;
}
Summary(uint32_t Size) { memset(this, 0, Size); }
void operator delete(void *ptr) { ::operator delete(ptr); }
Summary() = delete;
};
inline std::unique_ptr<Summary> allocSummary(uint32_t TotalSize) {
return std::unique_ptr<Summary>(new (::operator new(TotalSize))
Summary(TotalSize));
}
}
namespace RawInstrProf {
const uint64_t Version = INSTR_PROF_RAW_VERSION;
template <class IntPtrT> inline uint64_t getMagic();
template <> inline uint64_t getMagic<uint64_t>() {
return INSTR_PROF_RAW_MAGIC_64;
}
template <> inline uint64_t getMagic<uint32_t>() {
return INSTR_PROF_RAW_MAGIC_32;
}
template <class IntPtrT> struct LLVM_ALIGNAS(8) ProfileData {
#define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Type Name;
#include "llvm/ProfileData/InstrProfData.inc"
};
struct Header {
#define INSTR_PROF_RAW_HEADER(Type, Name, Init) const Type Name;
#include "llvm/ProfileData/InstrProfData.inc"
};
}
}
namespace std {
template <>
struct is_error_code_enum<llvm::instrprof_error> : std::true_type {};
}
#endif // LLVM_PROFILEDATA_INSTRPROF_H_