LLVM 17.0.0git
InstrProfCorrelator.cpp
Go to the documentation of this file.
1//===-- InstrProfCorrelator.cpp -------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
17#include "llvm/Object/MachO.h"
18#include "llvm/Support/Debug.h"
19#include <optional>
20
21#define DEBUG_TYPE "correlator"
22
23using namespace llvm;
24
25/// Get the __llvm_prf_cnts section.
27 for (auto &Section : Obj.sections())
28 if (auto SectionName = Section.getName())
29 if (SectionName.get() == INSTR_PROF_CNTS_SECT_NAME)
30 return Section;
31 return make_error<InstrProfError>(
32 instrprof_error::unable_to_correlate_profile,
33 "could not find counter section (" INSTR_PROF_CNTS_SECT_NAME ")");
34}
35
36const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
37const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash";
38const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
39
41InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
42 const object::ObjectFile &Obj) {
43 auto CountersSection = getCountersSection(Obj);
44 if (auto Err = CountersSection.takeError())
45 return std::move(Err);
46 auto C = std::make_unique<Context>();
47 C->Buffer = std::move(Buffer);
48 C->CountersSectionStart = CountersSection->getAddress();
49 C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize();
50 C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost;
51 return Expected<std::unique_ptr<Context>>(std::move(C));
52}
53
56 auto DsymObjectsOrErr =
58 if (auto Err = DsymObjectsOrErr.takeError())
59 return std::move(Err);
60 if (!DsymObjectsOrErr->empty()) {
61 // TODO: Enable profile correlation when there are multiple objects in a
62 // dSYM bundle.
63 if (DsymObjectsOrErr->size() > 1)
64 return make_error<InstrProfError>(
66 "using multiple objects is not yet supported");
67 DebugInfoFilename = *DsymObjectsOrErr->begin();
68 }
69 auto BufferOrErr =
70 errorOrToExpected(MemoryBuffer::getFile(DebugInfoFilename));
71 if (auto Err = BufferOrErr.takeError())
72 return std::move(Err);
73
74 return get(std::move(*BufferOrErr));
75}
76
78InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer) {
79 auto BinOrErr = object::createBinary(*Buffer);
80 if (auto Err = BinOrErr.takeError())
81 return std::move(Err);
82
83 if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
84 auto CtxOrErr = Context::get(std::move(Buffer), *Obj);
85 if (auto Err = CtxOrErr.takeError())
86 return std::move(Err);
87 auto T = Obj->makeTriple();
88 if (T.isArch64Bit())
89 return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj);
90 if (T.isArch32Bit())
91 return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj);
92 }
93 return make_error<InstrProfError>(
95}
96
97std::optional<size_t> InstrProfCorrelator::getDataSize() const {
98 if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint32_t>>(this)) {
99 return C->getDataSize();
100 } else if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint64_t>>(this)) {
101 return C->getDataSize();
102 }
103 return {};
104}
105
106namespace llvm {
107
108template <>
110 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
112 std::move(Ctx)) {}
113template <>
115 std::unique_ptr<InstrProfCorrelator::Context> Ctx)
117 std::move(Ctx)) {}
118template <>
120 return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
121}
122template <>
124 return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
125}
126
127} // end namespace llvm
128
129template <class IntPtrT>
132 std::unique_ptr<InstrProfCorrelator::Context> Ctx,
133 const object::ObjectFile &Obj) {
134 if (Obj.isELF() || Obj.isMachO()) {
135 auto DICtx = DWARFContext::create(Obj);
136 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(std::move(DICtx),
137 std::move(Ctx));
138 }
139 return make_error<InstrProfError>(
140 instrprof_error::unable_to_correlate_profile,
141 "unsupported debug info format (only DWARF is supported)");
142}
143
144template <class IntPtrT>
146 assert(Data.empty() && Names.empty() && NamesVec.empty());
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");
152 auto Result =
153 collectPGOFuncNameStrings(NamesVec, /*doCompression=*/false, Names);
154 CounterOffsets.clear();
155 NamesVec.clear();
156 return Result;
157}
158
159template <> struct yaml::MappingTraits<InstrProfCorrelator::CorrelationData> {
160 static void mapping(yaml::IO &io,
162 io.mapRequired("Probes", Data.Probes);
163 }
164};
165
166template <> struct yaml::MappingTraits<InstrProfCorrelator::Probe> {
167 static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P) {
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);
175 }
176};
177
178template <> struct yaml::SequenceElementTraits<InstrProfCorrelator::Probe> {
179 static const bool flow = false;
180};
181
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);
191 YamlOS << Data;
192 return Error::success();
193}
194
195template <class IntPtrT>
197 uint64_t CFGHash,
198 IntPtrT CounterOffset,
199 IntPtrT FunctionPtr,
200 uint32_t NumCounters) {
201 // Check if a probe was already added for this counter offset.
202 if (!CounterOffsets.insert(CounterOffset).second)
203 return;
204 Data.push_back({
205 maybeSwap<uint64_t>(IndexedInstrProf::ComputeHash(FunctionName)),
206 maybeSwap<uint64_t>(CFGHash),
207 // In this mode, CounterPtr actually stores the section relative address
208 // of the counter.
209 maybeSwap<IntPtrT>(CounterOffset),
210 maybeSwap<IntPtrT>(FunctionPtr),
211 // TODO: Value profiling is not yet supported.
212 /*ValuesPtr=*/maybeSwap<IntPtrT>(0),
213 maybeSwap<uint32_t>(NumCounters),
214 /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
215 });
216 NamesVec.push_back(FunctionName.str());
217}
218
219template <class IntPtrT>
220std::optional<uint64_t>
222 auto Locations = Die.getLocations(dwarf::DW_AT_location);
223 if (!Locations) {
224 consumeError(Locations.takeError());
225 return {};
226 }
227 auto &DU = *Die.getDwarfUnit();
228 auto AddressSize = DU.getAddressByteSize();
229 for (auto &Location : *Locations) {
230 DataExtractor Data(Location.Expr, DICtx->isLittleEndian(), AddressSize);
231 DWARFExpression Expr(Data, AddressSize);
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) {
236 uint64_t Index = Op.getRawOperand(0);
237 if (auto SA = DU.getAddrOffsetSectionItem(Index))
238 return SA->Address;
239 }
240 }
241 }
242 return {};
243}
244
245template <class IntPtrT>
247 const auto &ParentDie = Die.getParent();
248 if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL())
249 return false;
250 if (Die.getTag() != dwarf::DW_TAG_variable)
251 return false;
252 if (!ParentDie.isSubprogramDIE())
253 return false;
254 if (!Die.hasChildren())
255 return false;
256 if (const char *Name = Die.getName(DINameKind::ShortName))
258 return false;
259}
260
261template <class IntPtrT>
264 auto maybeAddProbe = [&](DWARFDie Die) {
265 if (!isDIEOfProbe(Die))
266 return;
267 std::optional<const char *> FunctionName;
268 std::optional<uint64_t> CFGHash;
269 std::optional<uint64_t> CounterPtr = getLocation(Die);
270 auto FnDie = Die.getParent();
271 auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc));
272 std::optional<uint64_t> NumCounters;
273 for (const DWARFDie &Child : Die.children()) {
274 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
275 continue;
276 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
277 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
278 if (!AnnotationFormName || !AnnotationFormValue)
279 continue;
280 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
281 if (auto Err = AnnotationNameOrErr.takeError()) {
282 consumeError(std::move(Err));
283 continue;
284 }
285 StringRef AnnotationName = *AnnotationNameOrErr;
286 if (AnnotationName.compare(
288 if (auto EC =
289 AnnotationFormValue->getAsCString().moveInto(FunctionName))
290 consumeError(std::move(EC));
291 } else if (AnnotationName.compare(
293 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
294 } else if (AnnotationName.compare(
296 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
297 }
298 }
299 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
300 LLVM_DEBUG(dbgs() << "Incomplete DIE for probe\n\tFunctionName: "
301 << FunctionName << "\n\tCFGHash: " << CFGHash
302 << "\n\tCounterPtr: " << CounterPtr
303 << "\n\tNumCounters: " << NumCounters);
304 LLVM_DEBUG(Die.dump(dbgs()));
305 return;
306 }
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"
313 << Twine::utohexstr(CountersStart) << ", 0x"
314 << Twine::utohexstr(CountersEnd) << ")\n\tActual: 0x"
315 << Twine::utohexstr(*CounterPtr));
316 LLVM_DEBUG(Die.dump(dbgs()));
317 return;
318 }
319 if (!FunctionPtr) {
320 LLVM_DEBUG(dbgs() << "Could not find address of " << *FunctionName
321 << "\n");
322 LLVM_DEBUG(Die.dump(dbgs()));
323 }
324 IntPtrT CounterOffset = *CounterPtr - CountersStart;
325 if (Data) {
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);
340 } else {
341 this->addProbe(*FunctionName, *CFGHash, CounterOffset,
342 FunctionPtr.value_or(0), *NumCounters);
343 }
344 };
345 for (auto &CU : DICtx->normal_units())
346 for (const auto &Entry : CU->dies())
347 maybeAddProbe(DWARFDie(CU.get(), &Entry));
348 for (auto &CU : DICtx->dwo_units())
349 for (const auto &Entry : CU->dies())
350 maybeAddProbe(DWARFDie(CU.get(), &Entry));
351}
#define LLVM_DEBUG(X)
Definition: Debug.h:101
std::string Name
Expected< object::SectionRef > getCountersSection(const object::ObjectFile &Obj)
Get the __llvm_prf_cnts section.
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static MemoryLocation getLocation(Instruction *I)
raw_pwrite_stream & OS
@ Names
Definition: TextStubV5.cpp:106
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.
Definition: DWARFDie.h:42
iterator_range< iterator > children() const
Definition: DWARFDie.h:395
DWARFDie getParent() const
Get the parent of this DIE object.
Definition: DWARFDie.cpp:622
DWARFUnit * getDwarfUnit() const
Definition: DWARFDie.h:53
bool hasChildren() const
Definition: DWARFDie.h:78
const char * getName(DINameKind Kind) const
Return the DIE name resolving DW_AT_specification or DW_AT_abstract_origin references if necessary.
Definition: DWARFDie.cpp:442
dwarf::Tag getTag() const
Definition: DWARFDie.h:71
Expected< DWARFLocationExpressionsVector > getLocations(dwarf::Attribute Attr) const
Definition: DWARFDie.cpp:406
bool isNULL() const
Returns true for a valid DIE that terminates a sibling chain.
Definition: DWARFDie.h:84
bool isValid() const
Definition: DWARFDie.h:50
void dump(raw_ostream &OS, unsigned indent=0, DIDumpOptions DumpOpts=DIDumpOptions()) const
Dump the DIE and all of its attributes to the supplied stream.
Definition: DWARFDie.cpp:562
uint8_t getAddressByteSize() const
Definition: DWARFUnit.h:319
DwarfInstrProfCorrelator - A child of InstrProfCorrelatorImpl that takes DWARF debug info as input to...
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
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.
Definition: StringRef.h:50
std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:222
iterator begin() const
Definition: StringRef.h:111
bool startswith(StringRef Prefix) const
Definition: StringRef.h:261
int compare(StringRef RHS) const
compare - Compare two strings; the result is negative, zero, or positive if this string is lexicograp...
Definition: StringRef.h:177
static Twine utohexstr(const uint64_t &Val)
Definition: Twine.h:404
bool isLittleEndian() const
Definition: Binary.h:155
bool isMachO() const
Definition: Binary.h:127
bool isELF() const
Definition: Binary.h:123
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.
Definition: ObjectFile.h:228
section_iterator_range sections() const
Definition: ObjectFile.h:327
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
uint64_t ComputeHash(StringRef K)
Definition: InstrProf.h:1077
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.
Definition: Binary.cpp:45
static const bool IsLittleEndianHost
Definition: SwapByteOrder.h:70
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition: Casting.h:649
StringRef getInstrProfCountersVarPrefix()
Return the name prefix of profile counter variables.
Definition: InstrProf.h:96
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
Definition: Error.h:1186
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1946
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...
Definition: InstrProf.cpp:442
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1043
Definition: BitVector.h:858
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)