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