21#define DEBUG_TYPE "correlator"
31 return make_error<InstrProfError>(
32 instrprof_error::unable_to_correlate_profile,
33 "could not find counter section (" INSTR_PROF_CNTS_SECT_NAME
")");
44 if (
auto Err = CountersSection.takeError())
45 return std::move(Err);
46 auto C = std::make_unique<Context>();
48 C->CountersSectionStart = CountersSection->getAddress();
49 C->CountersSectionEnd =
C->CountersSectionStart + CountersSection->getSize();
56 auto DsymObjectsOrErr =
58 if (
auto Err = DsymObjectsOrErr.takeError())
59 return std::move(Err);
60 if (!DsymObjectsOrErr->empty()) {
63 if (DsymObjectsOrErr->size() > 1)
64 return make_error<InstrProfError>(
66 "using multiple objects is not yet supported");
67 DebugInfoFilename = *DsymObjectsOrErr->
begin();
71 if (
auto Err = BufferOrErr.takeError())
72 return std::move(Err);
74 return get(std::move(*BufferOrErr));
80 if (
auto Err = BinOrErr.takeError())
81 return std::move(Err);
83 if (
auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
85 if (
auto Err = CtxOrErr.takeError())
86 return std::move(Err);
87 auto T = Obj->makeTriple();
93 return make_error<InstrProfError>(
99 return C->getDataSize();
101 return C->getDataSize();
110 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
115 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
120 return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
124 return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
129template <
class IntPtrT>
132 std::unique_ptr<InstrProfCorrelator::Context> Ctx,
136 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(std::move(DICtx),
139 return make_error<InstrProfError>(
140 instrprof_error::unable_to_correlate_profile,
141 "unsupported debug info format (only DWARF is supported)");
144template <
class IntPtrT>
147 correlateProfileDataImpl();
148 if (
Data.empty() || NamesVec.empty())
149 return make_error<InstrProfError>(
150 instrprof_error::unable_to_correlate_profile,
151 "could not find any profile metadata in debug info");
154 CounterOffsets.clear();
162 io.mapRequired(
"Probes",
Data.Probes);
168 io.mapRequired(
"Function Name",
P.FunctionName);
169 io.mapOptional(
"Linkage Name",
P.LinkageName);
170 io.mapRequired(
"CFG Hash",
P.CFGHash);
171 io.mapRequired(
"Counter Offset",
P.CounterOffset);
172 io.mapRequired(
"Num Counters",
P.NumCounters);
173 io.mapOptional(
"File",
P.FilePath);
174 io.mapOptional(
"Line",
P.LineNumber);
179 static const bool flow =
false;
182template <
class IntPtrT>
185 correlateProfileDataImpl(&
Data);
186 if (
Data.Probes.empty())
187 return make_error<InstrProfError>(
188 instrprof_error::unable_to_correlate_profile,
189 "could not find any profile metadata in debug info");
190 yaml::Output YamlOS(
OS);
195template <
class IntPtrT>
202 if (!CounterOffsets.insert(CounterOffset).second)
206 maybeSwap<uint64_t>(CFGHash),
209 maybeSwap<IntPtrT>(CounterOffset),
210 maybeSwap<IntPtrT>(FunctionPtr),
212 maybeSwap<IntPtrT>(0),
213 maybeSwap<uint32_t>(NumCounters),
214 {maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
216 NamesVec.push_back(FunctionName.
str());
219template <
class IntPtrT>
220std::optional<uint64_t>
222 auto Locations = Die.
getLocations(dwarf::DW_AT_location);
229 for (
auto &Location : *Locations) {
232 for (
auto &Op : Expr) {
233 if (
Op.getCode() == dwarf::DW_OP_addr) {
234 return Op.getRawOperand(0);
235 }
else if (
Op.getCode() == dwarf::DW_OP_addrx) {
237 if (
auto SA = DU.getAddrOffsetSectionItem(
Index))
245template <
class IntPtrT>
250 if (Die.
getTag() != dwarf::DW_TAG_variable)
252 if (!ParentDie.isSubprogramDIE())
256 if (
const char *
Name = Die.
getName(DINameKind::ShortName))
261template <
class IntPtrT>
264 auto maybeAddProbe = [&](
DWARFDie Die) {
265 if (!isDIEOfProbe(Die))
267 std::optional<const char *> FunctionName;
268 std::optional<uint64_t> CFGHash;
269 std::optional<uint64_t> CounterPtr =
getLocation(Die);
272 std::optional<uint64_t> NumCounters;
274 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
276 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
277 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
278 if (!AnnotationFormName || !AnnotationFormValue)
280 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
281 if (
auto Err = AnnotationNameOrErr.takeError()) {
285 StringRef AnnotationName = *AnnotationNameOrErr;
289 AnnotationFormValue->getAsCString().moveInto(FunctionName))
291 }
else if (AnnotationName.
compare(
293 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
294 }
else if (AnnotationName.
compare(
296 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
299 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
301 << FunctionName <<
"\n\tCFGHash: " << CFGHash
302 <<
"\n\tCounterPtr: " << CounterPtr
303 <<
"\n\tNumCounters: " << NumCounters);
307 uint64_t CountersStart = this->Ctx->CountersSectionStart;
308 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
309 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
311 dbgs() <<
"CounterPtr out of range for probe\n\tFunction Name: "
312 << FunctionName <<
"\n\tExpected: [0x"
320 LLVM_DEBUG(
dbgs() <<
"Could not find address of " << *FunctionName
324 IntPtrT CounterOffset = *CounterPtr - CountersStart;
327 P.FunctionName = *FunctionName;
328 if (
auto Name = FnDie.getName(DINameKind::LinkageName))
329 P.LinkageName =
Name;
330 P.CFGHash = *CFGHash;
331 P.CounterOffset = CounterOffset;
332 P.NumCounters = *NumCounters;
333 auto FilePath = FnDie.getDeclFile(
334 DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
335 if (!FilePath.empty())
336 P.FilePath = FilePath;
337 if (
auto LineNumber = FnDie.getDeclLine())
338 P.LineNumber = LineNumber;
339 Data->Probes.push_back(
P);
341 this->addProbe(*FunctionName, *CFGHash, CounterOffset,
342 FunctionPtr.value_or(0), *NumCounters);
345 for (
auto &
CU : DICtx->normal_units())
346 for (
const auto &Entry :
CU->dies())
348 for (
auto &
CU : DICtx->dwo_units())
349 for (
const auto &Entry :
CU->dies())
Expected< object::SectionRef > getCountersSection(const object::ObjectFile &Obj)
Get the __llvm_prf_cnts section.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static MemoryLocation getLocation(Instruction *I)
static std::unique_ptr< DWARFContext > create(const object::ObjectFile &Obj, ProcessDebugRelocations RelocAction=ProcessDebugRelocations::Process, const LoadedObjectInfo *L=nullptr, std::string DWPName="", std::function< void(Error)> RecoverableErrorHandler=WithColor::defaultErrorHandler, std::function< void(Error)> WarningHandler=WithColor::defaultWarningHandler)
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
iterator_range< iterator > children() const
DWARFDie getParent() const
Get the parent of this DIE object.
DWARFUnit * getDwarfUnit() const
const char * getName(DINameKind Kind) const
Return the DIE name resolving DW_AT_specification or DW_AT_abstract_origin references if necessary.
dwarf::Tag getTag() const
Expected< DWARFLocationExpressionsVector > getLocations(dwarf::Attribute Attr) const
bool isNULL() const
Returns true for a valid DIE that terminates a sibling chain.
void dump(raw_ostream &OS, unsigned indent=0, DIDumpOptions DumpOpts=DIDumpOptions()) const
Dump the DIE and all of its attributes to the supplied stream.
uint8_t getAddressByteSize() const
DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes DWARF debug info as input to...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
InstrProfCorrelatorImpl - A child of InstrProfCorrelator with a template pointer type so that the Pro...
Error correlateProfileData() override
Construct a ProfileData vector used to correlate raw instrumentation data to their functions.
Error dumpYaml(raw_ostream &OS) override
Process debug info and dump the correlation data.
static bool classof(const InstrProfCorrelator *C)
InstrProfCorrelatorImpl(std::unique_ptr< InstrProfCorrelator::Context > Ctx)
void addProbe(StringRef FunctionName, uint64_t CFGHash, IntPtrT CounterOffset, IntPtrT FunctionPtr, uint32_t NumCounters)
static llvm::Expected< std::unique_ptr< InstrProfCorrelatorImpl< IntPtrT > > > get(std::unique_ptr< InstrProfCorrelator::Context > Ctx, const object::ObjectFile &Obj)
InstrProfCorrelator - A base class used to create raw instrumentation data to their functions.
static const char * FunctionNameAttributeName
static const char * CFGHashAttributeName
static llvm::Expected< std::unique_ptr< InstrProfCorrelator > > get(StringRef DebugInfoFilename)
static const char * NumCountersAttributeName
std::optional< size_t > getDataSize() const
Return the number of ProfileData elements.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
StringRef - Represent a constant reference to a string, i.e.
std::string str() const
str - Get the contents as an std::string.
bool startswith(StringRef Prefix) const
int compare(StringRef RHS) const
compare - Compare two strings; the result is negative, zero, or positive if this string is lexicograp...
static Twine utohexstr(const uint64_t &Val)
bool isLittleEndian() const
static Expected< std::vector< std::string > > findDsymObjectMembers(StringRef Path)
If the input path is a .dSYM bundle (as created by the dsymutil tool), return the paths to the object...
This class is the base class for all object file types.
section_iterator_range sections() const
This class implements an extremely fast bulk output stream that can only output to a stream.
@ C
The default llvm calling convention, compatible with C.
uint64_t ComputeHash(StringRef K)
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
Expected< std::unique_ptr< Binary > > createBinary(MemoryBufferRef Source, LLVMContext *Context=nullptr, bool InitContent=true)
Create a Binary from Source, autodetecting the file type.
static const bool IsLittleEndianHost
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
StringRef getInstrProfCountersVarPrefix()
Return the name prefix of profile counter variables.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
@ unable_to_correlate_profile
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Error collectPGOFuncNameStrings(ArrayRef< std::string > NameStrs, bool doCompression, std::string &Result)
Given a vector of strings (function PGO names) NameStrs, the method generates a combined string Resul...
void consumeError(Error Err)
Consume a Error without doing anything.
static llvm::Expected< std::unique_ptr< Context > > get(std::unique_ptr< MemoryBuffer > Buffer, const object::ObjectFile &Obj)
std::unique_ptr< MemoryBuffer > Buffer
static void mapping(yaml::IO &io, InstrProfCorrelator::CorrelationData &Data)
static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P)