23#define DEBUG_TYPE "correlator"
31 std::string ExpectedSectionName =
38 return make_error<InstrProfError>(
39 instrprof_error::unable_to_correlate_profile,
40 "could not find section (" +
Twine(ExpectedSectionName) +
")");
51 if (
auto Err = CountersSection.takeError())
52 return std::move(Err);
53 auto C = std::make_unique<Context>();
55 C->CountersSectionStart = CountersSection->getAddress();
56 C->CountersSectionEnd =
C->CountersSectionStart + CountersSection->getSize();
64 auto DsymObjectsOrErr =
66 if (
auto Err = DsymObjectsOrErr.takeError())
67 return std::move(Err);
68 if (!DsymObjectsOrErr->empty()) {
71 if (DsymObjectsOrErr->size() > 1)
72 return make_error<InstrProfError>(
74 "using multiple objects is not yet supported");
75 Filename = *DsymObjectsOrErr->begin();
78 if (
auto Err = BufferOrErr.takeError())
79 return std::move(Err);
81 return get(std::move(*BufferOrErr), FileKind);
83 return make_error<InstrProfError>(
85 "unsupported correlation kind (only DWARF debug info is supported)");
92 if (
auto Err = BinOrErr.takeError())
93 return std::move(Err);
95 if (
auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
97 if (
auto Err = CtxOrErr.takeError())
98 return std::move(Err);
99 auto T = Obj->makeTriple();
107 return make_error<InstrProfError>(
113 return C->getDataSize();
115 return C->getDataSize();
124 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
129 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
134 return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
138 return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
143template <
class IntPtrT>
146 std::unique_ptr<InstrProfCorrelator::Context> Ctx,
148 if (FileKind == DEBUG_INFO) {
151 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
152 std::move(DICtx), std::move(Ctx));
154 return make_error<InstrProfError>(
155 instrprof_error::unable_to_correlate_profile,
156 "unsupported debug info format (only DWARF is supported)");
158 return make_error<InstrProfError>(
159 instrprof_error::unable_to_correlate_profile,
160 "unsupported correlation file type (only DWARF is supported)");
163template <
class IntPtrT>
165 assert(Data.empty() && Names.empty() && NamesVec.empty());
166 correlateProfileDataImpl(MaxWarnings);
167 if (this->Data.empty())
168 return make_error<InstrProfError>(
169 instrprof_error::unable_to_correlate_profile,
170 "could not find any profile data metadata in correlated file");
171 Error Result = correlateProfileNameImpl();
172 this->CounterOffsets.clear();
173 this->NamesVec.clear();
180 io.mapRequired(
"Probes",
Data.Probes);
186 io.mapRequired(
"Function Name",
P.FunctionName);
187 io.mapOptional(
"Linkage Name",
P.LinkageName);
188 io.mapRequired(
"CFG Hash",
P.CFGHash);
189 io.mapRequired(
"Counter Offset",
P.CounterOffset);
190 io.mapRequired(
"Num Counters",
P.NumCounters);
191 io.mapOptional(
"File",
P.FilePath);
192 io.mapOptional(
"Line",
P.LineNumber);
197 static const bool flow =
false;
200template <
class IntPtrT>
204 correlateProfileDataImpl(MaxWarnings, &Data);
205 if (Data.Probes.empty())
206 return make_error<InstrProfError>(
207 instrprof_error::unable_to_correlate_profile,
208 "could not find any profile data metadata in debug info");
209 yaml::Output YamlOS(
OS);
214template <
class IntPtrT>
221 if (!CounterOffsets.insert(CounterOffset).second)
225 maybeSwap<uint64_t>(CFGHash),
228 maybeSwap<IntPtrT>(CounterOffset),
230 maybeSwap<IntPtrT>(0),
231 maybeSwap<IntPtrT>(FunctionPtr),
233 maybeSwap<IntPtrT>(0),
234 maybeSwap<uint32_t>(NumCounters),
235 {maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
237 maybeSwap<uint32_t>(0),
239 NamesVec.push_back(FunctionName.
str());
242template <
class IntPtrT>
243std::optional<uint64_t>
245 auto Locations = Die.
getLocations(dwarf::DW_AT_location);
252 for (
auto &Location : *Locations) {
255 for (
auto &
Op : Expr) {
258 }
else if (
Op.
getCode() == dwarf::DW_OP_addrx) {
260 if (
auto SA = DU.getAddrOffsetSectionItem(
Index))
268template <
class IntPtrT>
273 if (Die.
getTag() != dwarf::DW_TAG_variable)
275 if (!ParentDie.isSubprogramDIE())
279 if (
const char *
Name = Die.
getName(DINameKind::ShortName))
284template <
class IntPtrT>
287 bool UnlimitedWarnings = (MaxWarnings == 0);
289 int NumSuppressedWarnings = -MaxWarnings;
290 auto maybeAddProbe = [&](
DWARFDie Die) {
291 if (!isDIEOfProbe(Die))
293 std::optional<const char *> FunctionName;
294 std::optional<uint64_t> CFGHash;
295 std::optional<uint64_t> CounterPtr =
getLocation(Die);
298 std::optional<uint64_t> NumCounters;
300 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
302 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
303 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
304 if (!AnnotationFormName || !AnnotationFormValue)
306 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
307 if (
auto Err = AnnotationNameOrErr.takeError()) {
311 StringRef AnnotationName = *AnnotationNameOrErr;
315 AnnotationFormValue->getAsCString().moveInto(FunctionName))
317 }
else if (AnnotationName.
compare(
319 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
320 }
else if (AnnotationName.
compare(
322 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
325 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
326 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
328 <<
"Incomplete DIE for function " << FunctionName
329 <<
": CFGHash=" << CFGHash <<
" CounterPtr=" << CounterPtr
330 <<
" NumCounters=" << NumCounters <<
"\n";
335 uint64_t CountersStart = this->Ctx->CountersSectionStart;
336 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
337 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
338 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
340 <<
format(
"CounterPtr out of range for function %s: Actual=0x%x "
341 "Expected=[0x%x, 0x%x)\n",
342 *FunctionName, *CounterPtr, CountersStart, CountersEnd);
347 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
352 IntPtrT CounterOffset = *CounterPtr - CountersStart;
355 P.FunctionName = *FunctionName;
356 if (
auto Name = FnDie.getName(DINameKind::LinkageName))
357 P.LinkageName =
Name;
358 P.CFGHash = *CFGHash;
359 P.CounterOffset = CounterOffset;
360 P.NumCounters = *NumCounters;
361 auto FilePath = FnDie.getDeclFile(
362 DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
363 if (!FilePath.empty())
364 P.FilePath = FilePath;
365 if (
auto LineNumber = FnDie.getDeclLine())
366 P.LineNumber = LineNumber;
367 Data->Probes.push_back(
P);
369 this->addProbe(*FunctionName, *CFGHash, CounterOffset,
370 FunctionPtr.value_or(0), *NumCounters);
373 for (
auto &
CU : DICtx->normal_units())
374 for (
const auto &Entry :
CU->dies())
376 for (
auto &
CU : DICtx->dwo_units())
377 for (
const auto &Entry :
CU->dies())
380 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
382 NumSuppressedWarnings);
385template <
class IntPtrT>
387 if (this->NamesVec.empty()) {
388 return make_error<InstrProfError>(
389 instrprof_error::unable_to_correlate_profile,
390 "could not find any profile name metadata in debug info");
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)
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 addProbe(StringRef 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 which kind correlator to use.
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...
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.
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)