LLVM 22.0.0git
MemProfUse.cpp
Go to the documentation of this file.
1//===- MemProfUse.cpp - memory allocation profile use pass --*- C++ -*-===//
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 implements the MemProfUsePass which reads memory profiling data
10// and uses it to add metadata to instructions to guide optimization.
11//
12//===----------------------------------------------------------------------===//
13
16#include "llvm/ADT/Statistic.h"
17#include "llvm/ADT/StringRef.h"
23#include "llvm/IR/Function.h"
25#include "llvm/IR/Module.h"
30#include "llvm/Support/BLAKE3.h"
32#include "llvm/Support/Debug.h"
36#include <map>
37#include <set>
38
39using namespace llvm;
40using namespace llvm::memprof;
41
42#define DEBUG_TYPE "memprof"
43
44namespace llvm {
48} // namespace llvm
49
50// By default disable matching of allocation profiles onto operator new that
51// already explicitly pass a hot/cold hint, since we don't currently
52// override these hints anyway.
54 "memprof-match-hot-cold-new",
56 "Match allocation profiles onto existing hot/cold operator new calls"),
57 cl::Hidden, cl::init(false));
58
59static cl::opt<bool>
60 ClPrintMemProfMatchInfo("memprof-print-match-info",
61 cl::desc("Print matching stats for each allocation "
62 "context in this module's profiles"),
63 cl::Hidden, cl::init(false));
64
65static cl::opt<bool>
66 SalvageStaleProfile("memprof-salvage-stale-profile",
67 cl::desc("Salvage stale MemProf profile"),
68 cl::init(false), cl::Hidden);
69
71 "memprof-attach-calleeguids",
73 "Attach calleeguids as value profile metadata for indirect calls."),
74 cl::init(true), cl::Hidden);
75
77 "memprof-matching-cold-threshold", cl::init(100), cl::Hidden,
78 cl::desc("Min percent of cold bytes matched to hint allocation cold"));
79
81 "memprof-annotate-static-data-prefix", cl::init(false), cl::Hidden,
82 cl::desc("If true, annotate the static data section prefix"));
83
84// Matching statistics
85STATISTIC(NumOfMemProfMissing, "Number of functions without memory profile.");
86STATISTIC(NumOfMemProfMismatch,
87 "Number of functions having mismatched memory profile hash.");
88STATISTIC(NumOfMemProfFunc, "Number of functions having valid memory profile.");
89STATISTIC(NumOfMemProfAllocContextProfiles,
90 "Number of alloc contexts in memory profile.");
91STATISTIC(NumOfMemProfCallSiteProfiles,
92 "Number of callsites in memory profile.");
93STATISTIC(NumOfMemProfMatchedAllocContexts,
94 "Number of matched memory profile alloc contexts.");
95STATISTIC(NumOfMemProfMatchedAllocs,
96 "Number of matched memory profile allocs.");
97STATISTIC(NumOfMemProfMatchedCallSites,
98 "Number of matched memory profile callsites.");
99STATISTIC(NumOfMemProfHotGlobalVars,
100 "Number of global vars annotated with 'hot' section prefix.");
101STATISTIC(NumOfMemProfColdGlobalVars,
102 "Number of global vars annotated with 'unlikely' section prefix.");
103STATISTIC(NumOfMemProfUnknownGlobalVars,
104 "Number of global vars with unknown hotness (no section prefix).");
105STATISTIC(NumOfMemProfExplicitSectionGlobalVars,
106 "Number of global vars with user-specified section (not annotated).");
107
109 ArrayRef<uint64_t> InlinedCallStack,
110 LLVMContext &Ctx) {
111 I.setMetadata(LLVMContext::MD_callsite,
112 buildCallstackMetadata(InlinedCallStack, Ctx));
113}
114
116 uint32_t Column) {
119 HashBuilder.add(Function, LineOffset, Column);
121 uint64_t Id;
122 std::memcpy(&Id, Hash.data(), sizeof(Hash));
123 return Id;
124}
125
129
131 return getAllocType(AllocInfo->Info.getTotalLifetimeAccessDensity(),
132 AllocInfo->Info.getAllocCount(),
133 AllocInfo->Info.getTotalLifetime());
134}
135
138 uint64_t FullStackId) {
139 SmallVector<uint64_t> StackIds;
140 for (const auto &StackFrame : AllocInfo->CallStack)
141 StackIds.push_back(computeStackId(StackFrame));
143 std::vector<ContextTotalSize> ContextSizeInfo;
145 auto TotalSize = AllocInfo->Info.getTotalSize();
146 assert(TotalSize);
147 assert(FullStackId != 0);
148 ContextSizeInfo.push_back({FullStackId, TotalSize});
149 }
150 AllocTrie.addCallStack(AllocType, StackIds, std::move(ContextSizeInfo));
151 return AllocType;
152}
153
154// Return true if InlinedCallStack, computed from a call instruction's debug
155// info, is a prefix of ProfileCallStack, a list of Frames from profile data
156// (either the allocation data or a callsite).
157static bool
159 ArrayRef<uint64_t> InlinedCallStack) {
160 return ProfileCallStack.size() >= InlinedCallStack.size() &&
161 llvm::equal(ProfileCallStack.take_front(InlinedCallStack.size()),
162 InlinedCallStack, [](const Frame &F, uint64_t StackId) {
163 return computeStackId(F) == StackId;
164 });
165}
166
167static bool isAllocationWithHotColdVariant(const Function *Callee,
168 const TargetLibraryInfo &TLI) {
169 if (!Callee)
170 return false;
171 LibFunc Func;
172 if (!TLI.getLibFunc(*Callee, Func))
173 return false;
174 switch (Func) {
175 case LibFunc_Znwm:
176 case LibFunc_ZnwmRKSt9nothrow_t:
177 case LibFunc_ZnwmSt11align_val_t:
178 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
179 case LibFunc_Znam:
180 case LibFunc_ZnamRKSt9nothrow_t:
181 case LibFunc_ZnamSt11align_val_t:
182 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
183 case LibFunc_size_returning_new:
184 case LibFunc_size_returning_new_aligned:
185 return true;
186 case LibFunc_Znwm12__hot_cold_t:
187 case LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t:
188 case LibFunc_ZnwmSt11align_val_t12__hot_cold_t:
189 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
190 case LibFunc_Znam12__hot_cold_t:
191 case LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t:
192 case LibFunc_ZnamSt11align_val_t12__hot_cold_t:
193 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
194 case LibFunc_size_returning_new_hot_cold:
195 case LibFunc_size_returning_new_aligned_hot_cold:
197 default:
198 return false;
199 }
200}
201
203 AnnotationKind Kind) {
205 "Should not handle AnnotationOK here");
206 SmallString<32> Reason;
207 switch (Kind) {
209 ++NumOfMemProfExplicitSectionGlobalVars;
210 Reason.append("explicit section name");
211 break;
213 Reason.append("linker declaration");
214 break;
216 Reason.append("name starts with `llvm.`");
217 break;
218 default:
219 llvm_unreachable("Unexpected annotation kind");
220 }
221 LLVM_DEBUG(dbgs() << "Skip annotation for " << GVar.getName() << " due to "
222 << Reason << ".\n");
223}
224
229
232 function_ref<bool(uint64_t)> IsPresentInProfile) {
234
235 auto GetOffset = [](const DILocation *DIL) {
236 return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) &
237 0xffff;
238 };
239
240 for (Function &F : M) {
241 if (F.isDeclaration())
242 continue;
243
244 for (auto &BB : F) {
245 for (auto &I : BB) {
247 continue;
248
249 auto *CB = dyn_cast<CallBase>(&I);
250 auto *CalledFunction = CB->getCalledFunction();
251 // Disregard indirect calls and intrinsics.
252 if (!CalledFunction || CalledFunction->isIntrinsic())
253 continue;
254
255 StringRef CalleeName = CalledFunction->getName();
256 // True if we are calling a heap allocation function that supports
257 // hot/cold variants.
258 bool IsAlloc = isAllocationWithHotColdVariant(CalledFunction, TLI);
259 // True for the first iteration below, indicating that we are looking at
260 // a leaf node.
261 bool IsLeaf = true;
262 for (const DILocation *DIL = I.getDebugLoc(); DIL;
263 DIL = DIL->getInlinedAt()) {
264 StringRef CallerName = DIL->getSubprogramLinkageName();
265 assert(!CallerName.empty() &&
266 "Be sure to enable -fdebug-info-for-profiling");
267 uint64_t CallerGUID = memprof::getGUID(CallerName);
268 uint64_t CalleeGUID = memprof::getGUID(CalleeName);
269 // Pretend that we are calling a function with GUID == 0 if we are
270 // in the inline stack leading to a heap allocation function.
271 if (IsAlloc) {
272 if (IsLeaf) {
273 // For leaf nodes, set CalleeGUID to 0 without consulting
274 // IsPresentInProfile.
275 CalleeGUID = 0;
276 } else if (!IsPresentInProfile(CalleeGUID)) {
277 // In addition to the leaf case above, continue to set CalleeGUID
278 // to 0 as long as we don't see CalleeGUID in the profile.
279 CalleeGUID = 0;
280 } else {
281 // Once we encounter a callee that exists in the profile, stop
282 // setting CalleeGUID to 0.
283 IsAlloc = false;
284 }
285 }
286
287 LineLocation Loc = {GetOffset(DIL), DIL->getColumn()};
288 Calls[CallerGUID].emplace_back(Loc, CalleeGUID);
289 CalleeName = CallerName;
290 IsLeaf = false;
291 }
292 }
293 }
294 }
295
296 // Sort each call list by the source location.
297 for (auto &[CallerGUID, CallList] : Calls) {
298 llvm::sort(CallList);
299 CallList.erase(llvm::unique(CallList), CallList.end());
300 }
301
302 return Calls;
303}
304
307 const TargetLibraryInfo &TLI) {
309
311 MemProfReader->getMemProfCallerCalleePairs();
313 extractCallsFromIR(M, TLI, [&](uint64_t GUID) {
314 return CallsFromProfile.contains(GUID);
315 });
316
317 // Compute an undrift map for each CallerGUID.
318 for (const auto &[CallerGUID, IRAnchors] : CallsFromIR) {
319 auto It = CallsFromProfile.find(CallerGUID);
320 if (It == CallsFromProfile.end())
321 continue;
322 const auto &ProfileAnchors = It->second;
323
324 LocToLocMap Matchings;
326 ProfileAnchors, IRAnchors, std::equal_to<GlobalValue::GUID>(),
327 [&](LineLocation A, LineLocation B) { Matchings.try_emplace(A, B); });
328 [[maybe_unused]] bool Inserted =
329 UndriftMaps.try_emplace(CallerGUID, std::move(Matchings)).second;
330
331 // The insertion must succeed because we visit each GUID exactly once.
332 assert(Inserted);
333 }
334
335 return UndriftMaps;
336}
337
338// Given a MemProfRecord, undrift all the source locations present in the
339// record in place.
340static void
342 memprof::MemProfRecord &MemProfRec) {
343 // Undrift a call stack in place.
344 auto UndriftCallStack = [&](std::vector<Frame> &CallStack) {
345 for (auto &F : CallStack) {
346 auto I = UndriftMaps.find(F.Function);
347 if (I == UndriftMaps.end())
348 continue;
349 auto J = I->second.find(LineLocation(F.LineOffset, F.Column));
350 if (J == I->second.end())
351 continue;
352 auto &NewLoc = J->second;
353 F.LineOffset = NewLoc.LineOffset;
354 F.Column = NewLoc.Column;
355 }
356 };
357
358 for (auto &AS : MemProfRec.AllocSites)
359 UndriftCallStack(AS.CallStack);
360
361 for (auto &CS : MemProfRec.CallSites)
362 UndriftCallStack(CS.Frames);
363}
364
365// Helper function to process CalleeGuids and create value profile metadata
367 ArrayRef<GlobalValue::GUID> CalleeGuids) {
368 if (!ClMemProfAttachCalleeGuids || CalleeGuids.empty())
369 return;
370
371 if (I.getMetadata(LLVMContext::MD_prof)) {
372 uint64_t Unused;
373 // TODO: When merging is implemented, increase this to a typical ICP value
374 // (e.g., 3-6) For now, we only need to check if existing data exists, so 1
375 // is sufficient
376 auto ExistingVD = getValueProfDataFromInst(I, IPVK_IndirectCallTarget,
377 /*MaxNumValueData=*/1, Unused);
378 // We don't know how to merge value profile data yet.
379 if (!ExistingVD.empty()) {
380 return;
381 }
382 }
383
385 uint64_t TotalCount = 0;
386
387 for (const GlobalValue::GUID CalleeGUID : CalleeGuids) {
388 InstrProfValueData VD;
389 VD.Value = CalleeGUID;
390 // For MemProf, we don't have actual call counts, so we assign
391 // a weight of 1 to each potential target.
392 // TODO: Consider making this weight configurable or increasing it to
393 // improve effectiveness for ICP.
394 VD.Count = 1;
395 VDs.push_back(VD);
396 TotalCount += VD.Count;
397 }
398
399 if (!VDs.empty()) {
400 annotateValueSite(M, I, VDs, TotalCount, IPVK_IndirectCallTarget,
401 VDs.size());
402 }
403}
404
405static void
407 ArrayRef<uint64_t> InlinedCallStack, LLVMContext &Ctx,
408 OptimizationRemarkEmitter &ORE, uint64_t MaxColdSize,
409 const std::set<const AllocationInfo *> &AllocInfoSet,
410 std::map<std::pair<uint64_t, unsigned>, AllocMatchInfo>
411 &FullStackIdToAllocMatchInfo) {
412 // TODO: Remove this once the profile creation logic deduplicates contexts
413 // that are the same other than the IsInlineFrame bool. Until then, keep the
414 // largest.
415 DenseMap<uint64_t, const AllocationInfo *> UniqueFullContextIdAllocInfo;
416 for (auto *AllocInfo : AllocInfoSet) {
417 auto FullStackId = computeFullStackId(AllocInfo->CallStack);
418 auto [It, Inserted] =
419 UniqueFullContextIdAllocInfo.insert({FullStackId, AllocInfo});
420 // If inserted entry, done.
421 if (Inserted)
422 continue;
423 // Keep the larger one, or the noncold one if they are the same size.
424 auto CurSize = It->second->Info.getTotalSize();
425 auto NewSize = AllocInfo->Info.getTotalSize();
426 if ((CurSize > NewSize) ||
427 (CurSize == NewSize &&
429 continue;
430 It->second = AllocInfo;
431 }
432 // We may match this instruction's location list to multiple MIB
433 // contexts. Add them to a Trie specialized for trimming the contexts to
434 // the minimal needed to disambiguate contexts with unique behavior.
435 CallStackTrie AllocTrie(&ORE, MaxColdSize);
436 uint64_t TotalSize = 0;
437 uint64_t TotalColdSize = 0;
438 for (auto &[FullStackId, AllocInfo] : UniqueFullContextIdAllocInfo) {
439 // Check the full inlined call stack against this one.
440 // If we found and thus matched all frames on the call, include
441 // this MIB.
443 InlinedCallStack)) {
444 NumOfMemProfMatchedAllocContexts++;
445 auto AllocType = addCallStack(AllocTrie, AllocInfo, FullStackId);
446 TotalSize += AllocInfo->Info.getTotalSize();
448 TotalColdSize += AllocInfo->Info.getTotalSize();
449 // Record information about the allocation if match info printing
450 // was requested.
452 assert(FullStackId != 0);
453 FullStackIdToAllocMatchInfo[std::make_pair(FullStackId,
454 InlinedCallStack.size())] = {
455 AllocInfo->Info.getTotalSize(), AllocType};
456 }
457 }
458 }
459 // If the threshold for the percent of cold bytes is less than 100%,
460 // and not all bytes are cold, see if we should still hint this
461 // allocation as cold without context sensitivity.
462 if (TotalColdSize < TotalSize && MinMatchedColdBytePercent < 100 &&
463 TotalColdSize * 100 >= MinMatchedColdBytePercent * TotalSize) {
464 AllocTrie.addSingleAllocTypeAttribute(CI, AllocationType::Cold, "dominant");
465 return;
466 }
467
468 // We might not have matched any to the full inlined call stack.
469 // But if we did, create and attach metadata, or a function attribute if
470 // all contexts have identical profiled behavior.
471 if (!AllocTrie.empty()) {
472 NumOfMemProfMatchedAllocs++;
473 // MemprofMDAttached will be false if a function attribute was
474 // attached.
475 bool MemprofMDAttached = AllocTrie.buildAndAttachMIBMetadata(CI);
476 assert(MemprofMDAttached == I.hasMetadata(LLVMContext::MD_memprof));
477 if (MemprofMDAttached) {
478 // Add callsite metadata for the instruction's location list so that
479 // it simpler later on to identify which part of the MIB contexts
480 // are from this particular instruction (including during inlining,
481 // when the callsite metadata will be updated appropriately).
482 // FIXME: can this be changed to strip out the matching stack
483 // context ids from the MIB contexts and not add any callsite
484 // metadata here to save space?
485 addCallsiteMetadata(I, InlinedCallStack, Ctx);
486 }
487 }
488}
489
490// Helper struct for maintaining refs to callsite data. As an alternative we
491// could store a pointer to the CallSiteInfo struct but we also need the frame
492// index. Using ArrayRefs instead makes it a little easier to read.
494 // Subset of frames for the corresponding CallSiteInfo.
496 // Potential targets for indirect calls.
498
499 // Only compare Frame contents.
500 // Use pointer-based equality instead of ArrayRef's operator== which does
501 // element-wise comparison. We want to check if it's the same slice of the
502 // underlying array, not just equivalent content.
503 bool operator==(const CallSiteEntry &Other) const {
504 return Frames.data() == Other.Frames.data() &&
505 Frames.size() == Other.Frames.size();
506 }
507};
508
510 size_t operator()(const CallSiteEntry &Entry) const {
511 return computeFullStackId(Entry.Frames);
512 }
513};
514
515static void handleCallSite(
516 Instruction &I, const Function *CalledFunction,
517 ArrayRef<uint64_t> InlinedCallStack,
518 const std::unordered_set<CallSiteEntry, CallSiteEntryHash> &CallSiteEntries,
519 Module &M, std::set<std::vector<uint64_t>> &MatchedCallSites) {
520 auto &Ctx = M.getContext();
521 for (const auto &CallSiteEntry : CallSiteEntries) {
522 // If we found and thus matched all frames on the call, create and
523 // attach call stack metadata.
525 InlinedCallStack)) {
526 NumOfMemProfMatchedCallSites++;
527 addCallsiteMetadata(I, InlinedCallStack, Ctx);
528
529 // Try to attach indirect call metadata if possible.
530 if (!CalledFunction)
532
533 // Only need to find one with a matching call stack and add a single
534 // callsite metadata.
535
536 // Accumulate call site matching information upon request.
538 std::vector<uint64_t> CallStack;
539 append_range(CallStack, InlinedCallStack);
540 MatchedCallSites.insert(std::move(CallStack));
541 }
542 break;
543 }
544 }
545}
546
547static void readMemprof(Module &M, Function &F,
549 const TargetLibraryInfo &TLI,
550 std::map<std::pair<uint64_t, unsigned>, AllocMatchInfo>
551 &FullStackIdToAllocMatchInfo,
552 std::set<std::vector<uint64_t>> &MatchedCallSites,
554 OptimizationRemarkEmitter &ORE, uint64_t MaxColdSize) {
555 auto &Ctx = M.getContext();
556 // Previously we used getIRPGOFuncName() here. If F is local linkage,
557 // getIRPGOFuncName() returns FuncName with prefix 'FileName;'. But
558 // llvm-profdata uses FuncName in dwarf to create GUID which doesn't
559 // contain FileName's prefix. It caused local linkage function can't
560 // find MemProfRecord. So we use getName() now.
561 // 'unique-internal-linkage-names' can make MemProf work better for local
562 // linkage function.
563 auto FuncName = F.getName();
564 auto FuncGUID = Function::getGUIDAssumingExternalLinkage(FuncName);
565 std::optional<memprof::MemProfRecord> MemProfRec;
566 auto Err = MemProfReader->getMemProfRecord(FuncGUID).moveInto(MemProfRec);
567 if (Err) {
568 handleAllErrors(std::move(Err), [&](const InstrProfError &IPE) {
569 auto Err = IPE.get();
570 bool SkipWarning = false;
571 LLVM_DEBUG(dbgs() << "Error in reading profile for Func " << FuncName
572 << ": ");
574 NumOfMemProfMissing++;
575 SkipWarning = !PGOWarnMissing;
576 LLVM_DEBUG(dbgs() << "unknown function");
577 } else if (Err == instrprof_error::hash_mismatch) {
578 NumOfMemProfMismatch++;
579 SkipWarning =
582 (F.hasComdat() ||
584 LLVM_DEBUG(dbgs() << "hash mismatch (skip=" << SkipWarning << ")");
585 }
586
587 if (SkipWarning)
588 return;
589
590 std::string Msg = (IPE.message() + Twine(" ") + F.getName().str() +
591 Twine(" Hash = ") + std::to_string(FuncGUID))
592 .str();
593
594 Ctx.diagnose(
595 DiagnosticInfoPGOProfile(M.getName().data(), Msg, DS_Warning));
596 });
597 return;
598 }
599
600 NumOfMemProfFunc++;
601
602 // If requested, undrfit MemProfRecord so that the source locations in it
603 // match those in the IR.
605 undriftMemProfRecord(UndriftMaps, *MemProfRec);
606
607 // Detect if there are non-zero column numbers in the profile. If not,
608 // treat all column numbers as 0 when matching (i.e. ignore any non-zero
609 // columns in the IR). The profiled binary might have been built with
610 // column numbers disabled, for example.
611 bool ProfileHasColumns = false;
612
613 // Build maps of the location hash to all profile data with that leaf location
614 // (allocation info and the callsites).
615 std::map<uint64_t, std::set<const AllocationInfo *>> LocHashToAllocInfo;
616
617 // For the callsites we need to record slices of the frame array (see comments
618 // below where the map entries are added) along with their CalleeGuids.
619 std::map<uint64_t, std::unordered_set<CallSiteEntry, CallSiteEntryHash>>
620 LocHashToCallSites;
621 for (auto &AI : MemProfRec->AllocSites) {
622 NumOfMemProfAllocContextProfiles++;
623 // Associate the allocation info with the leaf frame. The later matching
624 // code will match any inlined call sequences in the IR with a longer prefix
625 // of call stack frames.
626 uint64_t StackId = computeStackId(AI.CallStack[0]);
627 LocHashToAllocInfo[StackId].insert(&AI);
628 ProfileHasColumns |= AI.CallStack[0].Column;
629 }
630 for (auto &CS : MemProfRec->CallSites) {
631 NumOfMemProfCallSiteProfiles++;
632 // Need to record all frames from leaf up to and including this function,
633 // as any of these may or may not have been inlined at this point.
634 unsigned Idx = 0;
635 for (auto &StackFrame : CS.Frames) {
636 uint64_t StackId = computeStackId(StackFrame);
637 ArrayRef<Frame> FrameSlice = ArrayRef<Frame>(CS.Frames).drop_front(Idx++);
638 ArrayRef<GlobalValue::GUID> CalleeGuids(CS.CalleeGuids);
639 LocHashToCallSites[StackId].insert({FrameSlice, CalleeGuids});
640
641 ProfileHasColumns |= StackFrame.Column;
642 // Once we find this function, we can stop recording.
643 if (StackFrame.Function == FuncGUID)
644 break;
645 }
646 assert(Idx <= CS.Frames.size() && CS.Frames[Idx - 1].Function == FuncGUID);
647 }
648
649 auto GetOffset = [](const DILocation *DIL) {
650 return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) &
651 0xffff;
652 };
653
654 // Now walk the instructions, looking up the associated profile data using
655 // debug locations.
656 for (auto &BB : F) {
657 for (auto &I : BB) {
658 if (I.isDebugOrPseudoInst())
659 continue;
660 // We are only interested in calls (allocation or interior call stack
661 // context calls).
662 auto *CI = dyn_cast<CallBase>(&I);
663 if (!CI)
664 continue;
665 auto *CalledFunction = CI->getCalledFunction();
666 if (CalledFunction && CalledFunction->isIntrinsic())
667 continue;
668 // List of call stack ids computed from the location hashes on debug
669 // locations (leaf to inlined at root).
670 SmallVector<uint64_t, 8> InlinedCallStack;
671 // Was the leaf location found in one of the profile maps?
672 bool LeafFound = false;
673 // If leaf was found in a map, iterators pointing to its location in both
674 // of the maps. It might exist in neither, one, or both (the latter case
675 // can happen because we don't currently have discriminators to
676 // distinguish the case when a single line/col maps to both an allocation
677 // and another callsite).
678 auto AllocInfoIter = LocHashToAllocInfo.end();
679 auto CallSitesIter = LocHashToCallSites.end();
680 for (const DILocation *DIL = I.getDebugLoc(); DIL != nullptr;
681 DIL = DIL->getInlinedAt()) {
682 // Use C++ linkage name if possible. Need to compile with
683 // -fdebug-info-for-profiling to get linkage name.
684 StringRef Name = DIL->getScope()->getSubprogram()->getLinkageName();
685 if (Name.empty())
686 Name = DIL->getScope()->getSubprogram()->getName();
687 auto CalleeGUID = Function::getGUIDAssumingExternalLinkage(Name);
688 auto StackId = computeStackId(CalleeGUID, GetOffset(DIL),
689 ProfileHasColumns ? DIL->getColumn() : 0);
690 // Check if we have found the profile's leaf frame. If yes, collect
691 // the rest of the call's inlined context starting here. If not, see if
692 // we find a match further up the inlined context (in case the profile
693 // was missing debug frames at the leaf).
694 if (!LeafFound) {
695 AllocInfoIter = LocHashToAllocInfo.find(StackId);
696 CallSitesIter = LocHashToCallSites.find(StackId);
697 if (AllocInfoIter != LocHashToAllocInfo.end() ||
698 CallSitesIter != LocHashToCallSites.end())
699 LeafFound = true;
700 }
701 if (LeafFound)
702 InlinedCallStack.push_back(StackId);
703 }
704 // If leaf not in either of the maps, skip inst.
705 if (!LeafFound)
706 continue;
707
708 // First add !memprof metadata from allocation info, if we found the
709 // instruction's leaf location in that map, and if the rest of the
710 // instruction's locations match the prefix Frame locations on an
711 // allocation context with the same leaf.
712 if (AllocInfoIter != LocHashToAllocInfo.end() &&
713 // Only consider allocations which support hinting.
714 isAllocationWithHotColdVariant(CI->getCalledFunction(), TLI))
715 handleAllocSite(I, CI, InlinedCallStack, Ctx, ORE, MaxColdSize,
716 AllocInfoIter->second, FullStackIdToAllocMatchInfo);
717 else if (CallSitesIter != LocHashToCallSites.end())
718 // Otherwise, add callsite metadata. If we reach here then we found the
719 // instruction's leaf location in the callsites map and not the
720 // allocation map.
721 handleCallSite(I, CalledFunction, InlinedCallStack,
722 CallSitesIter->second, M, MatchedCallSites);
723 }
724 }
725}
726
727MemProfUsePass::MemProfUsePass(std::string MemoryProfileFile,
729 : MemoryProfileFileName(MemoryProfileFile), FS(FS) {
730 if (!FS)
731 this->FS = vfs::getRealFileSystem();
732}
733
735 // Return immediately if the module doesn't contain any function or global
736 // variables.
737 if (M.empty() && M.globals().empty())
738 return PreservedAnalyses::all();
739
740 LLVM_DEBUG(dbgs() << "Read in memory profile:\n");
741 auto &Ctx = M.getContext();
742 auto ReaderOrErr = IndexedInstrProfReader::create(MemoryProfileFileName, *FS);
743 if (Error E = ReaderOrErr.takeError()) {
744 handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
745 Ctx.diagnose(
746 DiagnosticInfoPGOProfile(MemoryProfileFileName.data(), EI.message()));
747 });
748 return PreservedAnalyses::all();
749 }
750
751 std::unique_ptr<IndexedInstrProfReader> MemProfReader =
752 std::move(ReaderOrErr.get());
753 if (!MemProfReader) {
754 Ctx.diagnose(DiagnosticInfoPGOProfile(
755 MemoryProfileFileName.data(), StringRef("Cannot get MemProfReader")));
756 return PreservedAnalyses::all();
757 }
758
759 if (!MemProfReader->hasMemoryProfile()) {
760 Ctx.diagnose(DiagnosticInfoPGOProfile(MemoryProfileFileName.data(),
761 "Not a memory profile"));
762 return PreservedAnalyses::all();
763 }
764
765 const bool Changed =
766 annotateGlobalVariables(M, MemProfReader->getDataAccessProfileData());
767
768 // If the module doesn't contain any function, return after we process all
769 // global variables.
770 if (M.empty())
772
773 auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
774
775 TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(*M.begin());
778 UndriftMaps = computeUndriftMap(M, MemProfReader.get(), TLI);
779
780 // Map from the stack hash and matched frame count of each allocation context
781 // in the function profiles to the total profiled size (bytes) and allocation
782 // type.
783 std::map<std::pair<uint64_t, unsigned>, AllocMatchInfo>
784 FullStackIdToAllocMatchInfo;
785
786 // Set of the matched call sites, each expressed as a sequence of an inline
787 // call stack.
788 std::set<std::vector<uint64_t>> MatchedCallSites;
789
790 uint64_t MaxColdSize = 0;
791 if (auto *MemProfSum = MemProfReader->getMemProfSummary())
792 MaxColdSize = MemProfSum->getMaxColdTotalSize();
793
794 for (auto &F : M) {
795 if (F.isDeclaration())
796 continue;
797
798 const TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
799 auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
800 readMemprof(M, F, MemProfReader.get(), TLI, FullStackIdToAllocMatchInfo,
801 MatchedCallSites, UndriftMaps, ORE, MaxColdSize);
802 }
803
805 for (const auto &[IdLengthPair, Info] : FullStackIdToAllocMatchInfo) {
806 auto [Id, Length] = IdLengthPair;
807 errs() << "MemProf " << getAllocTypeAttributeString(Info.AllocType)
808 << " context with id " << Id << " has total profiled size "
809 << Info.TotalSize << " is matched with " << Length << " frames\n";
810 }
811
812 for (const auto &CallStack : MatchedCallSites) {
813 errs() << "MemProf callsite match for inline call stack";
814 for (uint64_t StackId : CallStack)
815 errs() << " " << StackId;
816 errs() << "\n";
817 }
818 }
819
821}
822
823bool MemProfUsePass::annotateGlobalVariables(
824 Module &M, const memprof::DataAccessProfData *DataAccessProf) {
825 if (!AnnotateStaticDataSectionPrefix || M.globals().empty())
826 return false;
827
828 if (!DataAccessProf) {
829 M.addModuleFlag(Module::Warning, "EnableDataAccessProf", 0U);
830 M.getContext().diagnose(DiagnosticInfoPGOProfile(
831 MemoryProfileFileName.data(),
832 StringRef("Data access profiles not found in memprof. Ignore "
833 "-memprof-annotate-static-data-prefix."),
834 DS_Warning));
835 return false;
836 }
837 M.addModuleFlag(Module::Warning, "EnableDataAccessProf", 1U);
838
839 bool Changed = false;
840 // Iterate all global variables in the module and annotate them based on
841 // data access profiles. Note it's up to the linker to decide how to map input
842 // sections to output sections, and one conservative practice is to map
843 // unlikely-prefixed ones to unlikely output section, and map the rest
844 // (hot-prefixed or prefix-less) to the canonical output section.
845 for (GlobalVariable &GVar : M.globals()) {
846 assert(!GVar.getSectionPrefix().has_value() &&
847 "GVar shouldn't have section prefix yet");
848 auto Kind = llvm::memprof::getAnnotationKind(GVar);
851 continue;
852 }
853
854 StringRef Name = GVar.getName();
855 // Skip string literals as their mangled names don't stay stable across
856 // binary releases.
857 // TODO: Track string content hash in the profiles and compute it inside the
858 // compiler to categeorize the hotness string literals.
859 if (Name.starts_with(".str")) {
860 LLVM_DEBUG(dbgs() << "Skip annotating string literal " << Name << "\n");
861 continue;
862 }
863
864 // DataAccessProfRecord's get* methods will canonicalize the name under the
865 // hood before looking it up, so optimizer doesn't need to do it.
866 std::optional<DataAccessProfRecord> Record =
867 DataAccessProf->getProfileRecord(Name);
868 // Annotate a global variable as hot if it has non-zero sampled count, and
869 // annotate it as cold if it's seen in the profiled binary
870 // file but doesn't have any access sample.
871 // For logging, optimization remark emitter requires a llvm::Function, but
872 // it's not well defined how to associate a global variable with a function.
873 // So we just print out the static data section prefix in LLVM_DEBUG.
874 if (Record && Record->AccessCount > 0) {
875 ++NumOfMemProfHotGlobalVars;
876 Changed |= GVar.setSectionPrefix("hot");
877 LLVM_DEBUG(dbgs() << "Global variable " << Name
878 << " is annotated as hot\n");
879 } else if (DataAccessProf->isKnownColdSymbol(Name)) {
880 ++NumOfMemProfColdGlobalVars;
881 Changed |= GVar.setSectionPrefix("unlikely");
882 Changed = true;
883 LLVM_DEBUG(dbgs() << "Global variable " << Name
884 << " is annotated as unlikely\n");
885 } else {
886 ++NumOfMemProfUnknownGlobalVars;
887 LLVM_DEBUG(dbgs() << "Global variable " << Name << " is not annotated\n");
888 }
889 }
890
891 return Changed;
892}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:55
#define I(x, y, z)
Definition MD5.cpp:58
static void handleCallSite(Instruction &I, const Function *CalledFunction, ArrayRef< uint64_t > InlinedCallStack, const std::unordered_set< CallSiteEntry, CallSiteEntryHash > &CallSiteEntries, Module &M, std::set< std::vector< uint64_t > > &MatchedCallSites)
static void addCallsiteMetadata(Instruction &I, ArrayRef< uint64_t > InlinedCallStack, LLVMContext &Ctx)
static bool isAllocationWithHotColdVariant(const Function *Callee, const TargetLibraryInfo &TLI)
static cl::opt< bool > ClMemProfAttachCalleeGuids("memprof-attach-calleeguids", cl::desc("Attach calleeguids as value profile metadata for indirect calls."), cl::init(true), cl::Hidden)
static void HandleUnsupportedAnnotationKinds(GlobalVariable &GVar, AnnotationKind Kind)
static void undriftMemProfRecord(const DenseMap< uint64_t, LocToLocMap > &UndriftMaps, memprof::MemProfRecord &MemProfRec)
static uint64_t computeStackId(GlobalValue::GUID Function, uint32_t LineOffset, uint32_t Column)
static cl::opt< bool > ClPrintMemProfMatchInfo("memprof-print-match-info", cl::desc("Print matching stats for each allocation " "context in this module's profiles"), cl::Hidden, cl::init(false))
static void addVPMetadata(Module &M, Instruction &I, ArrayRef< GlobalValue::GUID > CalleeGuids)
static cl::opt< bool > AnnotateStaticDataSectionPrefix("memprof-annotate-static-data-prefix", cl::init(false), cl::Hidden, cl::desc("If true, annotate the static data section prefix"))
static cl::opt< bool > SalvageStaleProfile("memprof-salvage-stale-profile", cl::desc("Salvage stale MemProf profile"), cl::init(false), cl::Hidden)
static cl::opt< unsigned > MinMatchedColdBytePercent("memprof-matching-cold-threshold", cl::init(100), cl::Hidden, cl::desc("Min percent of cold bytes matched to hint allocation cold"))
static cl::opt< bool > ClMemProfMatchHotColdNew("memprof-match-hot-cold-new", cl::desc("Match allocation profiles onto existing hot/cold operator new calls"), cl::Hidden, cl::init(false))
static AllocationType addCallStack(CallStackTrie &AllocTrie, const AllocationInfo *AllocInfo, uint64_t FullStackId)
static void readMemprof(Module &M, Function &F, IndexedInstrProfReader *MemProfReader, const TargetLibraryInfo &TLI, std::map< std::pair< uint64_t, unsigned >, AllocMatchInfo > &FullStackIdToAllocMatchInfo, std::set< std::vector< uint64_t > > &MatchedCallSites, DenseMap< uint64_t, LocToLocMap > &UndriftMaps, OptimizationRemarkEmitter &ORE, uint64_t MaxColdSize)
static void handleAllocSite(Instruction &I, CallBase *CI, ArrayRef< uint64_t > InlinedCallStack, LLVMContext &Ctx, OptimizationRemarkEmitter &ORE, uint64_t MaxColdSize, const std::set< const AllocationInfo * > &AllocInfoSet, std::map< std::pair< uint64_t, unsigned >, AllocMatchInfo > &FullStackIdToAllocMatchInfo)
static bool stackFrameIncludesInlinedCallStack(ArrayRef< Frame > ProfileCallStack, ArrayRef< uint64_t > InlinedCallStack)
AllocType
FunctionAnalysisManager FAM
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:114
Defines the virtual file system interface vfs::FileSystem.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
ArrayRef< T > take_front(size_t N=1) const
Return a copy of *this with only the first N elements.
Definition ArrayRef.h:220
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition ArrayRef.h:196
size_t size() const
size - Get the array size.
Definition ArrayRef.h:143
bool empty() const
empty - Check if the array is empty.
Definition ArrayRef.h:138
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:178
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:248
iterator end()
Definition DenseMap.h:81
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition DenseMap.h:169
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:233
Diagnostic information for the PGO profiler.
Base class for error info classes.
Definition Error.h:44
virtual std::string message() const
Return the error message as a string.
Definition Error.h:52
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
Definition Globals.cpp:77
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
@ AvailableExternallyLinkage
Available for inspection, not emission.
Definition GlobalValue.h:54
HashResultTy< HasherT_ > final()
Forward to HasherT::final() if available.
Definition HashBuilder.h:64
Interface to help hash various types through a hasher type.
std::enable_if_t< hashbuilder_detail::IsHashableData< T >::value, HashBuilder & > add(T Value)
Implement hashing for hashable data types, e.g. integral or enum values.
Reader for the indexed binary instrprof format.
static Expected< std::unique_ptr< IndexedInstrProfReader > > create(const Twine &Path, vfs::FileSystem &FS, const Twine &RemappingPath="")
Factory method to create an indexed reader.
instrprof_error get() const
Definition InstrProf.h:465
std::string message() const override
Return the error message as a string.
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
LLVM_ABI MemProfUsePass(std::string MemoryProfileFile, IntrusiveRefCntPtr< vfs::FileSystem > FS=nullptr)
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
@ Warning
Emits a warning if two values disagree.
Definition Module.h:124
The optimization diagnostic interface.
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
void append(StringRef RHS)
Append from a StringRef.
Definition SmallString.h:68
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:143
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
bool getLibFunc(StringRef funcName, LibFunc &F) const
Searches for a particular function name.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:314
An efficient, type-erasing, non-owning reference to a callable.
Class to build a trie of call stack contexts for a particular profiled allocation call,...
LLVM_ABI void addCallStack(AllocationType AllocType, ArrayRef< uint64_t > StackIds, std::vector< ContextTotalSize > ContextSizeInfo={})
Add a call stack context with the given allocation type to the Trie.
LLVM_ABI void addSingleAllocTypeAttribute(CallBase *CI, AllocationType AT, StringRef Descriptor)
Add an attribute for the given allocation type to the call instruction.
LLVM_ABI bool buildAndAttachMIBMetadata(CallBase *CI)
Build and attach the minimal necessary MIB metadata.
Helper class to iterate through stack ids in both metadata (memprof MIB and callsite) and the corresp...
Encapsulates the data access profile data and the methods to operate on it.
LLVM_ABI std::optional< DataAccessProfRecord > getProfileRecord(const SymbolHandleRef SymID) const
Returns a profile record for SymbolID, or std::nullopt if there isn't a record.
LLVM_ABI bool isKnownColdSymbol(const SymbolHandleRef SymID) const
Returns true if SymID is seen in profiled binaries and cold.
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
LLVM_ABI DenseMap< uint64_t, LocToLocMap > computeUndriftMap(Module &M, IndexedInstrProfReader *MemProfReader, const TargetLibraryInfo &TLI)
LLVM_ABI MDNode * buildCallstackMetadata(ArrayRef< uint64_t > CallStack, LLVMContext &Ctx)
Build callstack metadata from the provided list of call stack ids.
LLVM_ABI AllocationType getAllocType(uint64_t TotalLifetimeAccessDensity, uint64_t AllocCount, uint64_t TotalLifetime)
Return the allocation type for a given set of memory profile values.
LLVM_ABI bool recordContextSizeInfoForAnalysis()
Whether we need to record the context size info in the alloc trie used to build metadata.
std::unordered_map< LineLocation, LineLocation, LineLocationHash > LocToLocMap
Definition MemProfUse.h:65
LLVM_ABI uint64_t computeFullStackId(ArrayRef< Frame > CallStack)
Helper to generate a single hash id for a given callstack, used for emitting matching statistics and ...
LLVM_ABI DenseMap< uint64_t, SmallVector< CallEdgeTy, 0 > > extractCallsFromIR(Module &M, const TargetLibraryInfo &TLI, function_ref< bool(uint64_t)> IsPresentInProfile=[](uint64_t) { return true;})
AnnotationKind getAnnotationKind(const GlobalVariable &GV)
Returns the annotation kind of the global variable GV.
LLVM_ABI GlobalValue::GUID getGUID(const StringRef FunctionName)
Definition MemProf.cpp:344
LLVM_ABI std::string getAllocTypeAttributeString(AllocationType Type)
Returns the string to use in attributes with the given type.
LLVM_ABI IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
This is an optimization pass for GlobalISel generic memory operations.
@ Length
Definition DWP.cpp:477
std::array< uint8_t, NumBytes > BLAKE3Result
The constant LLVM_BLAKE3_OUT_LEN provides the default output length, 32 bytes, which is recommended f...
Definition BLAKE3.h:35
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition Error.h:990
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2136
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
cl::opt< bool > PGOWarnMissing
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2076
LLVM_ABI void annotateValueSite(Module &M, Instruction &Inst, const InstrProfRecord &InstrProfR, InstrProfValueKind ValueKind, uint32_t SiteIndx, uint32_t MaxMDCount=3)
Get the value profile data for value site SiteIdx from InstrProfR and annotate the instruction Inst w...
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1622
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
LLVM_ABI SmallVector< InstrProfValueData, 4 > getValueProfDataFromInst(const Instruction &Inst, InstrProfValueKind ValueKind, uint32_t MaxNumValueData, uint64_t &TotalC, bool GetNoICPValue=false)
Extract the value profile data from Inst and returns them if Inst is annotated with value profile dat...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
cl::opt< bool > NoPGOWarnMismatch
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
@ Other
Any other memory.
Definition ModRef.h:68
cl::opt< bool > SalvageStaleProfile("salvage-stale-profile", cl::Hidden, cl::init(false), cl::desc("Salvage stale profile by fuzzy matching and use the remapped " "location for sample profile query."))
void longestCommonSequence(AnchorList AnchorList1, AnchorList AnchorList2, llvm::function_ref< bool(const Function &, const Function &)> FunctionMatchesProfile, llvm::function_ref< void(Loc, Loc)> InsertMatching)
ArrayRef(const T &OneElt) -> ArrayRef< T >
bool equal(L &&LRange, R &&RRange)
Wrapper function around std::equal to detect if pair-wise elements between two ranges are the same.
Definition STLExtras.h:2088
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
cl::opt< bool > NoPGOWarnMismatchComdatWeak
uint64_t TotalSize
AllocationType AllocType
size_t operator()(const CallSiteEntry &Entry) const
ArrayRef< GlobalValue::GUID > CalleeGuids
bool operator==(const CallSiteEntry &Other) const
ArrayRef< Frame > Frames
Summary of memprof metadata on allocations.
GlobalValue::GUID Function
Definition MemProf.h:245
uint32_t LineOffset
Definition MemProf.h:250
llvm::SmallVector< CallSiteInfo > CallSites
Definition MemProf.h:522
llvm::SmallVector< AllocationInfo > AllocSites
Definition MemProf.h:520