LLVM 18.0.0git
RawMemProfReader.cpp
Go to the documentation of this file.
1//===- RawMemProfReader.cpp - Instrumented memory profiling reader --------===//
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//
9// This file contains support for reading MemProf profiling data.
10//
11//===----------------------------------------------------------------------===//
12
13#include <algorithm>
14#include <cstdint>
15#include <memory>
16#include <type_traits>
17
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/SetVector.h"
22#include "llvm/ADT/SmallSet.h"
25#include "llvm/ADT/Twine.h"
29#include "llvm/Object/Binary.h"
30#include "llvm/Object/BuildID.h"
38#include "llvm/Support/Debug.h"
39#include "llvm/Support/Endian.h"
40#include "llvm/Support/Error.h"
42#include "llvm/Support/Path.h"
43
44#define DEBUG_TYPE "memprof"
45
46namespace llvm {
47namespace memprof {
48namespace {
49template <class T = uint64_t> inline T alignedRead(const char *Ptr) {
50 static_assert(std::is_pod<T>::value, "Not a pod type.");
51 assert(reinterpret_cast<size_t>(Ptr) % sizeof(T) == 0 && "Unaligned Read");
52 return *reinterpret_cast<const T *>(Ptr);
53}
54
55Error checkBuffer(const MemoryBuffer &Buffer) {
56 if (!RawMemProfReader::hasFormat(Buffer))
57 return make_error<InstrProfError>(instrprof_error::bad_magic);
58
59 if (Buffer.getBufferSize() == 0)
60 return make_error<InstrProfError>(instrprof_error::empty_raw_profile);
61
62 if (Buffer.getBufferSize() < sizeof(Header)) {
63 return make_error<InstrProfError>(instrprof_error::truncated);
64 }
65
66 // The size of the buffer can be > header total size since we allow repeated
67 // serialization of memprof profiles to the same file.
68 uint64_t TotalSize = 0;
69 const char *Next = Buffer.getBufferStart();
70 while (Next < Buffer.getBufferEnd()) {
71 auto *H = reinterpret_cast<const Header *>(Next);
72 if (H->Version != MEMPROF_RAW_VERSION) {
73 return make_error<InstrProfError>(instrprof_error::unsupported_version);
74 }
75
76 TotalSize += H->TotalSize;
77 Next += H->TotalSize;
78 }
79
80 if (Buffer.getBufferSize() != TotalSize) {
81 return make_error<InstrProfError>(instrprof_error::malformed);
82 }
83 return Error::success();
84}
85
86llvm::SmallVector<SegmentEntry> readSegmentEntries(const char *Ptr) {
87 using namespace support;
88
89 const uint64_t NumItemsToRead =
90 endian::readNext<uint64_t, little, unaligned>(Ptr);
92 for (uint64_t I = 0; I < NumItemsToRead; I++) {
93 Items.push_back(*reinterpret_cast<const SegmentEntry *>(
94 Ptr + I * sizeof(SegmentEntry)));
95 }
96 return Items;
97}
98
100readMemInfoBlocks(const char *Ptr) {
101 using namespace support;
102
103 const uint64_t NumItemsToRead =
104 endian::readNext<uint64_t, little, unaligned>(Ptr);
106 for (uint64_t I = 0; I < NumItemsToRead; I++) {
107 const uint64_t Id = endian::readNext<uint64_t, little, unaligned>(Ptr);
108 const MemInfoBlock MIB = *reinterpret_cast<const MemInfoBlock *>(Ptr);
109 Items.push_back({Id, MIB});
110 // Only increment by size of MIB since readNext implicitly increments.
111 Ptr += sizeof(MemInfoBlock);
112 }
113 return Items;
114}
115
116CallStackMap readStackInfo(const char *Ptr) {
117 using namespace support;
118
119 const uint64_t NumItemsToRead =
120 endian::readNext<uint64_t, little, unaligned>(Ptr);
121 CallStackMap Items;
122
123 for (uint64_t I = 0; I < NumItemsToRead; I++) {
124 const uint64_t StackId = endian::readNext<uint64_t, little, unaligned>(Ptr);
125 const uint64_t NumPCs = endian::readNext<uint64_t, little, unaligned>(Ptr);
126
127 SmallVector<uint64_t> CallStack;
128 for (uint64_t J = 0; J < NumPCs; J++) {
129 CallStack.push_back(endian::readNext<uint64_t, little, unaligned>(Ptr));
130 }
131
132 Items[StackId] = CallStack;
133 }
134 return Items;
135}
136
137// Merges the contents of stack information in \p From to \p To. Returns true if
138// any stack ids observed previously map to a different set of program counter
139// addresses.
140bool mergeStackMap(const CallStackMap &From, CallStackMap &To) {
141 for (const auto &IdStack : From) {
142 auto I = To.find(IdStack.first);
143 if (I == To.end()) {
144 To[IdStack.first] = IdStack.second;
145 } else {
146 // Check that the PCs are the same (in order).
147 if (IdStack.second != I->second)
148 return true;
149 }
150 }
151 return false;
152}
153
154Error report(Error E, const StringRef Context) {
156 std::move(E));
157}
158
159bool isRuntimePath(const StringRef Path) {
160 const StringRef Filename = llvm::sys::path::filename(Path);
161 // This list should be updated in case new files with additional interceptors
162 // are added to the memprof runtime.
163 return Filename.equals("memprof_malloc_linux.cpp") ||
164 Filename.equals("memprof_interceptors.cpp") ||
165 Filename.equals("memprof_new_delete.cpp");
166}
167
168std::string getBuildIdString(const SegmentEntry &Entry) {
169 // If the build id is unset print a helpful string instead of all zeros.
170 if (Entry.BuildIdSize == 0)
171 return "<None>";
172
173 std::string Str;
174 raw_string_ostream OS(Str);
175 for (size_t I = 0; I < Entry.BuildIdSize; I++) {
176 OS << format_hex_no_prefix(Entry.BuildId[I], 2);
177 }
178 return OS.str();
179}
180} // namespace
181
182Expected<std::unique_ptr<RawMemProfReader>>
183RawMemProfReader::create(const Twine &Path, const StringRef ProfiledBinary,
184 bool KeepName) {
185 auto BufferOr = MemoryBuffer::getFileOrSTDIN(Path);
186 if (std::error_code EC = BufferOr.getError())
187 return report(errorCodeToError(EC), Path.getSingleStringRef());
188
189 std::unique_ptr<MemoryBuffer> Buffer(BufferOr.get().release());
190 return create(std::move(Buffer), ProfiledBinary, KeepName);
191}
192
194RawMemProfReader::create(std::unique_ptr<MemoryBuffer> Buffer,
195 const StringRef ProfiledBinary, bool KeepName) {
196 if (Error E = checkBuffer(*Buffer))
197 return report(std::move(E), Buffer->getBufferIdentifier());
198
199 if (ProfiledBinary.empty()) {
200 // Peek the build ids to print a helpful error message.
201 const std::vector<std::string> BuildIds = peekBuildIds(Buffer.get());
202 std::string ErrorMessage(
203 R"(Path to profiled binary is empty, expected binary with one of the following build ids:
204)");
205 for (const auto &Id : BuildIds) {
206 ErrorMessage += "\n BuildId: ";
207 ErrorMessage += Id;
208 }
209 return report(
210 make_error<StringError>(ErrorMessage, inconvertibleErrorCode()),
211 /*Context=*/"");
212 }
213
214 auto BinaryOr = llvm::object::createBinary(ProfiledBinary);
215 if (!BinaryOr) {
216 return report(BinaryOr.takeError(), ProfiledBinary);
217 }
218
219 // Use new here since constructor is private.
220 std::unique_ptr<RawMemProfReader> Reader(
221 new RawMemProfReader(std::move(BinaryOr.get()), KeepName));
222 if (Error E = Reader->initialize(std::move(Buffer))) {
223 return std::move(E);
224 }
225 return std::move(Reader);
226}
228bool RawMemProfReader::hasFormat(const StringRef Path) {
229 auto BufferOr = MemoryBuffer::getFileOrSTDIN(Path);
230 if (!BufferOr)
231 return false;
232
233 std::unique_ptr<MemoryBuffer> Buffer(BufferOr.get().release());
234 return hasFormat(*Buffer);
235}
237bool RawMemProfReader::hasFormat(const MemoryBuffer &Buffer) {
238 if (Buffer.getBufferSize() < sizeof(uint64_t))
239 return false;
240 // Aligned read to sanity check that the buffer was allocated with at least 8b
241 // alignment.
242 const uint64_t Magic = alignedRead(Buffer.getBufferStart());
243 return Magic == MEMPROF_RAW_MAGIC_64;
244}
247 uint64_t NumAllocFunctions = 0, NumMibInfo = 0;
248 for (const auto &KV : FunctionProfileData) {
249 const size_t NumAllocSites = KV.second.AllocSites.size();
250 if (NumAllocSites > 0) {
251 NumAllocFunctions++;
252 NumMibInfo += NumAllocSites;
253 }
254 }
255
256 OS << "MemprofProfile:\n";
257 OS << " Summary:\n";
258 OS << " Version: " << MEMPROF_RAW_VERSION << "\n";
259 OS << " NumSegments: " << SegmentInfo.size() << "\n";
260 OS << " NumMibInfo: " << NumMibInfo << "\n";
261 OS << " NumAllocFunctions: " << NumAllocFunctions << "\n";
262 OS << " NumStackOffsets: " << StackMap.size() << "\n";
263 // Print out the segment information.
264 OS << " Segments:\n";
265 for (const auto &Entry : SegmentInfo) {
266 OS << " -\n";
267 OS << " BuildId: " << getBuildIdString(Entry) << "\n";
268 OS << " Start: 0x" << llvm::utohexstr(Entry.Start) << "\n";
269 OS << " End: 0x" << llvm::utohexstr(Entry.End) << "\n";
270 OS << " Offset: 0x" << llvm::utohexstr(Entry.Offset) << "\n";
271 }
272 // Print out the merged contents of the profiles.
273 OS << " Records:\n";
274 for (const auto &Entry : *this) {
275 OS << " -\n";
276 OS << " FunctionGUID: " << Entry.first << "\n";
277 Entry.second.print(OS);
278 }
279}
280
281Error RawMemProfReader::initialize(std::unique_ptr<MemoryBuffer> DataBuffer) {
282 const StringRef FileName = Binary.getBinary()->getFileName();
283
284 auto *ElfObject = dyn_cast<object::ELFObjectFileBase>(Binary.getBinary());
285 if (!ElfObject) {
286 return report(make_error<StringError>(Twine("Not an ELF file: "),
288 FileName);
289 }
290
291 // Check whether the profiled binary was built with position independent code
292 // (PIC). Perform sanity checks for assumptions we rely on to simplify
293 // symbolization.
294 auto* Elf64LEObject = llvm::cast<llvm::object::ELF64LEObjectFile>(ElfObject);
295 const llvm::object::ELF64LEFile& ElfFile = Elf64LEObject->getELFFile();
296 auto PHdrsOr = ElfFile.program_headers();
297 if (!PHdrsOr)
298 return report(
299 make_error<StringError>(Twine("Could not read program headers: "),
301 FileName);
302
303 int NumExecutableSegments = 0;
304 for (const auto &Phdr : *PHdrsOr) {
305 if (Phdr.p_type == ELF::PT_LOAD) {
306 if (Phdr.p_flags & ELF::PF_X) {
307 // We assume only one text segment in the main binary for simplicity and
308 // reduce the overhead of checking multiple ranges during symbolization.
309 if (++NumExecutableSegments > 1) {
310 return report(
311 make_error<StringError>(
312 "Expect only one executable load segment in the binary",
314 FileName);
315 }
316 // Segment will always be loaded at a page boundary, expect it to be
317 // aligned already. Assume 4K pagesize for the machine from which the
318 // profile has been collected. This should be fine for now, in case we
319 // want to support other pagesizes it can be recorded in the raw profile
320 // during collection.
321 PreferredTextSegmentAddress = Phdr.p_vaddr;
322 assert(Phdr.p_vaddr == (Phdr.p_vaddr & ~(0x1000 - 1U)) &&
323 "Expect p_vaddr to always be page aligned");
324 assert(Phdr.p_offset == 0 && "Expect p_offset = 0 for symbolization.");
325 }
326 }
327 }
328
329 auto Triple = ElfObject->makeTriple();
330 if (!Triple.isX86())
331 return report(make_error<StringError>(Twine("Unsupported target: ") +
332 Triple.getArchName(),
334 FileName);
335
336 auto *Object = cast<object::ObjectFile>(Binary.getBinary());
337 std::unique_ptr<DIContext> Context = DWARFContext::create(
339
341 Object, std::move(Context), /*UntagAddresses=*/false);
342 if (!SOFOr)
343 return report(SOFOr.takeError(), FileName);
344 Symbolizer = std::move(SOFOr.get());
345
346 // Process the raw profile.
347 if (Error E = readRawProfile(std::move(DataBuffer)))
348 return E;
349
350 if (Error E = setupForSymbolization())
351 return E;
352
353 if (Error E = symbolizeAndFilterStackFrames())
354 return E;
355
356 return mapRawProfileToRecords();
357}
358
359Error RawMemProfReader::setupForSymbolization() {
360 auto *Object = cast<object::ObjectFile>(Binary.getBinary());
361 object::BuildIDRef BinaryId = object::getBuildID(Object);
362 if (BinaryId.empty())
363 return make_error<StringError>(Twine("No build id found in binary ") +
364 Binary.getBinary()->getFileName(),
366
367 int NumMatched = 0;
368 for (const auto &Entry : SegmentInfo) {
369 llvm::ArrayRef<uint8_t> SegmentId(Entry.BuildId, Entry.BuildIdSize);
370 if (BinaryId == SegmentId) {
371 // We assume only one text segment in the main binary for simplicity and
372 // reduce the overhead of checking multiple ranges during symbolization.
373 if (++NumMatched > 1) {
374 return make_error<StringError>(
375 "We expect only one executable segment in the profiled binary",
377 }
378 ProfiledTextSegmentStart = Entry.Start;
379 ProfiledTextSegmentEnd = Entry.End;
380 }
381 }
382 assert(NumMatched != 0 && "No matching executable segments in segment info.");
383 assert((PreferredTextSegmentAddress == 0 ||
384 (PreferredTextSegmentAddress == ProfiledTextSegmentStart)) &&
385 "Expect text segment address to be 0 or equal to profiled text "
386 "segment start.");
387 return Error::success();
388}
389
390Error RawMemProfReader::mapRawProfileToRecords() {
391 // Hold a mapping from function to each callsite location we encounter within
392 // it that is part of some dynamic allocation context. The location is stored
393 // as a pointer to a symbolized list of inline frames.
394 using LocationPtr = const llvm::SmallVector<FrameId> *;
396 PerFunctionCallSites;
397
398 // Convert the raw profile callstack data into memprof records. While doing so
399 // keep track of related contexts so that we can fill these in later.
400 for (const auto &Entry : CallstackProfileData) {
401 const uint64_t StackId = Entry.first;
402
403 auto It = StackMap.find(StackId);
404 if (It == StackMap.end())
405 return make_error<InstrProfError>(
407 "memprof callstack record does not contain id: " + Twine(StackId));
408
409 // Construct the symbolized callstack.
411 Callstack.reserve(It->getSecond().size());
412
413 llvm::ArrayRef<uint64_t> Addresses = It->getSecond();
414 for (size_t I = 0; I < Addresses.size(); I++) {
415 const uint64_t Address = Addresses[I];
416 assert(SymbolizedFrame.count(Address) > 0 &&
417 "Address not found in SymbolizedFrame map");
418 const SmallVector<FrameId> &Frames = SymbolizedFrame[Address];
419
420 assert(!idToFrame(Frames.back()).IsInlineFrame &&
421 "The last frame should not be inlined");
422
423 // Record the callsites for each function. Skip the first frame of the
424 // first address since it is the allocation site itself that is recorded
425 // as an alloc site.
426 for (size_t J = 0; J < Frames.size(); J++) {
427 if (I == 0 && J == 0)
428 continue;
429 // We attach the entire bottom-up frame here for the callsite even
430 // though we only need the frames up to and including the frame for
431 // Frames[J].Function. This will enable better deduplication for
432 // compression in the future.
433 const GlobalValue::GUID Guid = idToFrame(Frames[J]).Function;
434 PerFunctionCallSites[Guid].insert(&Frames);
435 }
436
437 // Add all the frames to the current allocation callstack.
438 Callstack.append(Frames.begin(), Frames.end());
439 }
440
441 // We attach the memprof record to each function bottom-up including the
442 // first non-inline frame.
443 for (size_t I = 0; /*Break out using the condition below*/; I++) {
444 const Frame &F = idToFrame(Callstack[I]);
445 auto Result =
446 FunctionProfileData.insert({F.Function, IndexedMemProfRecord()});
447 IndexedMemProfRecord &Record = Result.first->second;
448 Record.AllocSites.emplace_back(Callstack, Entry.second);
449
450 if (!F.IsInlineFrame)
451 break;
452 }
453 }
454
455 // Fill in the related callsites per function.
456 for (const auto &[Id, Locs] : PerFunctionCallSites) {
457 // Some functions may have only callsite data and no allocation data. Here
458 // we insert a new entry for callsite data if we need to.
459 auto Result = FunctionProfileData.insert({Id, IndexedMemProfRecord()});
460 IndexedMemProfRecord &Record = Result.first->second;
461 for (LocationPtr Loc : Locs) {
462 Record.CallSites.push_back(*Loc);
463 }
464 }
465
466 return Error::success();
467}
468
469Error RawMemProfReader::symbolizeAndFilterStackFrames() {
470 // The specifier to use when symbolization is requested.
471 const DILineInfoSpecifier Specifier(
472 DILineInfoSpecifier::FileLineInfoKind::RawValue,
473 DILineInfoSpecifier::FunctionNameKind::LinkageName);
474
475 // For entries where all PCs in the callstack are discarded, we erase the
476 // entry from the stack map.
477 llvm::SmallVector<uint64_t> EntriesToErase;
478 // We keep track of all prior discarded entries so that we can avoid invoking
479 // the symbolizer for such entries.
480 llvm::DenseSet<uint64_t> AllVAddrsToDiscard;
481 for (auto &Entry : StackMap) {
482 for (const uint64_t VAddr : Entry.getSecond()) {
483 // Check if we have already symbolized and cached the result or if we
484 // don't want to attempt symbolization since we know this address is bad.
485 // In this case the address is also removed from the current callstack.
486 if (SymbolizedFrame.count(VAddr) > 0 ||
487 AllVAddrsToDiscard.contains(VAddr))
488 continue;
489
490 Expected<DIInliningInfo> DIOr = Symbolizer->symbolizeInlinedCode(
491 getModuleOffset(VAddr), Specifier, /*UseSymbolTable=*/false);
492 if (!DIOr)
493 return DIOr.takeError();
494 DIInliningInfo DI = DIOr.get();
495
496 // Drop frames which we can't symbolize or if they belong to the runtime.
497 if (DI.getFrame(0).FunctionName == DILineInfo::BadString ||
498 isRuntimePath(DI.getFrame(0).FileName)) {
499 AllVAddrsToDiscard.insert(VAddr);
500 continue;
501 }
502
503 for (size_t I = 0, NumFrames = DI.getNumberOfFrames(); I < NumFrames;
504 I++) {
505 const auto &DIFrame = DI.getFrame(I);
506 const uint64_t Guid =
507 IndexedMemProfRecord::getGUID(DIFrame.FunctionName);
508 const Frame F(Guid, DIFrame.Line - DIFrame.StartLine, DIFrame.Column,
509 // Only the last entry is not an inlined location.
510 I != NumFrames - 1);
511 // Here we retain a mapping from the GUID to canonical symbol name
512 // instead of adding it to the frame object directly to reduce memory
513 // overhead. This is because there can be many unique frames,
514 // particularly for callsite frames.
515 if (KeepSymbolName) {
516 StringRef CanonicalName =
518 DIFrame.FunctionName);
519 GuidToSymbolName.insert({Guid, CanonicalName.str()});
520 }
521
522 const FrameId Hash = F.hash();
523 IdToFrame.insert({Hash, F});
524 SymbolizedFrame[VAddr].push_back(Hash);
525 }
526 }
527
528 auto &CallStack = Entry.getSecond();
529 llvm::erase_if(CallStack, [&AllVAddrsToDiscard](const uint64_t A) {
530 return AllVAddrsToDiscard.contains(A);
531 });
532 if (CallStack.empty())
533 EntriesToErase.push_back(Entry.getFirst());
534 }
535
536 // Drop the entries where the callstack is empty.
537 for (const uint64_t Id : EntriesToErase) {
538 StackMap.erase(Id);
539 CallstackProfileData.erase(Id);
540 }
541
542 if (StackMap.empty())
543 return make_error<InstrProfError>(
545 "no entries in callstack map after symbolization");
546
547 return Error::success();
548}
549
550std::vector<std::string>
552 const char *Next = DataBuffer->getBufferStart();
553 // Use a set + vector since a profile file may contain multiple raw profile
554 // dumps, each with segment information. We want them unique and in order they
555 // were stored in the profile; the profiled binary should be the first entry.
556 // The runtime uses dl_iterate_phdr and the "... first object visited by
557 // callback is the main program."
558 // https://man7.org/linux/man-pages/man3/dl_iterate_phdr.3.html
559 std::vector<std::string> BuildIds;
561 while (Next < DataBuffer->getBufferEnd()) {
562 auto *Header = reinterpret_cast<const memprof::Header *>(Next);
563
564 const llvm::SmallVector<SegmentEntry> Entries =
565 readSegmentEntries(Next + Header->SegmentOffset);
566
567 for (const auto &Entry : Entries) {
568 const std::string Id = getBuildIdString(Entry);
569 if (BuildIdsSet.contains(Id))
570 continue;
571 BuildIds.push_back(Id);
572 BuildIdsSet.insert(Id);
573 }
574
575 Next += Header->TotalSize;
576 }
577 return BuildIds;
578}
579
580Error RawMemProfReader::readRawProfile(
581 std::unique_ptr<MemoryBuffer> DataBuffer) {
582 const char *Next = DataBuffer->getBufferStart();
583
584 while (Next < DataBuffer->getBufferEnd()) {
585 auto *Header = reinterpret_cast<const memprof::Header *>(Next);
586
587 // Read in the segment information, check whether its the same across all
588 // profiles in this binary file.
589 const llvm::SmallVector<SegmentEntry> Entries =
590 readSegmentEntries(Next + Header->SegmentOffset);
591 if (!SegmentInfo.empty() && SegmentInfo != Entries) {
592 // We do not expect segment information to change when deserializing from
593 // the same binary profile file. This can happen if dynamic libraries are
594 // loaded/unloaded between profile dumping.
595 return make_error<InstrProfError>(
597 "memprof raw profile has different segment information");
598 }
599 SegmentInfo.assign(Entries.begin(), Entries.end());
600
601 // Read in the MemInfoBlocks. Merge them based on stack id - we assume that
602 // raw profiles in the same binary file are from the same process so the
603 // stackdepot ids are the same.
604 for (const auto &Value : readMemInfoBlocks(Next + Header->MIBOffset)) {
605 if (CallstackProfileData.count(Value.first)) {
606 CallstackProfileData[Value.first].Merge(Value.second);
607 } else {
608 CallstackProfileData[Value.first] = Value.second;
609 }
610 }
611
612 // Read in the callstack for each ids. For multiple raw profiles in the same
613 // file, we expect that the callstack is the same for a unique id.
614 const CallStackMap CSM = readStackInfo(Next + Header->StackOffset);
615 if (StackMap.empty()) {
616 StackMap = CSM;
617 } else {
618 if (mergeStackMap(CSM, StackMap))
619 return make_error<InstrProfError>(
621 "memprof raw profile got different call stack for same id");
622 }
623
624 Next += Header->TotalSize;
625 }
626
627 return Error::success();
628}
629
630object::SectionedAddress
631RawMemProfReader::getModuleOffset(const uint64_t VirtualAddress) {
632 if (VirtualAddress > ProfiledTextSegmentStart &&
633 VirtualAddress <= ProfiledTextSegmentEnd) {
634 // For PIE binaries, the preferred address is zero and we adjust the virtual
635 // address by start of the profiled segment assuming that the offset of the
636 // segment in the binary is zero. For non-PIE binaries the preferred and
637 // profiled segment addresses should be equal and this is a no-op.
638 const uint64_t AdjustedAddress =
639 VirtualAddress + PreferredTextSegmentAddress - ProfiledTextSegmentStart;
640 return object::SectionedAddress{AdjustedAddress};
641 }
642 // Addresses which do not originate from the profiled text segment in the
643 // binary are not adjusted. These will fail symbolization and be filtered out
644 // during processing.
645 return object::SectionedAddress{VirtualAddress};
646}
649 GuidMemProfRecordPair &GuidRecord,
650 std::function<const Frame(const FrameId)> Callback) {
651 // Create a new callback for the RawMemProfRecord iterator so that we can
652 // provide the symbol name if the reader was initialized with KeepSymbolName =
653 // true. This is useful for debugging and testing.
654 auto IdToFrameCallback = [this](const FrameId Id) {
655 Frame F = this->idToFrame(Id);
656 if (!this->KeepSymbolName)
657 return F;
658 auto Iter = this->GuidToSymbolName.find(F.Function);
659 assert(Iter != this->GuidToSymbolName.end());
660 F.SymbolName = Iter->getSecond();
661 return F;
662 };
663 return MemProfReader::readNextRecord(GuidRecord, IdToFrameCallback);
664}
665} // namespace memprof
666} // namespace llvm
BlockVerifier::State From
This file declares a library for handling Build IDs and using them to find debug info.
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines DenseMapInfo traits for DenseMap.
This file defines the DenseMap class.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
#define H(x, y, z)
Definition: MD5.cpp:57
LLVMContext & Context
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallSet class.
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:165
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)
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:155
unsigned size() const
Definition: DenseMap.h:99
iterator end()
Definition: DenseMap.h:84
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: DenseMap.h:220
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
static ErrorSuccess success()
Create a success value.
Definition: Error.h:334
Tagged union holding either a T or a Error.
Definition: Error.h:474
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
Definition: GlobalValue.h:583
This class implements a map that also provides access to all stored values in a deterministic order.
Definition: MapVector.h:36
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition: MapVector.h:117
This interface provides simple read-only access to a block of memory, and provides simple methods for...
Definition: MemoryBuffer.h:51
size_t getBufferSize() const
Definition: MemoryBuffer.h:68
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
const char * getBufferStart() const
Definition: MemoryBuffer.h:66
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:135
bool contains(const T &V) const
Check if the SmallSet contains the given element.
Definition: SmallSet.h:236
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:179
size_t size() const
Definition: SmallVector.h:91
void reserve(size_type N)
Definition: SmallVector.h:667
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:687
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
LLVM Value Representation.
Definition: Value.h:74
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition: DenseSet.h:185
const Frame & idToFrame(const FrameId Id) const
virtual Error readNextRecord(GuidMemProfRecordPair &GuidRecord, std::function< const Frame(const FrameId)> Callback=nullptr)
llvm::DenseMap< FrameId, Frame > IdToFrame
llvm::MapVector< GlobalValue::GUID, IndexedMemProfRecord >::iterator Iter
llvm::MapVector< GlobalValue::GUID, IndexedMemProfRecord > FunctionProfileData
std::pair< GlobalValue::GUID, MemProfRecord > GuidMemProfRecordPair
static Expected< std::unique_ptr< RawMemProfReader > > create(const Twine &Path, StringRef ProfiledBinary, bool KeepName=false)
static std::vector< std::string > peekBuildIds(MemoryBuffer *DataBuffer)
virtual Error readNextRecord(GuidMemProfRecordPair &GuidRecord, std::function< const Frame(const FrameId)> Callback) override
static bool hasFormat(const MemoryBuffer &DataBuffer)
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
Definition: SampleProf.h:1087
static Expected< std::unique_ptr< SymbolizableObjectFile > > create(const object::ObjectFile *Obj, std::unique_ptr< DIContext > DICtx, bool UntagAddresses)
@ PF_X
Definition: ELF.h:1436
@ PT_LOAD
Definition: ELF.h:1388
uint64_t FrameId
Definition: MemProf.h:138
llvm::DenseMap< uint64_t, llvm::SmallVector< uint64_t > > CallStackMap
BuildIDRef getBuildID(const ObjectFile *Obj)
Returns the build ID, if any, contained in the given object file.
Definition: BuildID.cpp:56
ArrayRef< uint8_t > BuildIDRef
A reference to a BuildID in binary form.
Definition: BuildID.h:28
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
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:579
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:90
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1244
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:431
FormattedNumber format_hex_no_prefix(uint64_t N, unsigned Width, bool Upper=false)
format_hex_no_prefix - Output N as a fixed width hexadecimal.
Definition: Format.h:200
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
Definition: STLExtras.h:2021
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:103
static constexpr const char *const BadString
Definition: DIContext.h:34
GlobalValue::GUID Function
Definition: MemProf.h:145
static GlobalValue::GUID getGUID(const StringRef FunctionName)
Definition: MemProf.cpp:74