#include "llvm/ProfileData/SampleProfReader.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ProfileSummary.h"
#include "llvm/ProfileData/ProfileCommon.h"
#include "llvm/ProfileData/SampleProf.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/LineIterator.h"
#include "llvm/Support/MD5.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <memory>
#include <system_error>
#include <vector>
using namespace llvm;
using namespace sampleprof;
#define DEBUG_TYPE "samplepgo-reader"
static cl::opt<bool> ProfileIsFSDisciminator(
"profile-isfs", cl::Hidden, cl::init(false),
cl::desc("Profile uses flow sensitive discriminators"));
void SampleProfileReader::dumpFunctionProfile(SampleContext FContext,
raw_ostream &OS) {
OS << "Function: " << FContext.toString() << ": " << Profiles[FContext];
}
void SampleProfileReader::dump(raw_ostream &OS) {
std::vector<NameFunctionSamples> V;
sortFuncProfiles(Profiles, V);
for (const auto &I : V)
dumpFunctionProfile(I.first, OS);
}
static bool ParseHead(const StringRef &Input, StringRef &FName,
uint64_t &NumSamples, uint64_t &NumHeadSamples) {
if (Input[0] == ' ')
return false;
size_t n2 = Input.rfind(':');
size_t n1 = Input.rfind(':', n2 - 1);
FName = Input.substr(0, n1);
if (Input.substr(n1 + 1, n2 - n1 - 1).getAsInteger(10, NumSamples))
return false;
if (Input.substr(n2 + 1).getAsInteger(10, NumHeadSamples))
return false;
return true;
}
static bool isOffsetLegal(unsigned L) { return (L & 0xffff) == L; }
static bool parseMetadata(const StringRef &Input, uint64_t &FunctionHash,
uint32_t &Attributes) {
if (Input.startswith("!CFGChecksum:")) {
StringRef CFGInfo = Input.substr(strlen("!CFGChecksum:")).trim();
return !CFGInfo.getAsInteger(10, FunctionHash);
}
if (Input.startswith("!Attributes:")) {
StringRef Attrib = Input.substr(strlen("!Attributes:")).trim();
return !Attrib.getAsInteger(10, Attributes);
}
return false;
}
enum class LineType {
CallSiteProfile,
BodyProfile,
Metadata,
};
static bool ParseLine(const StringRef &Input, LineType &LineTy, uint32_t &Depth,
uint64_t &NumSamples, uint32_t &LineOffset,
uint32_t &Discriminator, StringRef &CalleeName,
DenseMap<StringRef, uint64_t> &TargetCountMap,
uint64_t &FunctionHash, uint32_t &Attributes) {
for (Depth = 0; Input[Depth] == ' '; Depth++)
;
if (Depth == 0)
return false;
if (Input[Depth] == '!') {
LineTy = LineType::Metadata;
return parseMetadata(Input.substr(Depth), FunctionHash, Attributes);
}
size_t n1 = Input.find(':');
StringRef Loc = Input.substr(Depth, n1 - Depth);
size_t n2 = Loc.find('.');
if (n2 == StringRef::npos) {
if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset))
return false;
Discriminator = 0;
} else {
if (Loc.substr(0, n2).getAsInteger(10, LineOffset))
return false;
if (Loc.substr(n2 + 1).getAsInteger(10, Discriminator))
return false;
}
StringRef Rest = Input.substr(n1 + 2);
if (isDigit(Rest[0])) {
LineTy = LineType::BodyProfile;
size_t n3 = Rest.find(' ');
if (n3 == StringRef::npos) {
if (Rest.getAsInteger(10, NumSamples))
return false;
} else {
if (Rest.substr(0, n3).getAsInteger(10, NumSamples))
return false;
}
while (n3 != StringRef::npos) {
n3 += Rest.substr(n3).find_first_not_of(' ');
Rest = Rest.substr(n3);
n3 = Rest.find_first_of(':');
if (n3 == StringRef::npos || n3 == 0)
return false;
StringRef Target;
uint64_t count, n4;
while (true) {
StringRef AfterColon = Rest.substr(n3 + 1);
Target = Rest.substr(0, n3);
n4 = AfterColon.find_first_of(' ');
n4 = (n4 != StringRef::npos) ? n3 + n4 + 1 : Rest.size();
StringRef WordAfterColon = Rest.substr(n3 + 1, n4 - n3 - 1);
if (!WordAfterColon.getAsInteger(10, count))
break;
uint64_t n5 = AfterColon.find_first_of(':');
if (n5 == StringRef::npos)
return false;
n3 += n5 + 1;
}
TargetCountMap[Target] = count;
if (n4 == Rest.size())
break;
n3 = n4;
}
} else {
LineTy = LineType::CallSiteProfile;
size_t n3 = Rest.find_last_of(':');
CalleeName = Rest.substr(0, n3);
if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples))
return false;
}
return true;
}
std::error_code SampleProfileReaderText::readImpl() {
line_iterator LineIt(*Buffer, true, '#');
sampleprof_error Result = sampleprof_error::success;
InlineCallStack InlineStack;
uint32_t TopLevelProbeProfileCount = 0;
uint32_t DepthMetadata = 0;
ProfileIsFS = ProfileIsFSDisciminator;
FunctionSamples::ProfileIsFS = ProfileIsFS;
for (; !LineIt.is_at_eof(); ++LineIt) {
if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#')
continue;
if ((*LineIt)[0] != ' ') {
uint64_t NumSamples, NumHeadSamples;
StringRef FName;
if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)) {
reportError(LineIt.line_number(),
"Expected 'mangled_name:NUM:NUM', found " + *LineIt);
return sampleprof_error::malformed;
}
DepthMetadata = 0;
SampleContext FContext(FName, CSNameTable);
if (FContext.hasContext())
++CSProfileCount;
Profiles[FContext] = FunctionSamples();
FunctionSamples &FProfile = Profiles[FContext];
FProfile.setContext(FContext);
MergeResult(Result, FProfile.addTotalSamples(NumSamples));
MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
InlineStack.clear();
InlineStack.push_back(&FProfile);
} else {
uint64_t NumSamples;
StringRef FName;
DenseMap<StringRef, uint64_t> TargetCountMap;
uint32_t Depth, LineOffset, Discriminator;
LineType LineTy;
uint64_t FunctionHash = 0;
uint32_t Attributes = 0;
if (!ParseLine(*LineIt, LineTy, Depth, NumSamples, LineOffset,
Discriminator, FName, TargetCountMap, FunctionHash,
Attributes)) {
reportError(LineIt.line_number(),
"Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
*LineIt);
return sampleprof_error::malformed;
}
if (LineTy != LineType::Metadata && Depth == DepthMetadata) {
reportError(LineIt.line_number(),
"Found non-metadata after metadata: " + *LineIt);
return sampleprof_error::malformed;
}
Discriminator &= getDiscriminatorMask();
while (InlineStack.size() > Depth) {
InlineStack.pop_back();
}
switch (LineTy) {
case LineType::CallSiteProfile: {
FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
LineLocation(LineOffset, Discriminator))[std::string(FName)];
FSamples.setName(FName);
MergeResult(Result, FSamples.addTotalSamples(NumSamples));
InlineStack.push_back(&FSamples);
DepthMetadata = 0;
break;
}
case LineType::BodyProfile: {
while (InlineStack.size() > Depth) {
InlineStack.pop_back();
}
FunctionSamples &FProfile = *InlineStack.back();
for (const auto &name_count : TargetCountMap) {
MergeResult(Result, FProfile.addCalledTargetSamples(
LineOffset, Discriminator, name_count.first,
name_count.second));
}
MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator,
NumSamples));
break;
}
case LineType::Metadata: {
FunctionSamples &FProfile = *InlineStack.back();
if (FunctionHash) {
FProfile.setFunctionHash(FunctionHash);
if (Depth == 1)
++TopLevelProbeProfileCount;
}
FProfile.getContext().setAllAttributes(Attributes);
if (Attributes & (uint32_t)ContextShouldBeInlined)
ProfileIsPreInlined = true;
DepthMetadata = Depth;
break;
}
}
}
}
assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
"Cannot have both context-sensitive and regular profile");
ProfileIsCS = (CSProfileCount > 0);
assert((TopLevelProbeProfileCount == 0 ||
TopLevelProbeProfileCount == Profiles.size()) &&
"Cannot have both probe-based profiles and regular profiles");
ProfileIsProbeBased = (TopLevelProbeProfileCount > 0);
FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased;
FunctionSamples::ProfileIsCS = ProfileIsCS;
FunctionSamples::ProfileIsPreInlined = ProfileIsPreInlined;
if (Result == sampleprof_error::success)
computeSummary();
return Result;
}
bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) {
bool result = false;
line_iterator LineIt(Buffer, true, '#');
if (!LineIt.is_at_eof()) {
if ((*LineIt)[0] != ' ') {
uint64_t NumSamples, NumHeadSamples;
StringRef FName;
result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
}
}
return result;
}
template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
unsigned NumBytesRead = 0;
std::error_code EC;
uint64_t Val = decodeULEB128(Data, &NumBytesRead);
if (Val > std::numeric_limits<T>::max())
EC = sampleprof_error::malformed;
else if (Data + NumBytesRead > End)
EC = sampleprof_error::truncated;
else
EC = sampleprof_error::success;
if (EC) {
reportError(0, EC.message());
return EC;
}
Data += NumBytesRead;
return static_cast<T>(Val);
}
ErrorOr<StringRef> SampleProfileReaderBinary::readString() {
std::error_code EC;
StringRef Str(reinterpret_cast<const char *>(Data));
if (Data + Str.size() + 1 > End) {
EC = sampleprof_error::truncated;
reportError(0, EC.message());
return EC;
}
Data += Str.size() + 1;
return Str;
}
template <typename T>
ErrorOr<T> SampleProfileReaderBinary::readUnencodedNumber() {
std::error_code EC;
if (Data + sizeof(T) > End) {
EC = sampleprof_error::truncated;
reportError(0, EC.message());
return EC;
}
using namespace support;
T Val = endian::readNext<T, little, unaligned>(Data);
return Val;
}
template <typename T>
inline ErrorOr<uint32_t> SampleProfileReaderBinary::readStringIndex(T &Table) {
std::error_code EC;
auto Idx = readNumber<uint32_t>();
if (std::error_code EC = Idx.getError())
return EC;
if (*Idx >= Table.size())
return sampleprof_error::truncated_name_table;
return *Idx;
}
ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
auto Idx = readStringIndex(NameTable);
if (std::error_code EC = Idx.getError())
return EC;
return NameTable[*Idx];
}
ErrorOr<SampleContext> SampleProfileReaderBinary::readSampleContextFromTable() {
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;
return SampleContext(*FName);
}
ErrorOr<StringRef> SampleProfileReaderExtBinaryBase::readStringFromTable() {
if (!FixedLengthMD5)
return SampleProfileReaderBinary::readStringFromTable();
auto Idx = readStringIndex(NameTable);
if (std::error_code EC = Idx.getError())
return EC;
StringRef &SR = NameTable[*Idx];
if (SR.empty()) {
const uint8_t *SavedData = Data;
Data = MD5NameMemStart + ((*Idx) * sizeof(uint64_t));
auto FID = readUnencodedNumber<uint64_t>();
if (std::error_code EC = FID.getError())
return EC;
MD5StringBuf->push_back(std::to_string(*FID));
SR = MD5StringBuf->back();
Data = SavedData;
}
return SR;
}
ErrorOr<StringRef> SampleProfileReaderCompactBinary::readStringFromTable() {
auto Idx = readStringIndex(NameTable);
if (std::error_code EC = Idx.getError())
return EC;
return StringRef(NameTable[*Idx]);
}
std::error_code
SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
auto NumSamples = readNumber<uint64_t>();
if (std::error_code EC = NumSamples.getError())
return EC;
FProfile.addTotalSamples(*NumSamples);
auto NumRecords = readNumber<uint32_t>();
if (std::error_code EC = NumRecords.getError())
return EC;
for (uint32_t I = 0; I < *NumRecords; ++I) {
auto LineOffset = readNumber<uint64_t>();
if (std::error_code EC = LineOffset.getError())
return EC;
if (!isOffsetLegal(*LineOffset)) {
return std::error_code();
}
auto Discriminator = readNumber<uint64_t>();
if (std::error_code EC = Discriminator.getError())
return EC;
auto NumSamples = readNumber<uint64_t>();
if (std::error_code EC = NumSamples.getError())
return EC;
auto NumCalls = readNumber<uint32_t>();
if (std::error_code EC = NumCalls.getError())
return EC;
uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
for (uint32_t J = 0; J < *NumCalls; ++J) {
auto CalledFunction(readStringFromTable());
if (std::error_code EC = CalledFunction.getError())
return EC;
auto CalledFunctionSamples = readNumber<uint64_t>();
if (std::error_code EC = CalledFunctionSamples.getError())
return EC;
FProfile.addCalledTargetSamples(*LineOffset, DiscriminatorVal,
*CalledFunction, *CalledFunctionSamples);
}
FProfile.addBodySamples(*LineOffset, DiscriminatorVal, *NumSamples);
}
auto NumCallsites = readNumber<uint32_t>();
if (std::error_code EC = NumCallsites.getError())
return EC;
for (uint32_t J = 0; J < *NumCallsites; ++J) {
auto LineOffset = readNumber<uint64_t>();
if (std::error_code EC = LineOffset.getError())
return EC;
auto Discriminator = readNumber<uint64_t>();
if (std::error_code EC = Discriminator.getError())
return EC;
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;
uint32_t DiscriminatorVal = (*Discriminator) & getDiscriminatorMask();
FunctionSamples &CalleeProfile = FProfile.functionSamplesAt(
LineLocation(*LineOffset, DiscriminatorVal))[std::string(*FName)];
CalleeProfile.setName(*FName);
if (std::error_code EC = readProfile(CalleeProfile))
return EC;
}
return sampleprof_error::success;
}
std::error_code
SampleProfileReaderBinary::readFuncProfile(const uint8_t *Start) {
Data = Start;
auto NumHeadSamples = readNumber<uint64_t>();
if (std::error_code EC = NumHeadSamples.getError())
return EC;
ErrorOr<SampleContext> FContext(readSampleContextFromTable());
if (std::error_code EC = FContext.getError())
return EC;
Profiles[*FContext] = FunctionSamples();
FunctionSamples &FProfile = Profiles[*FContext];
FProfile.setContext(*FContext);
FProfile.addHeadSamples(*NumHeadSamples);
if (FContext->hasContext())
CSProfileCount++;
if (std::error_code EC = readProfile(FProfile))
return EC;
return sampleprof_error::success;
}
std::error_code SampleProfileReaderBinary::readImpl() {
ProfileIsFS = ProfileIsFSDisciminator;
FunctionSamples::ProfileIsFS = ProfileIsFS;
while (!at_eof()) {
if (std::error_code EC = readFuncProfile(Data))
return EC;
}
return sampleprof_error::success;
}
ErrorOr<SampleContextFrames>
SampleProfileReaderExtBinaryBase::readContextFromTable() {
auto ContextIdx = readNumber<uint32_t>();
if (std::error_code EC = ContextIdx.getError())
return EC;
if (*ContextIdx >= CSNameTable->size())
return sampleprof_error::truncated_name_table;
return (*CSNameTable)[*ContextIdx];
}
ErrorOr<SampleContext>
SampleProfileReaderExtBinaryBase::readSampleContextFromTable() {
if (ProfileIsCS) {
auto FContext(readContextFromTable());
if (std::error_code EC = FContext.getError())
return EC;
return SampleContext(*FContext);
} else {
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;
return SampleContext(*FName);
}
}
std::error_code SampleProfileReaderExtBinaryBase::readOneSection(
const uint8_t *Start, uint64_t Size, const SecHdrTableEntry &Entry) {
Data = Start;
End = Start + Size;
switch (Entry.Type) {
case SecProfSummary:
if (std::error_code EC = readSummary())
return EC;
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial))
Summary->setPartialProfile(true);
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext))
FunctionSamples::ProfileIsCS = ProfileIsCS = true;
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagIsPreInlined))
FunctionSamples::ProfileIsPreInlined = ProfileIsPreInlined = true;
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator))
FunctionSamples::ProfileIsFS = ProfileIsFS = true;
break;
case SecNameTable: {
FixedLengthMD5 =
hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5);
bool UseMD5 = hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name);
assert((!FixedLengthMD5 || UseMD5) &&
"If FixedLengthMD5 is true, UseMD5 has to be true");
FunctionSamples::HasUniqSuffix =
hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix);
if (std::error_code EC = readNameTableSec(UseMD5))
return EC;
break;
}
case SecCSNameTable: {
if (std::error_code EC = readCSNameTableSec())
return EC;
break;
}
case SecLBRProfile:
if (std::error_code EC = readFuncProfiles())
return EC;
break;
case SecFuncOffsetTable:
FuncOffsetsOrdered = hasSecFlag(Entry, SecFuncOffsetFlags::SecFlagOrdered);
if (std::error_code EC = readFuncOffsetTable())
return EC;
break;
case SecFuncMetadata: {
ProfileIsProbeBased =
hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased);
FunctionSamples::ProfileIsProbeBased = ProfileIsProbeBased;
bool HasAttribute =
hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute);
if (std::error_code EC = readFuncMetadata(HasAttribute))
return EC;
break;
}
case SecProfileSymbolList:
if (std::error_code EC = readProfileSymbolList())
return EC;
break;
default:
if (std::error_code EC = readCustomSection(Entry))
return EC;
break;
}
return sampleprof_error::success;
}
bool SampleProfileReaderExtBinaryBase::collectFuncsFromModule() {
if (!M)
return false;
FuncsToUse.clear();
for (auto &F : *M)
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
return true;
}
std::error_code SampleProfileReaderExtBinaryBase::readFuncOffsetTable() {
FuncOffsetTable.clear();
auto Size = readNumber<uint64_t>();
if (std::error_code EC = Size.getError())
return EC;
FuncOffsetTable.reserve(*Size);
if (FuncOffsetsOrdered) {
OrderedFuncOffsets =
std::make_unique<std::vector<std::pair<SampleContext, uint64_t>>>();
OrderedFuncOffsets->reserve(*Size);
}
for (uint32_t I = 0; I < *Size; ++I) {
auto FContext(readSampleContextFromTable());
if (std::error_code EC = FContext.getError())
return EC;
auto Offset = readNumber<uint64_t>();
if (std::error_code EC = Offset.getError())
return EC;
FuncOffsetTable[*FContext] = *Offset;
if (FuncOffsetsOrdered)
OrderedFuncOffsets->emplace_back(*FContext, *Offset);
}
return sampleprof_error::success;
}
std::error_code SampleProfileReaderExtBinaryBase::readFuncProfiles() {
bool LoadFuncsToBeUsed = collectFuncsFromModule();
const uint8_t *Start = Data;
if (!LoadFuncsToBeUsed) {
while (Data < End) {
if (std::error_code EC = readFuncProfile(Data))
return EC;
}
assert(Data == End && "More data is read than expected");
} else {
if (Remapper) {
for (auto Name : FuncsToUse) {
Remapper->insert(Name);
}
}
if (ProfileIsCS) {
DenseSet<uint64_t> FuncGuidsToUse;
if (useMD5()) {
for (auto Name : FuncsToUse)
FuncGuidsToUse.insert(Function::getGUID(Name));
}
assert(OrderedFuncOffsets.get() &&
"func offset table should always be sorted in CS profile");
const SampleContext *CommonContext = nullptr;
for (const auto &NameOffset : *OrderedFuncOffsets) {
const auto &FContext = NameOffset.first;
auto FName = FContext.getName();
if ((useMD5() && FuncGuidsToUse.count(std::stoull(FName.data()))) ||
(!useMD5() && (FuncsToUse.count(FName) ||
(Remapper && Remapper->exist(FName))))) {
if (!CommonContext || !CommonContext->IsPrefixOf(FContext))
CommonContext = &FContext;
}
if (CommonContext == &FContext ||
(CommonContext && CommonContext->IsPrefixOf(FContext))) {
const uint8_t *FuncProfileAddr = Start + NameOffset.second;
assert(FuncProfileAddr < End && "out of LBRProfile section");
if (std::error_code EC = readFuncProfile(FuncProfileAddr))
return EC;
}
}
} else {
if (useMD5()) {
for (auto Name : FuncsToUse) {
auto GUID = std::to_string(MD5Hash(Name));
auto iter = FuncOffsetTable.find(StringRef(GUID));
if (iter == FuncOffsetTable.end())
continue;
const uint8_t *FuncProfileAddr = Start + iter->second;
assert(FuncProfileAddr < End && "out of LBRProfile section");
if (std::error_code EC = readFuncProfile(FuncProfileAddr))
return EC;
}
} else {
for (auto NameOffset : FuncOffsetTable) {
SampleContext FContext(NameOffset.first);
auto FuncName = FContext.getName();
if (!FuncsToUse.count(FuncName) &&
(!Remapper || !Remapper->exist(FuncName)))
continue;
const uint8_t *FuncProfileAddr = Start + NameOffset.second;
assert(FuncProfileAddr < End && "out of LBRProfile section");
if (std::error_code EC = readFuncProfile(FuncProfileAddr))
return EC;
}
}
}
Data = End;
}
assert((CSProfileCount == 0 || CSProfileCount == Profiles.size()) &&
"Cannot have both context-sensitive and regular profile");
assert((!CSProfileCount || ProfileIsCS) &&
"Section flag should be consistent with actual profile");
return sampleprof_error::success;
}
std::error_code SampleProfileReaderExtBinaryBase::readProfileSymbolList() {
if (!ProfSymList)
ProfSymList = std::make_unique<ProfileSymbolList>();
if (std::error_code EC = ProfSymList->read(Data, End - Data))
return EC;
Data = End;
return sampleprof_error::success;
}
std::error_code SampleProfileReaderExtBinaryBase::decompressSection(
const uint8_t *SecStart, const uint64_t SecSize,
const uint8_t *&DecompressBuf, uint64_t &DecompressBufSize) {
Data = SecStart;
End = SecStart + SecSize;
auto DecompressSize = readNumber<uint64_t>();
if (std::error_code EC = DecompressSize.getError())
return EC;
DecompressBufSize = *DecompressSize;
auto CompressSize = readNumber<uint64_t>();
if (std::error_code EC = CompressSize.getError())
return EC;
if (!llvm::compression::zlib::isAvailable())
return sampleprof_error::zlib_unavailable;
uint8_t *Buffer = Allocator.Allocate<uint8_t>(DecompressBufSize);
size_t UCSize = DecompressBufSize;
llvm::Error E = compression::zlib::uncompress(
makeArrayRef(Data, *CompressSize), Buffer, UCSize);
if (E)
return sampleprof_error::uncompress_failed;
DecompressBuf = reinterpret_cast<const uint8_t *>(Buffer);
return sampleprof_error::success;
}
std::error_code SampleProfileReaderExtBinaryBase::readImpl() {
const uint8_t *BufStart =
reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
for (auto &Entry : SecHdrTable) {
if (!Entry.Size)
continue;
if (SkipFlatProf && hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
continue;
const uint8_t *SecStart = BufStart + Entry.Offset;
uint64_t SecSize = Entry.Size;
bool isCompressed = hasSecFlag(Entry, SecCommonFlags::SecFlagCompress);
if (isCompressed) {
const uint8_t *DecompressBuf;
uint64_t DecompressBufSize;
if (std::error_code EC = decompressSection(
SecStart, SecSize, DecompressBuf, DecompressBufSize))
return EC;
SecStart = DecompressBuf;
SecSize = DecompressBufSize;
}
if (std::error_code EC = readOneSection(SecStart, SecSize, Entry))
return EC;
if (Data != SecStart + SecSize)
return sampleprof_error::malformed;
if (isCompressed) {
Data = BufStart + Entry.Offset;
End = BufStart + Buffer->getBufferSize();
}
}
return sampleprof_error::success;
}
std::error_code SampleProfileReaderCompactBinary::readImpl() {
bool LoadFuncsToBeUsed = collectFuncsFromModule();
ProfileIsFS = ProfileIsFSDisciminator;
FunctionSamples::ProfileIsFS = ProfileIsFS;
std::vector<uint64_t> OffsetsToUse;
if (!LoadFuncsToBeUsed) {
for (auto FuncEntry : FuncOffsetTable) {
OffsetsToUse.push_back(FuncEntry.second);
}
} else {
for (auto Name : FuncsToUse) {
auto GUID = std::to_string(MD5Hash(Name));
auto iter = FuncOffsetTable.find(StringRef(GUID));
if (iter == FuncOffsetTable.end())
continue;
OffsetsToUse.push_back(iter->second);
}
}
for (auto Offset : OffsetsToUse) {
const uint8_t *SavedData = Data;
if (std::error_code EC = readFuncProfile(
reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
Offset))
return EC;
Data = SavedData;
}
return sampleprof_error::success;
}
std::error_code SampleProfileReaderRawBinary::verifySPMagic(uint64_t Magic) {
if (Magic == SPMagic())
return sampleprof_error::success;
return sampleprof_error::bad_magic;
}
std::error_code SampleProfileReaderExtBinary::verifySPMagic(uint64_t Magic) {
if (Magic == SPMagic(SPF_Ext_Binary))
return sampleprof_error::success;
return sampleprof_error::bad_magic;
}
std::error_code
SampleProfileReaderCompactBinary::verifySPMagic(uint64_t Magic) {
if (Magic == SPMagic(SPF_Compact_Binary))
return sampleprof_error::success;
return sampleprof_error::bad_magic;
}
std::error_code SampleProfileReaderBinary::readNameTable() {
auto Size = readNumber<uint32_t>();
if (std::error_code EC = Size.getError())
return EC;
NameTable.reserve(*Size + NameTable.size());
for (uint32_t I = 0; I < *Size; ++I) {
auto Name(readString());
if (std::error_code EC = Name.getError())
return EC;
NameTable.push_back(*Name);
}
return sampleprof_error::success;
}
std::error_code SampleProfileReaderExtBinaryBase::readMD5NameTable() {
auto Size = readNumber<uint64_t>();
if (std::error_code EC = Size.getError())
return EC;
MD5StringBuf = std::make_unique<std::vector<std::string>>();
MD5StringBuf->reserve(*Size);
if (FixedLengthMD5) {
NameTable.resize(*Size + NameTable.size());
MD5NameMemStart = Data;
Data = Data + (*Size) * sizeof(uint64_t);
return sampleprof_error::success;
}
NameTable.reserve(*Size);
for (uint32_t I = 0; I < *Size; ++I) {
auto FID = readNumber<uint64_t>();
if (std::error_code EC = FID.getError())
return EC;
MD5StringBuf->push_back(std::to_string(*FID));
NameTable.push_back(MD5StringBuf->back());
}
return sampleprof_error::success;
}
std::error_code SampleProfileReaderExtBinaryBase::readNameTableSec(bool IsMD5) {
if (IsMD5)
return readMD5NameTable();
return SampleProfileReaderBinary::readNameTable();
}
std::error_code SampleProfileReaderExtBinaryBase::readCSNameTableSec() {
auto Size = readNumber<uint32_t>();
if (std::error_code EC = Size.getError())
return EC;
std::vector<SampleContextFrameVector> *PNameVec =
new std::vector<SampleContextFrameVector>();
PNameVec->reserve(*Size);
for (uint32_t I = 0; I < *Size; ++I) {
PNameVec->emplace_back(SampleContextFrameVector());
auto ContextSize = readNumber<uint32_t>();
if (std::error_code EC = ContextSize.getError())
return EC;
for (uint32_t J = 0; J < *ContextSize; ++J) {
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;
auto LineOffset = readNumber<uint64_t>();
if (std::error_code EC = LineOffset.getError())
return EC;
if (!isOffsetLegal(*LineOffset))
return std::error_code();
auto Discriminator = readNumber<uint64_t>();
if (std::error_code EC = Discriminator.getError())
return EC;
PNameVec->back().emplace_back(
FName.get(), LineLocation(LineOffset.get(), Discriminator.get()));
}
}
CSNameTable.reset(PNameVec);
return sampleprof_error::success;
}
std::error_code
SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute,
FunctionSamples *FProfile) {
if (Data < End) {
if (ProfileIsProbeBased) {
auto Checksum = readNumber<uint64_t>();
if (std::error_code EC = Checksum.getError())
return EC;
if (FProfile)
FProfile->setFunctionHash(*Checksum);
}
if (ProfileHasAttribute) {
auto Attributes = readNumber<uint32_t>();
if (std::error_code EC = Attributes.getError())
return EC;
if (FProfile)
FProfile->getContext().setAllAttributes(*Attributes);
}
if (!ProfileIsCS) {
auto NumCallsites = readNumber<uint32_t>();
if (std::error_code EC = NumCallsites.getError())
return EC;
for (uint32_t J = 0; J < *NumCallsites; ++J) {
auto LineOffset = readNumber<uint64_t>();
if (std::error_code EC = LineOffset.getError())
return EC;
auto Discriminator = readNumber<uint64_t>();
if (std::error_code EC = Discriminator.getError())
return EC;
auto FContext(readSampleContextFromTable());
if (std::error_code EC = FContext.getError())
return EC;
FunctionSamples *CalleeProfile = nullptr;
if (FProfile) {
CalleeProfile = const_cast<FunctionSamples *>(
&FProfile->functionSamplesAt(LineLocation(
*LineOffset,
*Discriminator))[std::string(FContext.get().getName())]);
}
if (std::error_code EC =
readFuncMetadata(ProfileHasAttribute, CalleeProfile))
return EC;
}
}
}
return sampleprof_error::success;
}
std::error_code
SampleProfileReaderExtBinaryBase::readFuncMetadata(bool ProfileHasAttribute) {
while (Data < End) {
auto FContext(readSampleContextFromTable());
if (std::error_code EC = FContext.getError())
return EC;
FunctionSamples *FProfile = nullptr;
auto It = Profiles.find(*FContext);
if (It != Profiles.end())
FProfile = &It->second;
if (std::error_code EC = readFuncMetadata(ProfileHasAttribute, FProfile))
return EC;
}
assert(Data == End && "More data is read than expected");
return sampleprof_error::success;
}
std::error_code SampleProfileReaderCompactBinary::readNameTable() {
auto Size = readNumber<uint64_t>();
if (std::error_code EC = Size.getError())
return EC;
NameTable.reserve(*Size);
for (uint32_t I = 0; I < *Size; ++I) {
auto FID = readNumber<uint64_t>();
if (std::error_code EC = FID.getError())
return EC;
NameTable.push_back(std::to_string(*FID));
}
return sampleprof_error::success;
}
std::error_code
SampleProfileReaderExtBinaryBase::readSecHdrTableEntry(uint32_t Idx) {
SecHdrTableEntry Entry;
auto Type = readUnencodedNumber<uint64_t>();
if (std::error_code EC = Type.getError())
return EC;
Entry.Type = static_cast<SecType>(*Type);
auto Flags = readUnencodedNumber<uint64_t>();
if (std::error_code EC = Flags.getError())
return EC;
Entry.Flags = *Flags;
auto Offset = readUnencodedNumber<uint64_t>();
if (std::error_code EC = Offset.getError())
return EC;
Entry.Offset = *Offset;
auto Size = readUnencodedNumber<uint64_t>();
if (std::error_code EC = Size.getError())
return EC;
Entry.Size = *Size;
Entry.LayoutIndex = Idx;
SecHdrTable.push_back(std::move(Entry));
return sampleprof_error::success;
}
std::error_code SampleProfileReaderExtBinaryBase::readSecHdrTable() {
auto EntryNum = readUnencodedNumber<uint64_t>();
if (std::error_code EC = EntryNum.getError())
return EC;
for (uint32_t i = 0; i < (*EntryNum); i++)
if (std::error_code EC = readSecHdrTableEntry(i))
return EC;
return sampleprof_error::success;
}
std::error_code SampleProfileReaderExtBinaryBase::readHeader() {
const uint8_t *BufStart =
reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
Data = BufStart;
End = BufStart + Buffer->getBufferSize();
if (std::error_code EC = readMagicIdent())
return EC;
if (std::error_code EC = readSecHdrTable())
return EC;
return sampleprof_error::success;
}
uint64_t SampleProfileReaderExtBinaryBase::getSectionSize(SecType Type) {
uint64_t Size = 0;
for (auto &Entry : SecHdrTable) {
if (Entry.Type == Type)
Size += Entry.Size;
}
return Size;
}
uint64_t SampleProfileReaderExtBinaryBase::getFileSize() {
uint64_t FileSize = 0;
for (auto &Entry : SecHdrTable) {
FileSize = std::max(Entry.Offset + Entry.Size, FileSize);
}
return FileSize;
}
static std::string getSecFlagsStr(const SecHdrTableEntry &Entry) {
std::string Flags;
if (hasSecFlag(Entry, SecCommonFlags::SecFlagCompress))
Flags.append("{compressed,");
else
Flags.append("{");
if (hasSecFlag(Entry, SecCommonFlags::SecFlagFlat))
Flags.append("flat,");
switch (Entry.Type) {
case SecNameTable:
if (hasSecFlag(Entry, SecNameTableFlags::SecFlagFixedLengthMD5))
Flags.append("fixlenmd5,");
else if (hasSecFlag(Entry, SecNameTableFlags::SecFlagMD5Name))
Flags.append("md5,");
if (hasSecFlag(Entry, SecNameTableFlags::SecFlagUniqSuffix))
Flags.append("uniq,");
break;
case SecProfSummary:
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagPartial))
Flags.append("partial,");
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFullContext))
Flags.append("context,");
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagIsPreInlined))
Flags.append("preInlined,");
if (hasSecFlag(Entry, SecProfSummaryFlags::SecFlagFSDiscriminator))
Flags.append("fs-discriminator,");
break;
case SecFuncOffsetTable:
if (hasSecFlag(Entry, SecFuncOffsetFlags::SecFlagOrdered))
Flags.append("ordered,");
break;
case SecFuncMetadata:
if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagIsProbeBased))
Flags.append("probe,");
if (hasSecFlag(Entry, SecFuncMetadataFlags::SecFlagHasAttribute))
Flags.append("attr,");
break;
default:
break;
}
char &last = Flags.back();
if (last == ',')
last = '}';
else
Flags.append("}");
return Flags;
}
bool SampleProfileReaderExtBinaryBase::dumpSectionInfo(raw_ostream &OS) {
uint64_t TotalSecsSize = 0;
for (auto &Entry : SecHdrTable) {
OS << getSecName(Entry.Type) << " - Offset: " << Entry.Offset
<< ", Size: " << Entry.Size << ", Flags: " << getSecFlagsStr(Entry)
<< "\n";
;
TotalSecsSize += Entry.Size;
}
uint64_t HeaderSize = SecHdrTable.front().Offset;
assert(HeaderSize + TotalSecsSize == getFileSize() &&
"Size of 'header + sections' doesn't match the total size of profile");
OS << "Header Size: " << HeaderSize << "\n";
OS << "Total Sections Size: " << TotalSecsSize << "\n";
OS << "File Size: " << getFileSize() << "\n";
return true;
}
std::error_code SampleProfileReaderBinary::readMagicIdent() {
auto Magic = readNumber<uint64_t>();
if (std::error_code EC = Magic.getError())
return EC;
else if (std::error_code EC = verifySPMagic(*Magic))
return EC;
auto Version = readNumber<uint64_t>();
if (std::error_code EC = Version.getError())
return EC;
else if (*Version != SPVersion())
return sampleprof_error::unsupported_version;
return sampleprof_error::success;
}
std::error_code SampleProfileReaderBinary::readHeader() {
Data = reinterpret_cast<const uint8_t *>(Buffer->getBufferStart());
End = Data + Buffer->getBufferSize();
if (std::error_code EC = readMagicIdent())
return EC;
if (std::error_code EC = readSummary())
return EC;
if (std::error_code EC = readNameTable())
return EC;
return sampleprof_error::success;
}
std::error_code SampleProfileReaderCompactBinary::readHeader() {
SampleProfileReaderBinary::readHeader();
if (std::error_code EC = readFuncOffsetTable())
return EC;
return sampleprof_error::success;
}
std::error_code SampleProfileReaderCompactBinary::readFuncOffsetTable() {
auto TableOffset = readUnencodedNumber<uint64_t>();
if (std::error_code EC = TableOffset.getError())
return EC;
const uint8_t *SavedData = Data;
const uint8_t *TableStart =
reinterpret_cast<const uint8_t *>(Buffer->getBufferStart()) +
*TableOffset;
Data = TableStart;
auto Size = readNumber<uint64_t>();
if (std::error_code EC = Size.getError())
return EC;
FuncOffsetTable.reserve(*Size);
for (uint32_t I = 0; I < *Size; ++I) {
auto FName(readStringFromTable());
if (std::error_code EC = FName.getError())
return EC;
auto Offset = readNumber<uint64_t>();
if (std::error_code EC = Offset.getError())
return EC;
FuncOffsetTable[*FName] = *Offset;
}
End = TableStart;
Data = SavedData;
return sampleprof_error::success;
}
bool SampleProfileReaderCompactBinary::collectFuncsFromModule() {
if (!M)
return false;
FuncsToUse.clear();
for (auto &F : *M)
FuncsToUse.insert(FunctionSamples::getCanonicalFnName(F));
return true;
}
std::error_code SampleProfileReaderBinary::readSummaryEntry(
std::vector<ProfileSummaryEntry> &Entries) {
auto Cutoff = readNumber<uint64_t>();
if (std::error_code EC = Cutoff.getError())
return EC;
auto MinBlockCount = readNumber<uint64_t>();
if (std::error_code EC = MinBlockCount.getError())
return EC;
auto NumBlocks = readNumber<uint64_t>();
if (std::error_code EC = NumBlocks.getError())
return EC;
Entries.emplace_back(*Cutoff, *MinBlockCount, *NumBlocks);
return sampleprof_error::success;
}
std::error_code SampleProfileReaderBinary::readSummary() {
auto TotalCount = readNumber<uint64_t>();
if (std::error_code EC = TotalCount.getError())
return EC;
auto MaxBlockCount = readNumber<uint64_t>();
if (std::error_code EC = MaxBlockCount.getError())
return EC;
auto MaxFunctionCount = readNumber<uint64_t>();
if (std::error_code EC = MaxFunctionCount.getError())
return EC;
auto NumBlocks = readNumber<uint64_t>();
if (std::error_code EC = NumBlocks.getError())
return EC;
auto NumFunctions = readNumber<uint64_t>();
if (std::error_code EC = NumFunctions.getError())
return EC;
auto NumSummaryEntries = readNumber<uint64_t>();
if (std::error_code EC = NumSummaryEntries.getError())
return EC;
std::vector<ProfileSummaryEntry> Entries;
for (unsigned i = 0; i < *NumSummaryEntries; i++) {
std::error_code EC = readSummaryEntry(Entries);
if (EC != sampleprof_error::success)
return EC;
}
Summary = std::make_unique<ProfileSummary>(
ProfileSummary::PSK_Sample, Entries, *TotalCount, *MaxBlockCount, 0,
*MaxFunctionCount, *NumBlocks, *NumFunctions);
return sampleprof_error::success;
}
bool SampleProfileReaderRawBinary::hasFormat(const MemoryBuffer &Buffer) {
const uint8_t *Data =
reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
uint64_t Magic = decodeULEB128(Data);
return Magic == SPMagic();
}
bool SampleProfileReaderExtBinary::hasFormat(const MemoryBuffer &Buffer) {
const uint8_t *Data =
reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
uint64_t Magic = decodeULEB128(Data);
return Magic == SPMagic(SPF_Ext_Binary);
}
bool SampleProfileReaderCompactBinary::hasFormat(const MemoryBuffer &Buffer) {
const uint8_t *Data =
reinterpret_cast<const uint8_t *>(Buffer.getBufferStart());
uint64_t Magic = decodeULEB128(Data);
return Magic == SPMagic(SPF_Compact_Binary);
}
std::error_code SampleProfileReaderGCC::skipNextWord() {
uint32_t dummy;
if (!GcovBuffer.readInt(dummy))
return sampleprof_error::truncated;
return sampleprof_error::success;
}
template <typename T> ErrorOr<T> SampleProfileReaderGCC::readNumber() {
if (sizeof(T) <= sizeof(uint32_t)) {
uint32_t Val;
if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
return static_cast<T>(Val);
} else if (sizeof(T) <= sizeof(uint64_t)) {
uint64_t Val;
if (GcovBuffer.readInt64(Val) && Val <= std::numeric_limits<T>::max())
return static_cast<T>(Val);
}
std::error_code EC = sampleprof_error::malformed;
reportError(0, EC.message());
return EC;
}
ErrorOr<StringRef> SampleProfileReaderGCC::readString() {
StringRef Str;
if (!GcovBuffer.readString(Str))
return sampleprof_error::truncated;
return Str;
}
std::error_code SampleProfileReaderGCC::readHeader() {
if (!GcovBuffer.readGCDAFormat())
return sampleprof_error::unrecognized_format;
GCOV::GCOVVersion version;
if (!GcovBuffer.readGCOVVersion(version))
return sampleprof_error::unrecognized_format;
if (version != GCOV::V407)
return sampleprof_error::unsupported_version;
if (std::error_code EC = skipNextWord())
return EC;
return sampleprof_error::success;
}
std::error_code SampleProfileReaderGCC::readSectionTag(uint32_t Expected) {
uint32_t Tag;
if (!GcovBuffer.readInt(Tag))
return sampleprof_error::truncated;
if (Tag != Expected)
return sampleprof_error::malformed;
if (std::error_code EC = skipNextWord())
return EC;
return sampleprof_error::success;
}
std::error_code SampleProfileReaderGCC::readNameTable() {
if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
return EC;
uint32_t Size;
if (!GcovBuffer.readInt(Size))
return sampleprof_error::truncated;
for (uint32_t I = 0; I < Size; ++I) {
StringRef Str;
if (!GcovBuffer.readString(Str))
return sampleprof_error::truncated;
Names.push_back(std::string(Str));
}
return sampleprof_error::success;
}
std::error_code SampleProfileReaderGCC::readFunctionProfiles() {
if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
return EC;
uint32_t NumFunctions;
if (!GcovBuffer.readInt(NumFunctions))
return sampleprof_error::truncated;
InlineCallStack Stack;
for (uint32_t I = 0; I < NumFunctions; ++I)
if (std::error_code EC = readOneFunctionProfile(Stack, true, 0))
return EC;
computeSummary();
return sampleprof_error::success;
}
std::error_code SampleProfileReaderGCC::readOneFunctionProfile(
const InlineCallStack &InlineStack, bool Update, uint32_t Offset) {
uint64_t HeadCount = 0;
if (InlineStack.size() == 0)
if (!GcovBuffer.readInt64(HeadCount))
return sampleprof_error::truncated;
uint32_t NameIdx;
if (!GcovBuffer.readInt(NameIdx))
return sampleprof_error::truncated;
StringRef Name(Names[NameIdx]);
uint32_t NumPosCounts;
if (!GcovBuffer.readInt(NumPosCounts))
return sampleprof_error::truncated;
uint32_t NumCallsites;
if (!GcovBuffer.readInt(NumCallsites))
return sampleprof_error::truncated;
FunctionSamples *FProfile = nullptr;
if (InlineStack.size() == 0) {
FProfile = &Profiles[Name];
FProfile->addHeadSamples(HeadCount);
if (FProfile->getTotalSamples() > 0)
Update = false;
} else {
FunctionSamples *CallerProfile = InlineStack.front();
uint32_t LineOffset = Offset >> 16;
uint32_t Discriminator = Offset & 0xffff;
FProfile = &CallerProfile->functionSamplesAt(
LineLocation(LineOffset, Discriminator))[std::string(Name)];
}
FProfile->setName(Name);
for (uint32_t I = 0; I < NumPosCounts; ++I) {
uint32_t Offset;
if (!GcovBuffer.readInt(Offset))
return sampleprof_error::truncated;
uint32_t NumTargets;
if (!GcovBuffer.readInt(NumTargets))
return sampleprof_error::truncated;
uint64_t Count;
if (!GcovBuffer.readInt64(Count))
return sampleprof_error::truncated;
uint32_t LineOffset = Offset >> 16;
uint32_t Discriminator = Offset & 0xffff;
InlineCallStack NewStack;
NewStack.push_back(FProfile);
llvm::append_range(NewStack, InlineStack);
if (Update) {
for (auto CallerProfile : NewStack)
CallerProfile->addTotalSamples(Count);
FProfile->addBodySamples(LineOffset, Discriminator, Count);
}
for (uint32_t J = 0; J < NumTargets; J++) {
uint32_t HistVal;
if (!GcovBuffer.readInt(HistVal))
return sampleprof_error::truncated;
if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
return sampleprof_error::malformed;
uint64_t TargetIdx;
if (!GcovBuffer.readInt64(TargetIdx))
return sampleprof_error::truncated;
StringRef TargetName(Names[TargetIdx]);
uint64_t TargetCount;
if (!GcovBuffer.readInt64(TargetCount))
return sampleprof_error::truncated;
if (Update)
FProfile->addCalledTargetSamples(LineOffset, Discriminator,
TargetName, TargetCount);
}
}
for (uint32_t I = 0; I < NumCallsites; I++) {
uint32_t Offset;
if (!GcovBuffer.readInt(Offset))
return sampleprof_error::truncated;
InlineCallStack NewStack;
NewStack.push_back(FProfile);
llvm::append_range(NewStack, InlineStack);
if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset))
return EC;
}
return sampleprof_error::success;
}
std::error_code SampleProfileReaderGCC::readImpl() {
assert(!ProfileIsFSDisciminator && "Gcc profiles not support FSDisciminator");
if (std::error_code EC = readNameTable())
return EC;
if (std::error_code EC = readFunctionProfiles())
return EC;
return sampleprof_error::success;
}
bool SampleProfileReaderGCC::hasFormat(const MemoryBuffer &Buffer) {
StringRef Magic(reinterpret_cast<const char *>(Buffer.getBufferStart()));
return Magic == "adcg*704";
}
void SampleProfileReaderItaniumRemapper::applyRemapping(LLVMContext &Ctx) {
if (Reader.useMD5()) {
Ctx.diagnose(DiagnosticInfoSampleProfile(
Reader.getBuffer()->getBufferIdentifier(),
"Profile data remapping cannot be applied to profile data "
"in compact format (original mangled names are not available).",
DS_Warning));
return;
}
assert(Remappings && "should be initialized while creating remapper");
for (auto &Sample : Reader.getProfiles()) {
DenseSet<StringRef> NamesInSample;
Sample.second.findAllNames(NamesInSample);
for (auto &Name : NamesInSample)
if (auto Key = Remappings->insert(Name))
NameMap.insert({Key, Name});
}
RemappingApplied = true;
}
Optional<StringRef>
SampleProfileReaderItaniumRemapper::lookUpNameInProfile(StringRef Fname) {
if (auto Key = Remappings->lookup(Fname))
return NameMap.lookup(Key);
return None;
}
static ErrorOr<std::unique_ptr<MemoryBuffer>>
setupMemoryBuffer(const Twine &Filename) {
auto BufferOrErr = MemoryBuffer::getFileOrSTDIN(Filename, true);
if (std::error_code EC = BufferOrErr.getError())
return EC;
auto Buffer = std::move(BufferOrErr.get());
if (uint64_t(Buffer->getBufferSize()) > std::numeric_limits<uint32_t>::max())
return sampleprof_error::too_large;
return std::move(Buffer);
}
ErrorOr<std::unique_ptr<SampleProfileReader>>
SampleProfileReader::create(const std::string Filename, LLVMContext &C,
FSDiscriminatorPass P,
const std::string RemapFilename) {
auto BufferOrError = setupMemoryBuffer(Filename);
if (std::error_code EC = BufferOrError.getError())
return EC;
return create(BufferOrError.get(), C, P, RemapFilename);
}
ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
SampleProfileReaderItaniumRemapper::create(const std::string Filename,
SampleProfileReader &Reader,
LLVMContext &C) {
auto BufferOrError = setupMemoryBuffer(Filename);
if (std::error_code EC = BufferOrError.getError())
return EC;
return create(BufferOrError.get(), Reader, C);
}
ErrorOr<std::unique_ptr<SampleProfileReaderItaniumRemapper>>
SampleProfileReaderItaniumRemapper::create(std::unique_ptr<MemoryBuffer> &B,
SampleProfileReader &Reader,
LLVMContext &C) {
auto Remappings = std::make_unique<SymbolRemappingReader>();
if (Error E = Remappings->read(*B)) {
handleAllErrors(
std::move(E), [&](const SymbolRemappingParseError &ParseError) {
C.diagnose(DiagnosticInfoSampleProfile(B->getBufferIdentifier(),
ParseError.getLineNum(),
ParseError.getMessage()));
});
return sampleprof_error::malformed;
}
return std::make_unique<SampleProfileReaderItaniumRemapper>(
std::move(B), std::move(Remappings), Reader);
}
ErrorOr<std::unique_ptr<SampleProfileReader>>
SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C,
FSDiscriminatorPass P,
const std::string RemapFilename) {
std::unique_ptr<SampleProfileReader> Reader;
if (SampleProfileReaderRawBinary::hasFormat(*B))
Reader.reset(new SampleProfileReaderRawBinary(std::move(B), C));
else if (SampleProfileReaderExtBinary::hasFormat(*B))
Reader.reset(new SampleProfileReaderExtBinary(std::move(B), C));
else if (SampleProfileReaderCompactBinary::hasFormat(*B))
Reader.reset(new SampleProfileReaderCompactBinary(std::move(B), C));
else if (SampleProfileReaderGCC::hasFormat(*B))
Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
else if (SampleProfileReaderText::hasFormat(*B))
Reader.reset(new SampleProfileReaderText(std::move(B), C));
else
return sampleprof_error::unrecognized_format;
if (!RemapFilename.empty()) {
auto ReaderOrErr =
SampleProfileReaderItaniumRemapper::create(RemapFilename, *Reader, C);
if (std::error_code EC = ReaderOrErr.getError()) {
std::string Msg = "Could not create remapper: " + EC.message();
C.diagnose(DiagnosticInfoSampleProfile(RemapFilename, Msg));
return EC;
}
Reader->Remapper = std::move(ReaderOrErr.get());
}
if (std::error_code EC = Reader->readHeader()) {
return EC;
}
Reader->setDiscriminatorMaskedBitFrom(P);
return std::move(Reader);
}
void SampleProfileReader::computeSummary() {
SampleProfileSummaryBuilder Builder(ProfileSummaryBuilder::DefaultCutoffs);
Summary = Builder.computeSummaryForProfiles(Profiles);
}