23#define DEBUG_TYPE "correlator"
37 std::string ExpectedSectionName =
40 ExpectedSectionName = StripSuffix(ExpectedSectionName);
41 for (
auto &Section : Obj.
sections()) {
46 return make_error<InstrProfError>(
47 instrprof_error::unable_to_correlate_profile,
48 "could not find section (" +
Twine(ExpectedSectionName) +
")");
59 auto C = std::make_unique<Context>();
61 if (
auto Err = CountersSection.takeError())
62 return std::move(Err);
65 if (
auto Err = DataSection.takeError())
66 return std::move(Err);
67 auto DataOrErr = DataSection->getContents();
69 return DataOrErr.takeError();
71 if (
auto Err = NameSection.takeError())
72 return std::move(Err);
73 auto NameOrErr = NameSection->getContents();
75 return NameOrErr.takeError();
76 C->DataStart = DataOrErr->data();
77 C->DataEnd = DataOrErr->data() + DataOrErr->size();
78 C->NameStart = NameOrErr->data();
79 C->NameSize = NameOrErr->size();
82 C->CountersSectionStart = CountersSection->getAddress();
83 C->CountersSectionEnd =
C->CountersSectionStart + CountersSection->getSize();
87 ++
C->CountersSectionStart;
96 auto DsymObjectsOrErr =
98 if (
auto Err = DsymObjectsOrErr.takeError())
99 return std::move(Err);
100 if (!DsymObjectsOrErr->empty()) {
103 if (DsymObjectsOrErr->size() > 1)
104 return make_error<InstrProfError>(
106 "using multiple objects is not yet supported");
107 Filename = *DsymObjectsOrErr->begin();
110 if (
auto Err = BufferOrErr.takeError())
111 return std::move(Err);
113 return get(std::move(*BufferOrErr), FileKind);
117 if (
auto Err = BufferOrErr.takeError())
118 return std::move(Err);
120 return get(std::move(*BufferOrErr), FileKind);
122 return make_error<InstrProfError>(
124 "unsupported correlation kind (only DWARF debug info and Binary format "
125 "(ELF/COFF) are supported)");
132 if (
auto Err = BinOrErr.takeError())
133 return std::move(Err);
135 if (
auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
136 auto CtxOrErr =
Context::get(std::move(Buffer), *Obj, FileKind);
137 if (
auto Err = CtxOrErr.takeError())
138 return std::move(Err);
139 auto T = Obj->makeTriple();
147 return make_error<InstrProfError>(
153 return C->getDataSize();
155 return C->getDataSize();
164 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
169 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
174 return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
178 return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
183template <
class IntPtrT>
186 std::unique_ptr<InstrProfCorrelator::Context> Ctx,
188 if (FileKind == DEBUG_INFO) {
191 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
192 std::move(DICtx), std::move(Ctx));
194 return make_error<InstrProfError>(
195 instrprof_error::unable_to_correlate_profile,
196 "unsupported debug info format (only DWARF is supported)");
199 return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx));
200 return make_error<InstrProfError>(
201 instrprof_error::unable_to_correlate_profile,
202 "unsupported binary format (only ELF and COFF are supported)");
205template <
class IntPtrT>
207 assert(Data.empty() && Names.empty() && NamesVec.empty());
208 correlateProfileDataImpl(MaxWarnings);
209 if (this->Data.empty())
210 return make_error<InstrProfError>(
211 instrprof_error::unable_to_correlate_profile,
212 "could not find any profile data metadata in correlated file");
213 Error Result = correlateProfileNameImpl();
214 this->CounterOffsets.clear();
215 this->NamesVec.clear();
222 io.mapRequired(
"Probes",
Data.Probes);
228 io.mapRequired(
"Function Name",
P.FunctionName);
229 io.mapOptional(
"Linkage Name",
P.LinkageName);
230 io.mapRequired(
"CFG Hash",
P.CFGHash);
231 io.mapRequired(
"Counter Offset",
P.CounterOffset);
232 io.mapRequired(
"Num Counters",
P.NumCounters);
233 io.mapOptional(
"File",
P.FilePath);
234 io.mapOptional(
"Line",
P.LineNumber);
239 static const bool flow =
false;
242template <
class IntPtrT>
246 correlateProfileDataImpl(MaxWarnings, &Data);
247 if (Data.Probes.empty())
248 return make_error<InstrProfError>(
249 instrprof_error::unable_to_correlate_profile,
250 "could not find any profile data metadata in debug info");
251 yaml::Output YamlOS(
OS);
256template <
class IntPtrT>
263 if (!CounterOffsets.insert(CounterOffset).second)
266 maybeSwap<uint64_t>(NameRef),
267 maybeSwap<uint64_t>(CFGHash),
270 maybeSwap<IntPtrT>(CounterOffset),
272 maybeSwap<IntPtrT>(0),
273 maybeSwap<IntPtrT>(FunctionPtr),
275 maybeSwap<IntPtrT>(0),
276 maybeSwap<uint32_t>(NumCounters),
277 {maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
279 maybeSwap<uint32_t>(0),
283template <
class IntPtrT>
284std::optional<uint64_t>
286 auto Locations = Die.
getLocations(dwarf::DW_AT_location);
293 for (
auto &Location : *Locations) {
296 for (
auto &
Op : Expr) {
299 }
else if (
Op.
getCode() == dwarf::DW_OP_addrx) {
301 if (
auto SA = DU.getAddrOffsetSectionItem(
Index))
309template <
class IntPtrT>
314 if (Die.
getTag() != dwarf::DW_TAG_variable)
316 if (!ParentDie.isSubprogramDIE())
320 if (
const char *
Name = Die.
getName(DINameKind::ShortName))
325template <
class IntPtrT>
328 bool UnlimitedWarnings = (MaxWarnings == 0);
330 int NumSuppressedWarnings = -MaxWarnings;
331 auto maybeAddProbe = [&](
DWARFDie Die) {
332 if (!isDIEOfProbe(Die))
334 std::optional<const char *> FunctionName;
335 std::optional<uint64_t> CFGHash;
336 std::optional<uint64_t> CounterPtr =
getLocation(Die);
339 std::optional<uint64_t> NumCounters;
341 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
343 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
344 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
345 if (!AnnotationFormName || !AnnotationFormValue)
347 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
348 if (
auto Err = AnnotationNameOrErr.takeError()) {
352 StringRef AnnotationName = *AnnotationNameOrErr;
355 AnnotationFormValue->getAsCString().moveInto(FunctionName))
358 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
359 }
else if (AnnotationName ==
361 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
364 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
365 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
367 <<
"Incomplete DIE for function " << FunctionName
368 <<
": CFGHash=" << CFGHash <<
" CounterPtr=" << CounterPtr
369 <<
" NumCounters=" << NumCounters <<
"\n";
374 uint64_t CountersStart = this->Ctx->CountersSectionStart;
375 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
376 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
377 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
379 <<
format(
"CounterPtr out of range for function %s: Actual=0x%x "
380 "Expected=[0x%x, 0x%x)\n",
381 *FunctionName, *CounterPtr, CountersStart, CountersEnd);
386 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
393 IntPtrT CounterOffset = *CounterPtr - CountersStart;
396 P.FunctionName = *FunctionName;
397 if (
auto Name = FnDie.getName(DINameKind::LinkageName))
398 P.LinkageName =
Name;
399 P.CFGHash = *CFGHash;
400 P.CounterOffset = CounterOffset;
401 P.NumCounters = *NumCounters;
402 auto FilePath = FnDie.getDeclFile(
403 DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
404 if (!FilePath.empty())
405 P.FilePath = FilePath;
406 if (
auto LineNumber = FnDie.getDeclLine())
407 P.LineNumber = LineNumber;
408 Data->Probes.push_back(
P);
411 CounterOffset, FunctionPtr.value_or(0), *NumCounters);
412 this->NamesVec.push_back(*FunctionName);
415 for (
auto &
CU : DICtx->normal_units())
416 for (
const auto &Entry :
CU->dies())
418 for (
auto &
CU : DICtx->dwo_units())
419 for (
const auto &Entry :
CU->dies())
422 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
424 NumSuppressedWarnings);
427template <
class IntPtrT>
429 if (this->NamesVec.empty()) {
430 return make_error<InstrProfError>(
431 instrprof_error::unable_to_correlate_profile,
432 "could not find any profile name metadata in debug info");
440template <
class IntPtrT>
444 bool UnlimitedWarnings = (MaxWarnings == 0);
446 int NumSuppressedWarnings = -MaxWarnings;
448 const RawProfData *DataStart = (
const RawProfData *)this->Ctx->DataStart;
449 const RawProfData *DataEnd = (
const RawProfData *)this->Ctx->DataEnd;
451 for (
const RawProfData *
I = DataStart;
I < DataEnd; ++
I) {
452 uint64_t CounterPtr = this->
template maybeSwap<IntPtrT>(
I->CounterPtr);
453 uint64_t CountersStart = this->Ctx->CountersSectionStart;
454 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
455 if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
456 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
458 <<
format(
"CounterPtr out of range for function: Actual=0x%x "
459 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
460 CounterPtr, CountersStart, CountersEnd,
461 (
I - DataStart) *
sizeof(RawProfData));
466 IntPtrT CounterOffset = CounterPtr - CountersStart;
467 this->addDataProbe(
I->NameRef,
I->FuncHash, CounterOffset,
468 I->FunctionPointer,
I->NumCounters);
472template <
class IntPtrT>
474 if (this->Ctx->NameSize == 0) {
475 return make_error<InstrProfError>(
476 instrprof_error::unable_to_correlate_profile,
477 "could not find any profile data metadata in object file");
479 this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
Expected< object::SectionRef > getInstrProfSection(const object::ObjectFile &Obj, InstrProfSectKind IPSK)
Get profile section.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static MemoryLocation getLocation(Instruction *I)
BinaryInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes an object file as input to ...
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, bool ThreadSafe=false)
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.
This class represents an Operation in the Expression.
uint64_t getRawOperand(unsigned Idx) const
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...
static llvm::Expected< std::unique_ptr< InstrProfCorrelatorImpl< IntPtrT > > > get(std::unique_ptr< InstrProfCorrelator::Context > Ctx, const object::ObjectFile &Obj, ProfCorrelatorKind FileKind)
Error correlateProfileData(int MaxWarnings) override
Construct a ProfileData vector used to correlate raw instrumentation data to their functions.
static bool classof(const InstrProfCorrelator *C)
InstrProfCorrelatorImpl(std::unique_ptr< InstrProfCorrelator::Context > Ctx)
void addDataProbe(uint64_t FunctionName, uint64_t CFGHash, IntPtrT CounterOffset, IntPtrT FunctionPtr, uint32_t NumCounters)
Error dumpYaml(int MaxWarnings, raw_ostream &OS) override
Process debug info and dump the correlation data.
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 Filename, ProfCorrelatorKind FileKind)
static const char * NumCountersAttributeName
ProfCorrelatorKind
Indicate if we should use the debug info or profile metadata sections to correlate.
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.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
static raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
Triple::ObjectFormatType getTripleObjectFormat() const
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.
std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
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.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
@ unable_to_correlate_profile
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
Error collectGlobalObjectNameStrings(ArrayRef< std::string > NameStrs, bool doCompression, std::string &Result)
Given a vector of strings (names of global objects like functions or, virtual tables) NameStrs,...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
void consumeError(Error Err)
Consume a Error without doing anything.
Implement std::hash so that hash_code can be used in STL containers.
std::unique_ptr< MemoryBuffer > Buffer
static llvm::Expected< std::unique_ptr< Context > > get(std::unique_ptr< MemoryBuffer > Buffer, const object::ObjectFile &Obj, ProfCorrelatorKind FileKind)
static void mapping(yaml::IO &io, InstrProfCorrelator::CorrelationData &Data)
static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P)