LLVM 24.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 == ProfCorrelatorKind::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 == ProfCorrelatorKind::DebugInfo) {
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 auto BufferOrErr =
180 errorOrToExpected(MemoryBuffer::getFile(EffectiveFilename));
181 if (auto Err = BufferOrErr.takeError())
182 return std::move(Err);
183 return get(std::move(*BufferOrErr), FileKind);
184}
185
187InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer,
188 ProfCorrelatorKind FileKind) {
189 auto BinOrErr = object::createBinary(*Buffer);
190 if (auto Err = BinOrErr.takeError())
191 return std::move(Err);
192
193 if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
194 auto CtxOrErr = Context::get(std::move(Buffer), *Obj, FileKind);
195 if (auto Err = CtxOrErr.takeError())
196 return std::move(Err);
197 auto T = Obj->makeTriple();
198 if (T.isArch64Bit())
199 return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj,
200 FileKind);
201 if (T.isArch32Bit())
202 return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj,
203 FileKind);
204 }
207}
208
209std::optional<size_t> InstrProfCorrelator::getDataSize() const {
211 return C->getDataSize();
213 return C->getDataSize();
214 return {};
215}
216
217namespace llvm {
218
219template <>
224template <>
229template <>
233template <>
237
238} // end namespace llvm
239
240template <class IntPtrT>
243 std::unique_ptr<InstrProfCorrelator::Context> Ctx,
244 const object::ObjectFile &Obj, ProfCorrelatorKind FileKind) {
245 if (FileKind == ProfCorrelatorKind::DebugInfo) {
246 if (Obj.isELF() || Obj.isMachO()) {
247 auto DICtx = DWARFContext::create(Obj);
248 return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(
249 std::move(DICtx), std::move(Ctx));
250 }
253 "unsupported debug info format (only DWARF is supported)");
254 }
255 if (Obj.isELF() || Obj.isCOFF() || Obj.isMachO())
256 return std::make_unique<BinaryInstrProfCorrelator<IntPtrT>>(std::move(Ctx));
259 "unsupported binary format (only ELF, COFF, and Mach-O are supported)");
260}
261
262template <class IntPtrT>
264 assert(Data.empty() && Names.empty() && NamesVec.empty());
265 correlateProfileDataImpl(MaxWarnings);
266 if (this->Data.empty())
269 "could not find any profile data metadata in correlated file");
271 this->CounterOffsets.clear();
272 this->BitmapOffsets.clear();
273 this->NamesVec.clear();
274 return Result;
275}
276
277template <> struct yaml::MappingTraits<InstrProfCorrelator::CorrelationData> {
278 static void mapping(yaml::IO &io,
280 io.mapRequired("Probes", Data.Probes);
281 }
282};
283
284template <> struct yaml::MappingTraits<InstrProfCorrelator::Probe> {
286 io.mapRequired("Function Name", P.FunctionName);
287 io.mapOptional("Linkage Name", P.LinkageName);
288 io.mapRequired("CFG Hash", P.CFGHash);
289 io.mapRequired("Counter Offset", P.CounterOffset);
290 io.mapRequired("Num Counters", P.NumCounters);
291 io.mapRequired("Bitmap Offset", P.BitmapOffset);
292 io.mapRequired("Num BitmapBytes", P.NumBitmapBytes);
293 io.mapOptional("File", P.FilePath);
294 io.mapOptional("Line", P.LineNumber);
295 }
296};
297
299 static const bool flow = false;
300};
301
302template <class IntPtrT>
304 raw_ostream &OS) {
306 correlateProfileDataImpl(MaxWarnings, &Data);
307 if (Data.Probes.empty())
310 "could not find any profile data metadata in debug info");
311 yaml::Output YamlOS(OS);
312 YamlOS << Data;
313 return Error::success();
314}
315
316template <class IntPtrT>
318 uint64_t NameRef, uint64_t CFGHash, IntPtrT CounterOffset,
319 IntPtrT BitmapOffset, IntPtrT FunctionPtr, uint32_t NumCounters,
321 // Check if a probe was already added for this counter offset.
322 if (NumCounters && !CounterOffsets.insert(CounterOffset).second)
323 return;
324 // Check if a probe was already added for this bitmap offset.
325 if (NumBitmapBytes && !BitmapOffsets.insert(BitmapOffset).second)
326 return;
327 Data.push_back({
328 maybeSwap<uint64_t>(NameRef),
329 maybeSwap<uint64_t>(CFGHash),
330 // In this mode, CounterPtr actually stores the section relative address
331 // of the counter.
332 maybeSwap<IntPtrT>(CounterOffset),
333 /*UniformCounterPtr=*/maybeSwap<IntPtrT>(0),
334 maybeSwap<IntPtrT>(BitmapOffset),
335 maybeSwap<IntPtrT>(FunctionPtr),
336 // TODO: Value profiling is not yet supported.
337 /*ValuesPtr=*/maybeSwap<IntPtrT>(0),
338 maybeSwap<uint32_t>(NumCounters),
339 /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
340 /*OffloadDeviceWaveSize=*/maybeSwap<uint16_t>(0),
342 });
343}
344
345template <class IntPtrT>
346std::optional<uint64_t>
347DwarfInstrProfCorrelator<IntPtrT>::getLocation(const DWARFDie &Die) const {
348 auto Locations = Die.getLocations(dwarf::DW_AT_location);
349 if (!Locations) {
350 consumeError(Locations.takeError());
351 return {};
352 }
353 auto &DU = *Die.getDwarfUnit();
354 auto AddressSize = DU.getAddressByteSize();
355 for (auto &Location : *Locations) {
356 DataExtractor Data(Location.Expr, DICtx->isLittleEndian());
357 DWARFExpression Expr(Data, AddressSize);
358 for (auto &Op : Expr) {
359 if (Op.getCode() == dwarf::DW_OP_addr)
360 return Op.getRawOperand(0);
361 if (Op.getCode() == dwarf::DW_OP_addrx) {
362 uint64_t Index = Op.getRawOperand(0);
363 if (auto SA = DU.getAddrOffsetSectionItem(Index))
364 return SA->Address;
365 }
366 }
367 }
368 return {};
369}
370
371template <class IntPtrT>
372bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die,
373 StringRef Prefix) {
374 const auto &ParentDie = Die.getParent();
375 if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL())
376 return false;
377 if (Die.getTag() != dwarf::DW_TAG_variable)
378 return false;
379 if (!ParentDie.isSubprogramDIE())
380 return false;
381 if (!Die.hasChildren())
382 return false;
383 if (const char *Name = Die.getName(DINameKind::ShortName))
384 return StringRef(Name).starts_with(Prefix);
385 return false;
386}
387
388template <class IntPtrT>
389std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>
390DwarfInstrProfCorrelator<IntPtrT>::addCountersToDataProbe(
391 const DWARFDie &Die, const bool UnlimitedWarnings,
392 int &NumSuppressedWarnings) {
393 std::optional<const char *> FunctionName;
394 std::optional<uint64_t> CFGHash;
395 std::optional<uint64_t> CounterPtr = getLocation(Die);
396 auto FnDie = Die.getParent();
397 auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc));
398 std::optional<uint64_t> NumCounters;
399 for (const DWARFDie &Child : Die.children()) {
400 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
401 continue;
402 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
403 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
404 if (!AnnotationFormName || !AnnotationFormValue)
405 continue;
406 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
407 if (auto Err = AnnotationNameOrErr.takeError()) {
408 consumeError(std::move(Err));
409 continue;
410 }
411 StringRef AnnotationName = *AnnotationNameOrErr;
413 if (auto EC = AnnotationFormValue->getAsCString().moveInto(FunctionName))
414 consumeError(std::move(EC));
415 } else if (AnnotationName == InstrProfCorrelator::CFGHashAttributeName) {
416 CFGHash = AnnotationFormValue->getAsUnsignedConstant();
417 } else if (AnnotationName ==
419 NumCounters = AnnotationFormValue->getAsUnsignedConstant();
420 }
421 }
422 // If there is no function and no counter, assume it was dead-stripped
423 if (!FunctionPtr && !CounterPtr)
424 return std::nullopt;
425 if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
426 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
427 WithColor::warning() << "Incomplete DIE for function " << FunctionName
428 << ": CFGHash=" << CFGHash
429 << " CounterPtr=" << CounterPtr
430 << " NumCounters=" << NumCounters << "\n";
431 LLVM_DEBUG(Die.dump(dbgs()));
432 }
433 return std::nullopt;
434 }
435 uint64_t CountersStart = this->Ctx->CountersSectionStart;
436 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
437 if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
438 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
440 "CounterPtr out of range for function %s: Actual=0x%x "
441 "Expected=[0x%x, 0x%x)\n",
442 *FunctionName, *CounterPtr, CountersStart, CountersEnd);
443 LLVM_DEBUG(Die.dump(dbgs()));
444 }
445 return std::nullopt;
446 }
447 if (!FunctionPtr && (UnlimitedWarnings || ++NumSuppressedWarnings < 1)) {
448 WithColor::warning() << format("Could not find address of function %s\n",
449 *FunctionName);
450 LLVM_DEBUG(Die.dump(dbgs()));
451 }
452 // In debug info correlation mode, the CounterPtr is an absolute address
453 // of the counter, but it's expected to be relative later when iterating
454 // Data.
455 IntPtrT CounterOffset = *CounterPtr - CountersStart;
457 P.FunctionName = *FunctionName;
458 if (const char *Name = FnDie.getName(DINameKind::LinkageName))
459 P.LinkageName = Name;
460 P.CFGHash = *CFGHash;
461 P.CounterOffset = CounterOffset;
462 P.NumCounters = *NumCounters;
463 auto FilePath = FnDie.getDeclFile(
465 if (!FilePath.empty())
466 P.FilePath = FilePath;
467 if (auto LineNumber = FnDie.getDeclLine())
468 P.LineNumber = LineNumber;
469
470 return std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>(
471 {P, FunctionPtr.value_or(0)});
472}
473
474template <class IntPtrT>
475std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>
476DwarfInstrProfCorrelator<IntPtrT>::addBitmapToDataProbe(
477 const DWARFDie &Die, const bool UnlimitedWarnings,
478 int &NumSuppressedWarnings) {
479 std::optional<const char *> FunctionName;
480 std::optional<uint64_t> BitmapPtr = getLocation(Die);
482 for (const DWARFDie &Child : Die.children()) {
483 if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
484 continue;
485 auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
486 auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
487 if (!AnnotationFormName || !AnnotationFormValue)
488 continue;
489 auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
490 if (auto Err = AnnotationNameOrErr.takeError()) {
491 consumeError(std::move(Err));
492 continue;
493 }
494 StringRef AnnotationName = *AnnotationNameOrErr;
496 if (auto EC = AnnotationFormValue->getAsCString().moveInto(FunctionName))
497 consumeError(std::move(EC));
498 } else if (AnnotationName ==
500 std::optional<uint64_t> NumBitmapBits =
501 AnnotationFormValue->getAsUnsignedConstant();
502 NumBitmapBytes = alignTo(*NumBitmapBits, CHAR_BIT) / CHAR_BIT;
503 }
504 }
505 if (!FunctionName || !BitmapPtr || !NumBitmapBytes) {
506 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
507 WithColor::warning() << "Incomplete DIE for function " << FunctionName
508 << " BitmapPtr=" << BitmapPtr
509 << " NumBitmapBytes=" << NumBitmapBytes << "\n";
510 LLVM_DEBUG(Die.dump(dbgs()));
511 }
512 return std::nullopt;
513 }
514 uint64_t BitmapStart = this->Ctx->BitmapSectionStart;
515 uint64_t BitmapEnd = this->Ctx->BitmapSectionEnd;
516 if (!BitmapStart && !BitmapEnd && NumBitmapBytes) {
519 "could not find profile bitmap section in correlated file");
520 return std::nullopt;
521 }
522 if (*BitmapPtr < BitmapStart || (*BitmapPtr >= BitmapEnd && NumBitmapBytes)) {
523 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
525 "BitmapPtr out of range for function %s: Actual=0x%x "
526 "Expected=[0x%x, 0x%x)\n",
527 *FunctionName, *BitmapPtr, BitmapStart, BitmapEnd);
528 LLVM_DEBUG(Die.dump(dbgs()));
529 }
530 return std::nullopt;
531 }
532 // In debug info correlation mode, the BitmapPtr is an absolute address of
533 // the bitmap, but it's expected to be relative later when iterating Data.
534 IntPtrT BitmapOffset = *BitmapPtr - BitmapStart;
536 P.FunctionName = *FunctionName;
537 P.BitmapOffset = BitmapOffset;
538 P.NumBitmapBytes = NumBitmapBytes;
539
540 return std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>>({P, 0});
541}
542
543template <class IntPtrT>
544void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
545 int MaxWarnings, InstrProfCorrelator::CorrelationData *Data) {
546 // Map from FunctionName string to (Probe, FunctionPtr) pair.
547 // We use it to collect data from all functions Counter and Bitmap DIEs.
550 Probes;
551 bool UnlimitedWarnings = (MaxWarnings == 0);
552 // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
553 int NumSuppressedWarnings = -MaxWarnings;
554
555 auto MaybeAddProbe = [&](DWARFDie Die) {
556 std::optional<std::pair<InstrProfCorrelator::Probe, IntPtrT>> ProbeData;
557 if (isDIEOfProbe(Die, getInstrProfCountersVarPrefix()))
558 ProbeData =
559 addCountersToDataProbe(Die, UnlimitedWarnings, NumSuppressedWarnings);
560 else if (isDIEOfProbe(Die, getInstrProfBitmapVarPrefix()))
561 ProbeData =
562 addBitmapToDataProbe(Die, UnlimitedWarnings, NumSuppressedWarnings);
563 if (!ProbeData)
564 return;
565 auto [Probe, FunctionPtr] = *ProbeData;
566
567 auto [It, Inserted] =
568 Probes.try_emplace(Probe.FunctionName, Probe, FunctionPtr);
569 if (!Inserted) {
570 auto &P = It->second.first;
571 if (isDIEOfProbe(Die, getInstrProfCountersVarPrefix())) {
572 P.LinkageName = Probe.LinkageName;
573 P.CFGHash = Probe.CFGHash;
574 P.CounterOffset = Probe.CounterOffset;
575 P.NumCounters = Probe.NumCounters;
576 P.FilePath = Probe.FilePath;
577 P.LineNumber = Probe.LineNumber;
578 } else {
579 P.BitmapOffset = Probe.BitmapOffset;
580 P.NumBitmapBytes = Probe.NumBitmapBytes;
581 }
582 }
583 };
584 for (auto &CU : DICtx->normal_units())
585 for (const auto &Entry : CU->dies())
586 MaybeAddProbe(DWARFDie(CU.get(), &Entry));
587 for (auto &CU : DICtx->dwo_units())
588 for (const auto &Entry : CU->dies())
589 MaybeAddProbe(DWARFDie(CU.get(), &Entry));
590
591 for (const auto &[FunctionName, ProbeData] : Probes) {
592 const auto &[Probe, FunctionPtr] = ProbeData;
593 if (Data)
594 Data->Probes.push_back(Probe);
595 else {
596 this->NamesVec.push_back(FunctionName);
597 uint64_t NameRef = IndexedInstrProf::ComputeHash(FunctionName);
598 this->addDataProbe(NameRef, Probe.CFGHash, Probe.CounterOffset,
599 Probe.BitmapOffset, FunctionPtr, Probe.NumCounters,
600 Probe.NumBitmapBytes);
601 }
602 }
603 if (!UnlimitedWarnings && NumSuppressedWarnings > 0)
604 WithColor::warning() << format("Suppressed %d additional warnings\n",
605 NumSuppressedWarnings);
606}
607
608template <class IntPtrT>
609Error DwarfInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
610 if (this->NamesVec.empty()) {
613 "could not find any profile name metadata in debug info");
614 }
615 auto Result =
616 collectGlobalObjectNameStrings(this->NamesVec,
617 /*doCompression=*/false, this->Names);
618 return Result;
619}
620
621template <class IntPtrT>
622void BinaryInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
623 int MaxWarnings, InstrProfCorrelator::CorrelationData *CorrelateData) {
624 using RawProfData = RawInstrProf::ProfileData<IntPtrT>;
625 bool UnlimitedWarnings = (MaxWarnings == 0);
626 // -N suppressed warnings means we can emit up to N (unsuppressed) warnings
627 int NumSuppressedWarnings = -MaxWarnings;
628
629 const RawProfData *DataStart = (const RawProfData *)this->Ctx->DataStart;
630 const RawProfData *DataEnd = (const RawProfData *)this->Ctx->DataEnd;
631 // We need to use < here because the last data record may have no padding.
632 for (const RawProfData *I = DataStart; I < DataEnd; ++I) {
633 uint64_t CounterPtr = this->template maybeSwap<IntPtrT>(I->CounterPtr);
634 uint64_t CountersStart = this->Ctx->CountersSectionStart;
635 uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
636
637 uint64_t BitmapPtr = this->template maybeSwap<IntPtrT>(I->BitmapPtr);
638 uint64_t BitmapStart = this->Ctx->BitmapSectionStart;
639 uint64_t BitmapEnd = this->Ctx->BitmapSectionEnd;
640 if (!BitmapStart && !BitmapEnd && I->NumBitmapBytes) {
643 "could not find profile bitmap section in correlated file");
644 return;
645 }
646 if (!this->Ctx->MachOFixups.empty()) {
647 auto GetPtrByOffset = [&](uint64_t Offset, uint64_t &Ptr) {
648 auto It = this->Ctx->MachOFixups.find(Offset);
649 if (It != this->Ctx->MachOFixups.end()) {
650 Ptr = It->second;
651 } else if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
653 "Mach-O fixup not found for covdata offset 0x%llx\n", Offset);
654 }
655 };
656 uint64_t CounterOffset = (uint64_t)&I->CounterPtr - (uint64_t)DataStart;
657 uint64_t BitmapOffset = (uint64_t)&I->BitmapPtr - (uint64_t)DataStart;
658 GetPtrByOffset(CounterOffset, CounterPtr);
659 GetPtrByOffset(BitmapOffset, BitmapPtr);
660 }
661 if (CounterPtr < CountersStart || CounterPtr >= CountersEnd) {
662 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
664 << format("CounterPtr out of range for function: Actual=0x%x "
665 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
666 CounterPtr, CountersStart, CountersEnd,
667 (I - DataStart) * sizeof(RawProfData));
668 }
669 }
670 if (I->NumBitmapBytes &&
671 (BitmapPtr < BitmapStart || BitmapPtr >= BitmapEnd)) {
672 if (UnlimitedWarnings || ++NumSuppressedWarnings < 1) {
674 << format("BitmapPtr out of range for function: Actual=0x%x "
675 "Expected=[0x%x, 0x%x) at data offset=0x%x\n",
676 BitmapPtr, BitmapStart, BitmapEnd,
677 (I - DataStart) * sizeof(RawProfData));
678 }
679 }
680 // In binary correlation mode, CounterPtr and BitmapPtr are absolute
681 // addresses, but they're expected to be relative later when iterating Data.
682 IntPtrT CounterOffset = CounterPtr - CountersStart;
683 IntPtrT BitmapOffset = BitmapPtr - BitmapStart;
684 this->addDataProbe(I->NameRef, I->FuncHash, CounterOffset, BitmapOffset,
685 I->FunctionPointer, I->NumCounters, I->NumBitmapBytes);
686 }
687}
688
689template <class IntPtrT>
690Error BinaryInstrProfCorrelator<IntPtrT>::correlateProfileNameImpl() {
691 if (this->Ctx->NameSize == 0) {
694 "could not find any profile data metadata in object file");
695 }
696 this->Names.append(this->Ctx->NameStart, this->Ctx->NameSize);
697 return Error::success();
698}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
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)
#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:754
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:560
dwarf::Tag getTag() const
Definition DWARFDie.h:73
LLVM_ABI Expected< DWARFLocationExpressionsVector > getLocations(dwarf::Attribute Attr) const
Definition DWARFDie.cpp:524
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:692
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
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:129
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.
uint64_t ComputeHash(StringRef K)
Definition InstrProf.h:1226
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.
MemoryLocation getLocation(Instruction *I)
Definition SLPUtils.cpp:823
constexpr bool IsLittleEndianHost
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:577
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:149
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:102
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
ProfCorrelatorKind
Whether the debug info or the profile metadata sections correlate raw profile data to functions.
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:1933
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:878
#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)