#ifndef LLVM_PROFILEDATA_SAMPLEPROFREADER_H
#define LLVM_PROFILEDATA_SAMPLEPROFREADER_H
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/ProfileSummary.h"
#include "llvm/ProfileData/GCOV.h"
#include "llvm/ProfileData/SampleProf.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Discriminator.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/SymbolRemappingReader.h"
#include <cstdint>
#include <list>
#include <memory>
#include <string>
#include <system_error>
#include <unordered_set>
#include <vector>
namespace llvm {
class raw_ostream;
class Twine;
namespace sampleprof {
class SampleProfileReader;
class SampleProfileReaderItaniumRemapper {
public:
SampleProfileReaderItaniumRemapper(std::unique_ptr<MemoryBuffer> B,
std::unique_ptr<SymbolRemappingReader> SRR,
SampleProfileReader &R)
: Buffer(std::move(B)), Remappings(std::move(SRR)), Reader(R) {
assert(Remappings && "Remappings cannot be nullptr");
}
static ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
create(const std::string Filename, SampleProfileReader &Reader,
LLVMContext &C);
static ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
create(std::unique_ptr<MemoryBuffer> &B, SampleProfileReader &Reader,
LLVMContext &C);
void applyRemapping(LLVMContext &Ctx);
bool hasApplied() { return RemappingApplied; }
void insert(StringRef FunctionName) { Remappings->insert(FunctionName); }
bool exist(StringRef FunctionName) {
return Remappings->lookup(FunctionName);
}
Optional<StringRef> lookUpNameInProfile(StringRef FunctionName);
private:
std::unique_ptr<MemoryBuffer> Buffer;
std::unique_ptr<SymbolRemappingReader> Remappings;
DenseMap<SymbolRemappingReader::Key, StringRef> NameMap;
SampleProfileReader &Reader;
bool RemappingApplied = false;
};
class SampleProfileReader {
public:
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;
virtual std::error_code readHeader() = 0;
void setDiscriminatorMaskedBitFrom(FSDiscriminatorPass P) {
MaskedBitFrom = getFSPassBitEnd(P);
}
uint32_t getDiscriminatorMask() const {
if (!ProfileIsFS)
return 0xFFFFFFFF;
assert((MaskedBitFrom != 0) && "MaskedBitFrom is not set properly");
return getN1Bits(MaskedBitFrom);
}
std::error_code read() {
if (std::error_code EC = readImpl())
return EC;
if (Remapper)
Remapper->applyRemapping(Ctx);
FunctionSamples::UseMD5 = useMD5();
return sampleprof_error::success;
}
virtual std::error_code readImpl() = 0;
void dumpFunctionProfile(SampleContext FContext, raw_ostream &OS = dbgs());
virtual bool collectFuncsFromModule() { return false; }
void dump(raw_ostream &OS = dbgs());
FunctionSamples *getSamplesFor(const Function &F) {
StringRef CanonName = FunctionSamples::getCanonicalFnName(F);
return getSamplesFor(CanonName);
}
FunctionSamples *getOrCreateSamplesFor(const Function &F) {
std::string FGUID;
StringRef CanonName = FunctionSamples::getCanonicalFnName(F);
CanonName = getRepInFormat(CanonName, useMD5(), FGUID);
auto It = Profiles.find(CanonName);
if (It != Profiles.end())
return &It->second;
if (!FGUID.empty()) {
assert(useMD5() && "New name should only be generated for md5 profile");
CanonName = *MD5NameBuffer.insert(FGUID).first;
}
return &Profiles[CanonName];
}
virtual FunctionSamples *getSamplesFor(StringRef Fname) {
std::string FGUID;
Fname = getRepInFormat(Fname, useMD5(), FGUID);
auto It = Profiles.find(Fname);
if (It != Profiles.end())
return &It->second;
if (Remapper) {
if (auto NameInProfile = Remapper->lookUpNameInProfile(Fname)) {
auto It = Profiles.find(*NameInProfile);
if (It != Profiles.end())
return &It->second;
}
}
return nullptr;
}
SampleProfileMap &getProfiles() { return Profiles; }
void reportError(int64_t LineNumber, const Twine &Msg) const {
Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(),
LineNumber, Msg));
}
static ErrorOr<std::unique_ptr<SampleProfileReader>>
create(const std::string Filename, LLVMContext &C,
FSDiscriminatorPass P = FSDiscriminatorPass::Base,
const std::string RemapFilename = "");
static ErrorOr<std::unique_ptr<SampleProfileReader>>
create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
FSDiscriminatorPass P = FSDiscriminatorPass::Base,
const std::string RemapFilename = "");
ProfileSummary &getSummary() const { return *(Summary.get()); }
MemoryBuffer *getBuffer() const { return Buffer.get(); }
SampleProfileFormat getFormat() const { return Format; }
bool profileIsProbeBased() const { return ProfileIsProbeBased; }
bool profileIsCS() const { return ProfileIsCS; }
bool profileIsPreInlined() const { return ProfileIsPreInlined; }
virtual std::unique_ptr<ProfileSymbolList> getProfileSymbolList() {
return nullptr;
};
virtual std::vector<StringRef> *getNameTable() { return nullptr; }
virtual bool dumpSectionInfo(raw_ostream &OS = dbgs()) { return false; };
virtual bool useMD5() { return false; }
virtual void setSkipFlatProf(bool Skip) {}
virtual bool hasUniqSuffix() { return false; }
SampleProfileReaderItaniumRemapper *getRemapper() { return Remapper.get(); }
void setModule(const Module *Mod) { M = Mod; }
protected:
SampleProfileMap Profiles;
LLVMContext &Ctx;
std::unique_ptr<MemoryBuffer> Buffer;
std::unordered_set<std::string> MD5NameBuffer;
std::unique_ptr<ProfileSummary> Summary;
static std::unique_ptr<ProfileSummary>
takeSummary(SampleProfileReader &Reader) {
return std::move(Reader.Summary);
}
void computeSummary();
std::unique_ptr<SampleProfileReaderItaniumRemapper> Remapper;
bool ProfileIsProbeBased = false;
bool ProfileIsCS = false;
bool ProfileIsPreInlined = false;
uint32_t CSProfileCount = 0;
bool ProfileIsFS = false;
SampleProfileFormat Format = SPF_None;
const Module *M = nullptr;
uint32_t MaskedBitFrom = 31;
};
class SampleProfileReaderText : public SampleProfileReader {
public:
SampleProfileReaderText(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
: SampleProfileReader(std::move(B), C, SPF_Text) {}
std::error_code readHeader() override { return sampleprof_error::success; }
std::error_code readImpl() override;
static bool hasFormat(const MemoryBuffer &Buffer);
private:
std::list<SampleContextFrameVector> CSNameTable;
};
class SampleProfileReaderBinary : public SampleProfileReader {
public:
SampleProfileReaderBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
SampleProfileFormat Format = SPF_None)
: SampleProfileReader(std::move(B), C, Format) {}
std::error_code readHeader() override;
std::error_code readImpl() override;
std::vector<StringRef> *getNameTable() override { return &NameTable; }
protected:
template <typename T> ErrorOr<T> readNumber();
template <typename T> ErrorOr<T> readUnencodedNumber();
ErrorOr<StringRef> readString();
template <typename T> inline ErrorOr<uint32_t> readStringIndex(T &Table);
bool at_eof() const { return Data >= End; }
std::error_code readFuncProfile(const uint8_t *Start);
std::error_code readProfile(FunctionSamples &FProfile);
std::error_code readMagicIdent();
std::error_code readSummary();
virtual std::error_code readNameTable();
const uint8_t *Data = nullptr;
const uint8_t *End = nullptr;
std::vector<StringRef> NameTable;
virtual ErrorOr<StringRef> readStringFromTable();
virtual ErrorOr<SampleContext> readSampleContextFromTable();
private:
std::error_code readSummaryEntry(std::vector<ProfileSummaryEntry> &Entries);
virtual std::error_code verifySPMagic(uint64_t Magic) = 0;
};
class SampleProfileReaderRawBinary : public SampleProfileReaderBinary {
private:
std::error_code verifySPMagic(uint64_t Magic) override;
public:
SampleProfileReaderRawBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
SampleProfileFormat Format = SPF_Binary)
: SampleProfileReaderBinary(std::move(B), C, Format) {}
static bool hasFormat(const MemoryBuffer &Buffer);
};
class SampleProfileReaderExtBinaryBase : public SampleProfileReaderBinary {
private:
std::error_code decompressSection(const uint8_t *SecStart,
const uint64_t SecSize,
const uint8_t *&DecompressBuf,
uint64_t &DecompressBufSize);
BumpPtrAllocator Allocator;
protected:
std::vector<SecHdrTableEntry> SecHdrTable;
std::error_code readSecHdrTableEntry(uint32_t Idx);
std::error_code readSecHdrTable();
std::error_code readFuncMetadata(bool ProfileHasAttribute);
std::error_code readFuncMetadata(bool ProfileHasAttribute,
FunctionSamples *FProfile);
std::error_code readFuncOffsetTable();
std::error_code readFuncProfiles();
std::error_code readMD5NameTable();
std::error_code readNameTableSec(bool IsMD5);
std::error_code readCSNameTableSec();
std::error_code readProfileSymbolList();
std::error_code readHeader() override;
std::error_code verifySPMagic(uint64_t Magic) override = 0;
virtual std::error_code readOneSection(const uint8_t *Start, uint64_t Size,
const SecHdrTableEntry &Entry);
virtual std::error_code readCustomSection(const SecHdrTableEntry &Entry) = 0;
ErrorOr<StringRef> readStringFromTable() override;
ErrorOr<SampleContext> readSampleContextFromTable() override;
ErrorOr<SampleContextFrames> readContextFromTable();
std::unique_ptr<ProfileSymbolList> ProfSymList;
DenseMap<SampleContext, uint64_t> FuncOffsetTable;
std::unique_ptr<std::vector<std::pair<SampleContext, uint64_t>>>
OrderedFuncOffsets;
DenseSet<StringRef> FuncsToUse;
bool FixedLengthMD5 = false;
const uint8_t *MD5NameMemStart = nullptr;
std::unique_ptr<std::vector<std::string>> MD5StringBuf;
std::unique_ptr<const std::vector<SampleContextFrameVector>> CSNameTable;
bool SkipFlatProf = false;
bool FuncOffsetsOrdered = false;
public:
SampleProfileReaderExtBinaryBase(std::unique_ptr<MemoryBuffer> B,
LLVMContext &C, SampleProfileFormat Format)
: SampleProfileReaderBinary(std::move(B), C, Format) {}
std::error_code readImpl() override;
uint64_t getSectionSize(SecType Type);
uint64_t getFileSize();
bool dumpSectionInfo(raw_ostream &OS = dbgs()) override;
bool collectFuncsFromModule() override;
bool useMD5() override { return MD5StringBuf.get(); }
std::unique_ptr<ProfileSymbolList> getProfileSymbolList() override {
return std::move(ProfSymList);
};
void setSkipFlatProf(bool Skip) override { SkipFlatProf = Skip; }
};
class SampleProfileReaderExtBinary : public SampleProfileReaderExtBinaryBase {
private:
std::error_code verifySPMagic(uint64_t Magic) override;
std::error_code readCustomSection(const SecHdrTableEntry &Entry) override {
Data = End;
return sampleprof_error::success;
};
public:
SampleProfileReaderExtBinary(std::unique_ptr<MemoryBuffer> B, LLVMContext &C,
SampleProfileFormat Format = SPF_Ext_Binary)
: SampleProfileReaderExtBinaryBase(std::move(B), C, Format) {}
static bool hasFormat(const MemoryBuffer &Buffer);
};
class SampleProfileReaderCompactBinary : public SampleProfileReaderBinary {
private:
std::vector<std::string> NameTable;
DenseMap<StringRef, uint64_t> FuncOffsetTable;
DenseSet<StringRef> FuncsToUse;
std::error_code verifySPMagic(uint64_t Magic) override;
std::error_code readNameTable() override;
ErrorOr<StringRef> readStringFromTable() override;
std::error_code readHeader() override;
std::error_code readFuncOffsetTable();
public:
SampleProfileReaderCompactBinary(std::unique_ptr<MemoryBuffer> B,
LLVMContext &C)
: SampleProfileReaderBinary(std::move(B), C, SPF_Compact_Binary) {}
static bool hasFormat(const MemoryBuffer &Buffer);
std::error_code readImpl() override;
bool collectFuncsFromModule() override;
bool useMD5() override { return true; }
};
using InlineCallStack = SmallVector<FunctionSamples *, 10>;
enum HistType {
HIST_TYPE_INTERVAL,
HIST_TYPE_POW2,
HIST_TYPE_SINGLE_VALUE,
HIST_TYPE_CONST_DELTA,
HIST_TYPE_INDIR_CALL,
HIST_TYPE_AVERAGE,
HIST_TYPE_IOR,
HIST_TYPE_INDIR_CALL_TOPN
};
class SampleProfileReaderGCC : public SampleProfileReader {
public:
SampleProfileReaderGCC(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
: SampleProfileReader(std::move(B), C, SPF_GCC),
GcovBuffer(Buffer.get()) {}
std::error_code readHeader() override;
std::error_code readImpl() override;
static bool hasFormat(const MemoryBuffer &Buffer);
protected:
std::error_code readNameTable();
std::error_code readOneFunctionProfile(const InlineCallStack &InlineStack,
bool Update, uint32_t Offset);
std::error_code readFunctionProfiles();
std::error_code skipNextWord();
template <typename T> ErrorOr<T> readNumber();
ErrorOr<StringRef> readString();
std::error_code readSectionTag(uint32_t Expected);
GCOVBuffer GcovBuffer;
std::vector<std::string> Names;
static const uint32_t GCOVTagAFDOFileNames = 0xaa000000;
static const uint32_t GCOVTagAFDOFunction = 0xac000000;
};
}
}
#endif