LLVM 23.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 "llvm/Support/Format.h"
21#include <optional>
22
23#define DEBUG_TYPE "correlator"
24
25using namespace llvm;
26
27/// Get profile section.
30 // On COFF, the getInstrProfSectionName returns the section names may followed
31 // by "$M". The linker removes the dollar and everything after it in the final
32 // binary. Do the same to match.
33 Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat();
34 auto StripSuffix = [ObjFormat](StringRef N) {
35 return ObjFormat == Triple::COFF ? N.split('$').first : N;
36 };
37 std::string ExpectedSectionName =
38 getInstrProfSectionName(IPSK, ObjFormat,
39 /*AddSegmentInfo=*/false);
40 ExpectedSectionName = StripSuffix(ExpectedSectionName);
41 for (auto &Section : Obj.sections()) {
42 if (auto SectionName = Section.getName())
43 if (*SectionName == ExpectedSectionName)
44 return Section;
45 }
48 "could not find section (" + Twine(ExpectedSectionName) + ")");
49}
50
51const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
52const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash";
53const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
54const char *InstrProfCorrelator::NumBitmapBitsAttributeName = "Num BitmapBits";
55
57InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
59 ProfCorrelatorKind FileKind) {
60 auto C = std::make_unique<Context>();
61 auto CountersSection = getInstrProfSection(Obj, IPSK_cnts);
62 if (auto Err = CountersSection.takeError())
63 return std::move(Err);
64 Triple::ObjectFormatType ObjFormat = Obj.getTripleObjectFormat();
65 if (FileKind == InstrProfCorrelator::BINARY) {
66 auto DataSection = getInstrProfSection(Obj, IPSK_covdata);
67 if (auto Err = DataSection.takeError())
68 return std::move(Err);
69 auto DataOrErr = DataSection->getContents();
70 if (!DataOrErr)
71 return DataOrErr.takeError();
72 auto NameSection = getInstrProfSection(Obj, IPSK_covname);
73 if (auto Err = NameSection.takeError())
74 return std::move(Err);
75 auto NameOrErr = NameSection->getContents();
76 if (!NameOrErr)
77 return NameOrErr.takeError();
78 C->DataStart = DataOrErr->data();
79 C->DataEnd = DataOrErr->data() + DataOrErr->size();
80 C->NameStart = NameOrErr->data();
81 C->NameSize = NameOrErr->size();
82
83 if (ObjFormat == Triple::MachO) {
84 std::string FullSectionName =
85 getInstrProfSectionName(IPSK_covdata, ObjFormat);
86 SmallVector<StringRef, 3> SegmentAndSection;
87 StringRef(FullSectionName).split(SegmentAndSection, ',', 2);
88 auto *MachO = static_cast<object::MachOObjectFile *>(&Obj);
89 Error Err = Error::success();
90 for (const object::MachOChainedFixupEntry &Entry :
91 MachO->fixupTable(Err)) {
92 if (Entry.isRebase() && Entry.segmentName() == SegmentAndSection[0] &&
93 Entry.sectionName() == SegmentAndSection[1]) {
94 C->MachOFixups[Entry.address() - DataSection->getAddress()] =
95 Entry.pointerValue();
96 }
97 }
98 if (Err)
99 return std::move(Err);
100 }
101 }
102 C->Buffer = std::move(Buffer);
103 C->CountersSectionStart = CountersSection->getAddress();
104 C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize();
105
106 auto BitmapSection = getInstrProfSection(Obj, IPSK_bitmap);
107 if (auto E = BitmapSection.takeError()) {
108 // It is not an error if NumBitmapBytes of each function is zero.
109 consumeError(std::move(E));
110 C->BitmapSectionStart = 0;
111 C->BitmapSectionEnd = 0;
112 } else {
113 C->BitmapSectionStart = BitmapSection->getAddress();
114 C->BitmapSectionEnd = C->BitmapSectionStart + BitmapSection->getSize();
115 }
116 // In COFF object file, there's a null byte at the beginning of both the
117 // counter and bitmap sections which doesn't exist in raw profile.
118 if (ObjFormat == Triple::COFF) {
119 ++C->CountersSectionStart;
120 if (C->BitmapSectionStart)
121 ++C->BitmapSectionStart;
122 }
123
124 C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost;
125 return Expected<std::unique_ptr<Context>>(std::move(C));
126}
127
130 const object::BuildIDFetcher *BIDFetcher,
131 const ArrayRef<object::BuildID> BIs) {
132 // Might be overwritten from BuildIDFetcher.
133 std::string EffectiveFilename = Filename.str();
134 if (BIDFetcher) {
135 if (BIs.empty())
138 "unsupported profile binary correlation when there is no build ID "
139 "in a profile");
140 if (BIs.size() > 1)
143 "unsupported profile binary correlation when there are multiple "
144 "build IDs in a profile");
145
146 Expected<std::string> Path = BIDFetcher->fetch(BIs.front());
147 if (!Path) {
148 // Propagate as InstrProf specific error type.
149 consumeError(Path.takeError());
152 "Missing build ID: " + llvm::toHex(BIs.front(),
153 /*LowerCase=*/true));
154 }
155 EffectiveFilename = *Path;
156 }
157
158 if (FileKind == DEBUG_INFO) {
159 auto DsymObjectsOrErr =
161 if (auto Err = DsymObjectsOrErr.takeError())
162 return std::move(Err);
163 if (!DsymObjectsOrErr->empty()) {
164 // TODO: Enable profile correlation when there are multiple objects in a
165 // dSYM bundle.
166 if (DsymObjectsOrErr->size() > 1)
169 "using multiple objects is not yet supported");
170 EffectiveFilename = *DsymObjectsOrErr->begin();
171 }
172 auto BufferOrErr =
173 errorOrToExpected(MemoryBuffer::getFile(EffectiveFilename));
174 if (auto Err = BufferOrErr.takeError())
175 return std::move(Err);
176
177 return get(std::move(*BufferOrErr), FileKind);
178 }
179 if (FileKind == BINARY) {
180 auto BufferOrErr =
181 errorOrToExpected(MemoryBuffer::getFile(EffectiveFilename));
182 if (auto Err = BufferOrErr.takeError())
183 return std::move(Err);
184
185 return get(std::move(*BufferOrErr), FileKind);
186 }
189 "unsupported correlation kind (only DWARF debug info and Binary format "
190 "(ELF/COFF) are supported)");
191}
192
194InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer,
195 ProfCorrelatorKind FileKind) {
196 auto BinOrErr = object::createBinary(*Buffer);
197 if (auto Err = BinOrErr.takeError())
198 return std::move(Err);
199
200 if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
201 auto CtxOrErr = Context::get(std::move(Buffer), *Obj, FileKind);
202 if (auto Err = CtxOrErr.takeError())
203 return std::move(Err);
204 auto T = Obj->makeTriple();
205 if (T.isArch64Bit())
206 return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj,
207 FileKind);
208 if (T.isArch32Bit())
209 return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj,
210 FileKind);
211 }
214}
215
216std::optional<size_t> InstrProfCorrelator::getDataSize() const {
218 return C->getDataSize();
220 return C->getDataSize();
221 return {};
222}
223
224namespace llvm {
225
226template <>
231template <>
236template <>
240template <>
244
245} // end namespace llvm
246
247template <class IntPtrT>
250 std::unique_ptr<InstrProfCorrelator::Context> Ctx,
251 const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) {
252 if (FileKind == DEBUG_INFO) {
253 if (Obj.isELF() || Obj.isMachO()) {
254 auto DICtx = DWARFContext::create(Obj);
255 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
256 std::move(DICtx), std::move(Ctx));
257 }
260 "unsupported debug info format (only DWARF is supported)");
261 }
262 if (Obj.isELF() || Obj.isCOFF() || Obj.isMachO())
263 return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx));
266 "unsupported binary format (only ELF, COFF, and Mach-O are supported)");
267}
268
269template <class IntPtrT>
271 assert(Data.empty() && Names.empty() && NamesVec.empty());
272 correlateProfileDataImpl(MaxWarnings);
273 if (this->Data.empty())
276 "could not find any profile data metadata in correlated file");
278 this->CounterOffsets.clear();
279 this->BitmapOffsets.clear();
280 this->NamesVec.clear();
281 return Result;
282}
283
284template <> struct yaml::MappingTraits<InstrProfCorrelator::CorrelationData> {
285 static void mapping(yaml::IO &io,
287 io.mapRequired("Probes", Data.Probes);
288 }
289};
290
291template <> struct yaml::MappingTraits<InstrProfCorrelator::Probe> {
293 io.mapRequired("Function Name", P.FunctionName);
294 io.mapOptional("Linkage Name", P.LinkageName);
295 io.mapRequired("CFG Hash", P.CFGHash);
296 io.mapRequired("Counter Offset", P.CounterOffset);
297 io.mapRequired("Num Counters", P.NumCounters);
298 io.mapRequired("Bitmap Offset", P.BitmapOffset);
299 io.mapRequired("Num BitmapBytes", P.NumBitmapBytes);
300 io.mapOptional("File", P.FilePath);
301 io.mapOptional("Line", P.LineNumber);
302 }
303};
304
306 static const bool flow = false;
307};
308
309template <class IntPtrT>
311 raw_ostream &OS) {
313 correlateProfileDataImpl(MaxWarnings, &Data);
314 if (Data.Probes.empty())
317 "could not find any profile data metadata in debug info");
318 yaml::Output YamlOS(OS);
319 YamlOS << Data;
320 return Error::success();
321}
322
323template <class IntPtrT>
325 uint64_t NameRef, uint64_t CFGHash, IntPtrT CounterOffset,
326 IntPtrT BitmapOffset, IntPtrT FunctionPtr, uint32_t NumCounters,
328 // Check if a probe was already added for this counter offset.
329 if (NumCounters && !CounterOffsets.insert(CounterOffset).second)
330 return;
331 // Check if a probe was already added for this bitmap offset.
332 if (NumBitmapBytes && !BitmapOffsets.insert(BitmapOffset).second)
333 return;
334 Data.push_back({
335 maybeSwap<uint64_t>(NameRef),
336 maybeSwap<uint64_t>(CFGHash),
337 // In this mode, CounterPtr actually stores the section relative address
338 // of the counter.
339 maybeSwap<IntPtrT>(CounterOffset),
340 /*UniformCounterPtr=*/maybeSwap<IntPtrT>(0),
341 maybeSwap<IntPtrT>(BitmapOffset),
342 maybeSwap<IntPtrT>(FunctionPtr),
343 // TODO: Value profiling is not yet supported.
344 /*ValuesPtr=*/maybeSwap<IntPtrT>(0),
345 maybeSwap<uint32_t>(NumCounters),
346 /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
347 /*OffloadDeviceWaveSize=*/maybeSwap<uint16_t>(0),
349 });
350}
351
352template <class IntPtrT>
353std::optional<uint64_t>
354DwarfInstrProfCorrelator<IntPtrT>::getLocation(const DWARFDie &Die) const {
355 auto Locations = Die.getLocations(dwarf::DW_AT_location);
356 if (!Locations) {
357 consumeError(Locations.takeError());
358 return {};
359 }
360 auto &DU = *Die.getDwarfUnit();
361 auto AddressSize = DU.getAddressByteSize();
362 for (auto &Location : *Locations) {
363 DataExtractor Data(Location.Expr, DICtx->isLittleEndian());
364 DWARFExpression Expr(Data, AddressSize);
365 for (auto &Op : Expr) {
366 if (Op.getCode() == dwarf::DW_OP_addr)
367 return Op.getRawOperand(0);
368 if (Op.getCode() == dwarf::DW_OP_addrx) {
369 uint64_t Index = Op.getRawOperand(0);
370 if (auto SA = DU.getAddrOffsetSectionItem(Index))
371 return SA->Address;
372 }
373 }
374 }
375 return {};
376}
377
378template <class IntPtrT>
379bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die,
380 StringRef Prefix) {
381 const auto &ParentDie = Die.getParent();
382 if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL())
383 return false;
384 if (Die.getTag() != dwarf::DW_TAG_variable)
385 return false;
386 if (!ParentDie.isSubprogramDIE())
387 return false;
388 if (!Die.hasChildren())
389 return false;
390 if (const char *Name = Die.getName(DINameKind::ShortName))
391 return StringRef(Name).starts_with(Prefix);
392 return false;
393}
394
395template <class IntPtrT>
396std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>
397DwarfInstrProfCorrelator<IntPtrT>::addCountersToDataProbe(
398 const DWARFDie &Die, const bool UnlimitedWarnings,
399 int &NumSuppressedWarnings) {
400 std::optional<const char *> FunctionName;
401 std::optional<uint64_t> CFGHash;
402 std::optional<uint64_t> CounterPtr = getLocation(Die);
403 auto FnDie = Die.getParent();
404 auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc));
405 std::optional<uint64_t> NumCounters;
406 for (const DWARFDie &Child : Die.children()) {
407 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
408 continue;
409 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
410 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
411 if (!AnnotationFormName || !AnnotationFormValue)
412 continue;
413 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
414 if (auto Err = AnnotationNameOrErr.takeError()) {
415 consumeError(std::move(Err));
416 continue;
417 }
418 StringRef AnnotationName = *AnnotationNameOrErr;
420 if (auto EC = AnnotationFormValue->getAsCString().moveInto(FunctionName))
421 consumeError(std::move(EC));
422 } else if (AnnotationName == InstrProfCorrelator::CFGHashAttributeName) {
423 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
424 } else if (AnnotationName ==
426 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
427 }
428 }
429 // If there is no function and no counter, assume it was dead-stripped
430 if (!FunctionPtr && !CounterPtr)
431 return std::nullopt;
432 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
433 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
434 WithColor::warning() << "Incomplete DIE for function " << FunctionName
435 << ": CFGHash=" << CFGHash
436 << " CounterPtr=" << CounterPtr
437 << " NumCounters=" << NumCounters << "\n";
438 LLVM_DEBUG(Die.dump(dbgs()));
439 }
440 return std::nullopt;
441 }
442 uint64_t CountersStart = this->Ctx->CountersSectionStart;
443 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
444 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
445 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
447 "CounterPtr out of range for function %s: Actual=0x%x "
448 "Expected=[0x%x, 0x%x)\n",
449 *FunctionName, *CounterPtr, CountersStart, CountersEnd);
450 LLVM_DEBUG(Die.dump(dbgs()));
451 }
452 return std::nullopt;
453 }
454 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
455 WithColor::warning() << format("Could not find address of function %s\n",
456 *FunctionName);
457 LLVM_DEBUG(Die.dump(dbgs()));
458 }
459 // In debug info correlation mode, the CounterPtr is an absolute address
460 // of the counter, but it's expected to be relative later when iterating
461 // Data.
462 IntPtrT CounterOffset = *CounterPtr - CountersStart;
464 P.FunctionName = *FunctionName;
465 if (const char *Name = FnDie.getName(DINameKind::LinkageName))
466 P.LinkageName = Name;
467 P.CFGHash = *CFGHash;
468 P.CounterOffset = CounterOffset;
469 P.NumCounters = *NumCounters;
470 auto FilePath = FnDie.getDeclFile(
472 if (!FilePath.empty())
473 P.FilePath = FilePath;
474 if (auto LineNumber = FnDie.getDeclLine())
475 P.LineNumber = LineNumber;
476
477 return std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>(
478 {P, FunctionPtr.value_or(0)});
479}
480
481template <class IntPtrT>
482std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>
483DwarfInstrProfCorrelator<IntPtrT>::addBitmapToDataProbe(
484 const DWARFDie &Die, const bool UnlimitedWarnings,
485 int &NumSuppressedWarnings) {
486 std::optional<const char *> FunctionName;
487 std::optional<uint64_t> BitmapPtr = getLocation(Die);
489 for (const DWARFDie &Child : Die.children()) {
490 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
491 continue;
492 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
493 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
494 if (!AnnotationFormName || !AnnotationFormValue)
495 continue;
496 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
497 if (auto Err = AnnotationNameOrErr.takeError()) {
498 consumeError(std::move(Err));
499 continue;
500 }
501 StringRef AnnotationName = *AnnotationNameOrErr;
503 if (auto EC = AnnotationFormValue->getAsCString().moveInto(FunctionName))
504 consumeError(std::move(EC));
505 } else if (AnnotationName ==
507 std::optional<uint64_t> NumBitmapBits =
508 AnnotationFormValue->getAsUnsignedConstant();
509 NumBitmapBytes = alignTo(*NumBitmapBits, CHAR_BIT) / CHAR_BIT;
510 }
511 }
512 if (!FunctionName || !BitmapPtr || !NumBitmapBytes) {
513 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
514 WithColor::warning() << "Incomplete DIE for function " << FunctionName
515 << " BitmapPtr=" << BitmapPtr
516 << " NumBitmapBytes=" << NumBitmapBytes << "\n";
517 LLVM_DEBUG(Die.dump(dbgs()));
518 }
519 return std::nullopt;
520 }
521 uint64_t BitmapStart = this->Ctx->BitmapSectionStart;
522 uint64_t BitmapEnd = this->Ctx->BitmapSectionEnd;
523 if (!BitmapStart && !BitmapEnd && NumBitmapBytes) {
526 "could not find profile bitmap section in correlated file");
527 return std::nullopt;
528 }
529 if (*BitmapPtr < BitmapStart || (*BitmapPtr >= BitmapEnd && NumBitmapBytes)) {
530 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
532 "BitmapPtr out of range for function %s: Actual=0x%x "
533 "Expected=[0x%x, 0x%x)\n",
534 *FunctionName, *BitmapPtr, BitmapStart, BitmapEnd);
535 LLVM_DEBUG(Die.dump(dbgs()));
536 }
537 return std::nullopt;
538 }
539 // In debug info correlation mode, the BitmapPtr is an absolute address of
540 // the bitmap, but it's expected to be relative later when iterating Data.
541 IntPtrT BitmapOffset = *BitmapPtr - BitmapStart;
543 P.FunctionName = *FunctionName;
544 P.BitmapOffset = BitmapOffset;
545 P.NumBitmapBytes = NumBitmapBytes;
546
547 return std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>({P, 0});
548}
549
550template <class IntPtrT>
551void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
552 int MaxWarnings, InstrProfCorrelator::CorrelationData *Data) {
553 // Map from FunctionName string to (Probe, FunctionPtr) pair.
554 // We use it to collect data from all functions Counter and Bitmap DIEs.
557 Probes;
558 bool UnlimitedWarnings = (MaxWarnings == 0);
559 // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
560 int NumSuppressedWarnings = -MaxWarnings;
561
562 auto MaybeAddProbe = [&](DWARFDie Die) {
563 std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>> ProbeData;
564 if (isDIEOfProbe(Die, getInstrProfCountersVarPrefix()))
565 ProbeData =
566 addCountersToDataProbe(Die, UnlimitedWarnings, NumSuppressedWarnings);
567 else if (isDIEOfProbe(Die, getInstrProfBitmapVarPrefix()))
568 ProbeData =
569 addBitmapToDataProbe(Die, UnlimitedWarnings, NumSuppressedWarnings);
570 if (!ProbeData)
571 return;
572 auto [Probe, FunctionPtr] = *ProbeData;
573
574 auto [It, Inserted] =
575 Probes.try_emplace(Probe.FunctionName, Probe, FunctionPtr);
576 if (!Inserted) {
577 auto &P = It->second.first;
578 if (isDIEOfProbe(Die, getInstrProfCountersVarPrefix())) {
579 P.LinkageName = Probe.LinkageName;
580 P.CFGHash = Probe.CFGHash;
581 P.CounterOffset = Probe.CounterOffset;
582 P.NumCounters = Probe.NumCounters;
583 P.FilePath = Probe.FilePath;
584 P.LineNumber = Probe.LineNumber;
585 } else {
586 P.BitmapOffset = Probe.BitmapOffset;
587 P.NumBitmapBytes = Probe.NumBitmapBytes;
588 }
589 }
590 };
591 for (auto &CU : DICtx->normal_units())
592 for (const auto &Entry : CU->dies())
593 MaybeAddProbe(DWARFDie(CU.get(), &Entry));
594 for (auto &CU : DICtx->dwo_units())
595 for (const auto &Entry : CU->dies())
596 MaybeAddProbe(DWARFDie(CU.get(), &Entry));
597
598 for (const auto &[FunctionName, ProbeData] : Probes) {
599 const auto &[Probe, FunctionPtr] = ProbeData;
600 if (Data)
601 Data->Probes.push_back(Probe);
602 else {
603 this->NamesVec.push_back(FunctionName);
604 uint64_t NameRef = IndexedInstrProf::ComputeHash(FunctionName);
605 this->addDataProbe(NameRef, Probe.CFGHash, Probe.CounterOffset,
606 Probe.BitmapOffset, FunctionPtr, Probe.NumCounters,
607 Probe.NumBitmapBytes);
608 }
609 }
610 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
611 WithColor::warning() << format("Suppressed %d additional warnings\n",
612 NumSuppressedWarnings);
613}
614
615template <class IntPtrT>
616Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
617 if (this->NamesVec.empty()) {
620 "could not find any profile name metadata in debug info");
621 }
622 auto Result =
623 collectGlobalObjectNameStrings(this->NamesVec,
624 /*doCompression=*/false, this->Names);
625 return Result;
626}
627
628template <class IntPtrT>
629void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
630 int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) {
631 using RawProfData = RawInstrProf::ProfileData<IntPtrT>;
632 bool UnlimitedWarnings = (MaxWarnings == 0);
633 // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
634 int NumSuppressedWarnings = -MaxWarnings;
635
636 const RawProfData *DataStart = (const RawProfData *)this->Ctx->DataStart;
637 const RawProfData *DataEnd = (const RawProfData *)this->Ctx->DataEnd;
638 // We need to use < here because the last data record may have no padding.
639 for (const RawProfData *I = DataStart; I < DataEnd; ++I) {
640 uint64_t CounterPtr = this->template maybeSwap<IntPtrT>(I->CounterPtr);
641 uint64_t CountersStart = this->Ctx->CountersSectionStart;
642 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
643
644 uint64_t BitmapPtr = this->template maybeSwap<IntPtrT>(I->BitmapPtr);
645 uint64_t BitmapStart = this->Ctx->BitmapSectionStart;
646 uint64_t BitmapEnd = this->Ctx->BitmapSectionEnd;
647 if (!BitmapStart && !BitmapEnd && I->NumBitmapBytes) {
650 "could not find profile bitmap section in correlated file");
651 return;
652 }
653 if (!this->Ctx->MachOFixups.empty()) {
654 auto GetPtrByOffset = [&](uint64_t Offset, uint64_t &Ptr) {
655 auto It = this->Ctx->MachOFixups.find(Offset);
656 if (It != this->Ctx->MachOFixups.end()) {
657 Ptr = It->second;
658 } else if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
660 "Mach-O fixup not found for covdata offset 0x%llx\n", Offset);
661 }
662 };
663 uint64_t CounterOffset = (uint64_t)&I->CounterPtr - (uint64_t)DataStart;
664 uint64_t BitmapOffset = (uint64_t)&I->BitmapPtr - (uint64_t)DataStart;
665 GetPtrByOffset(CounterOffset, CounterPtr);
666 GetPtrByOffset(BitmapOffset, BitmapPtr);
667 }
668 if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
669 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
671 << format("CounterPtr out of range for function: Actual=0x%x "
672 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
673 CounterPtr, CountersStart, CountersEnd,
674 (I - DataStart) * sizeof(RawProfData));
675 }
676 }
677 if (I->NumBitmapBytes &&
678 (BitmapPtr < BitmapStart || BitmapPtr >= BitmapEnd)) {
679 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
681 << format("BitmapPtr out of range for function: Actual=0x%x "
682 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
683 BitmapPtr, BitmapStart, BitmapEnd,
684 (I - DataStart) * sizeof(RawProfData));
685 }
686 }
687 // In binary correlation mode, CounterPtr and BitmapPtr are absolute
688 // addresses, but they're expected to be relative later when iterating Data.
689 IntPtrT CounterOffset = CounterPtr - CountersStart;
690 IntPtrT BitmapOffset = BitmapPtr - BitmapStart;
691 this->addDataProbe(I->NameRef, I->FuncHash, CounterOffset, BitmapOffset,
692 I->FunctionPointer, I->NumCounters, I->NumBitmapBytes);
693 }
694}
695
696template <class IntPtrT>
697Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
698 if (this->Ctx->NameSize == 0) {
701 "could not find any profile data metadata in object file");
702 }
703 this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
704 return Error::success();
705}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static Expected< object::SectionRef > getInstrProfSection(const object::ObjectFile &Obj, InstrProfSectKind IPSK)
Get profile section.
#define I(x, y, z)
Definition MD5.cpp:57
#define T
static constexpr StringLiteral Filename
#define P(N)
static MemoryLocation getLocation(Instruction *I)
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
const T & front() const
Get the first element.
Definition ArrayRef.h:144
size_t size() const
Get the array size.
Definition ArrayRef.h:141
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
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.
Definition DWARFDie.h:43
iterator_range< iterator > children() const
Definition DWARFDie.h:407
LLVM_ABI DWARFDie getParent() const
Get the parent of this DIE object.
Definition DWARFDie.cpp:736
DWARFUnit * getDwarfUnit() const
Definition DWARFDie.h:55
bool hasChildren() const
Definition DWARFDie.h:80
LLVM_ABI 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:542
dwarf::Tag getTag() const
Definition DWARFDie.h:73
LLVM_ABI Expected< DWARFLocationExpressionsVector > getLocations(dwarf::Attribute Attr) const
Definition DWARFDie.cpp:506
bool isNULL() const
Returns true for a valid DIE that terminates a sibling chain.
Definition DWARFDie.h:86
bool isValid() const
Definition DWARFDie.h:52
LLVM_ABI 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:674
uint8_t getAddressByteSize() const
Definition DWARFUnit.h:333
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
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)
virtual Error correlateProfileNameImpl()=0
virtual void correlateProfileDataImpl(int MaxWarnings, InstrProfCorrelator::CorrelationData *Data=nullptr)=0
std::vector< RawInstrProf::ProfileData< IntPtrT > > Data
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 BitmapOffset, IntPtrT FunctionPtr, uint32_t NumCounters, uint32_t NumBitmapBytes)
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 LLVM_ABI const char * FunctionNameAttributeName
static LLVM_ABI const char * CFGHashAttributeName
InstrProfCorrelator(InstrProfCorrelatorKind K, std::unique_ptr< Context > Ctx)
std::vector< std::string > NamesVec
static LLVM_ABI const char * NumCountersAttributeName
ProfCorrelatorKind
Indicate if we should use the debug info or profile metadata sections to correlate.
const std::unique_ptr< Context > Ctx
LLVM_ABI std::optional< size_t > getDataSize() const
Return the number of ProfileData elements.
static LLVM_ABI llvm::Expected< std::unique_ptr< InstrProfCorrelator > > get(StringRef Filename, ProfCorrelatorKind FileKind, const object::BuildIDFetcher *BIDFetcher=nullptr, const ArrayRef< llvm::object::BuildID > BIs={})
static LLVM_ABI const char * NumBitmapBitsAttributeName
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
std::pair< iterator, bool > try_emplace(const KeyT &Key, Ts &&...Args)
Definition MapVector.h:118
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,...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:128
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:736
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition StringRef.h:258
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
Definition WithColor.cpp:86
BuildIDFetcher searches local cache directories for debug info.
Definition BuildID.h:41
virtual Expected< std::string > fetch(BuildIDRef BuildID) const
Returns the path to the debug file with the given build ID.
Definition BuildID.cpp:83
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:231
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
void mapOptional(StringRef Key, T &Val)
Definition YAMLTraits.h:800
void mapRequired(StringRef Key, T &Val)
Definition YAMLTraits.h:790
The Output class is used to generate a yaml document from in-memory structs and vectors.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
uint64_t ComputeHash(StringRef K)
Definition InstrProf.h:1239
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
LLVM_ABI 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
constexpr bool IsLittleEndianHost
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:573
RelativeUniformCounterPtr ValuesPtrExpr NumBitmapBytes
Definition InstrProf.h:101
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
StringRef getInstrProfBitmapVarPrefix()
Return the name prefix of profile bitmap variables.
Definition InstrProf.h:143
LLVM_ABI std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
InstrProfSectKind
Definition InstrProf.h:91
StringRef getInstrProfCountersVarPrefix()
Return the name prefix of profile counter variables.
Definition InstrProf.h:140
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:144
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr CountersStart
Definition InstrProf.h:167
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
Definition Format.h:94
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
DWARFExpression::Operation Op
Expected< T > errorOrToExpected(ErrorOr< T > &&EO)
Convert an ErrorOr<T> to an Expected<T>.
Definition Error.h:1261
LLVM_ABI 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,...
void toHex(ArrayRef< uint8_t > Input, bool LowerCase, SmallVectorImpl< char > &Output)
Convert buffer Input to its hexadecimal representation. The returned string is double the size of Inp...
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:1917
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr DataStart
Definition InstrProf.h:173
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:860
#define N
std::unique_ptr< MemoryBuffer > Buffer
static LLVM_ABI llvm::Expected< std::unique_ptr< Context > > get(std::unique_ptr< MemoryBuffer > Buffer, object::ObjectFile &Obj, ProfCorrelatorKind FileKind)
This class should be specialized by any type that needs to be converted to/from a YAML mapping.
Definition YAMLTraits.h:63
This class should be specialized by any type for which vectors of that type need to be converted to/f...
Definition YAMLTraits.h:258
static void mapping(yaml::IO &io, InstrProfCorrelator::CorrelationData &Data)
static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P)