LLVM 24.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
15#include "llvm/ADT/DenseSet.h"
17#include "llvm/ADT/Statistic.h"
18#include "llvm/ADT/StringRef.h"
24#include "llvm/IR/Function.h"
26#include "llvm/IR/Module.h"
31#include "llvm/Support/BLAKE3.h"
33#include "llvm/Support/Debug.h"
35#include "llvm/Support/MD5.h"
38#include <map>
39#include <set>
40
41using namespace llvm;
42using namespace llvm::memprof;
43
44#define DEBUG_TYPE "memprof"
45
46namespace llvm {
51} // namespace llvm
52
53// By default disable matching of allocation profiles onto operator new that
54// already explicitly pass a hot/cold hint, since we don't currently
55// override these hints anyway.
57 "memprof-match-hot-cold-new",
59 "Match allocation profiles onto existing hot/cold operator new calls"),
60 cl::Hidden, cl::init(false));
61
62static cl::opt<bool>
63 ClPrintMemProfMatchInfo("memprof-print-match-info",
64 cl::desc("Print matching stats for each allocation "
65 "context in this module's profiles"),
66 cl::Hidden, cl::init(false));
67
69 "memprof-print-matched-alloc-stack",
70 cl::desc("Print full stack context for matched "
71 "allocations with -memprof-print-match-info."),
72 cl::Hidden, cl::init(false));
73
74static cl::opt<bool>
75 PrintFunctionGuids("memprof-print-function-guids",
76 cl::desc("Print function GUIDs computed for matching"),
77 cl::Hidden, cl::init(false));
78
79static cl::opt<bool>
80 SalvageStaleProfile("memprof-salvage-stale-profile",
81 cl::desc("Salvage stale MemProf profile"),
82 cl::init(false), cl::Hidden);
83
85 "memprof-attach-calleeguids",
87 "Attach calleeguids as value profile metadata for indirect calls."),
88 cl::init(true), cl::Hidden);
89
91 "memprof-matching-cold-threshold", cl::init(100), cl::Hidden,
92 cl::desc("Min percent of cold bytes matched to hint allocation cold"));
93
95 "memprof-annotate-static-data-prefix", cl::init(false), cl::Hidden,
96 cl::desc("If true, annotate the static data section prefix"));
97
98// Matching statistics
99STATISTIC(NumOfMemProfMissing, "Number of functions without memory profile.");
100STATISTIC(NumOfMemProfMismatch,
101 "Number of functions having mismatched memory profile hash.");
102STATISTIC(NumOfMemProfFunc, "Number of functions having valid memory profile.");
103STATISTIC(NumOfMemProfAllocContextProfiles,
104 "Number of alloc contexts in memory profile.");
105STATISTIC(NumOfMemProfCallSiteProfiles,
106 "Number of callsites in memory profile.");
107STATISTIC(NumOfMemProfMatchedAllocContexts,
108 "Number of matched memory profile alloc contexts.");
109STATISTIC(NumOfMemProfMatchedAllocs,
110 "Number of matched memory profile allocs.");
111STATISTIC(NumOfMemProfMatchedCallSites,
112 "Number of matched memory profile callsites.");
113STATISTIC(NumOfMemProfHotGlobalVars,
114 "Number of global vars annotated with 'hot' section prefix.");
115STATISTIC(NumOfMemProfColdGlobalVars,
116 "Number of global vars annotated with 'unlikely' section prefix.");
117STATISTIC(NumOfMemProfUnknownGlobalVars,
118 "Number of global vars with unknown hotness (no section prefix).");
119STATISTIC(NumOfMemProfExplicitSectionGlobalVars,
120 "Number of global vars with user-specified section (not annotated).");
121
123 ArrayRef<uint64_t> InlinedCallStack,
124 LLVMContext &Ctx) {
125 I.setMetadata(LLVMContext::MD_callsite,
126 buildCallstackMetadata(InlinedCallStack, Ctx));
127}
128
130 uint32_t Column) {
133 HashBuilder.add(Function, LineOffset, Column);
135 uint64_t Id;
136 std::memcpy(&Id, Hash.data(), sizeof(Hash));
137 return Id;
138}
139
143
145 return getAllocType(AllocInfo->Info.getTotalLifetimeAccessDensity(),
146 AllocInfo->Info.getAllocCount(),
147 AllocInfo->Info.getTotalLifetime());
148}
149
152 uint64_t FullStackId) {
153 SmallVector<uint64_t> StackIds;
154 for (const auto &StackFrame : AllocInfo->CallStack)
155 StackIds.push_back(computeStackId(StackFrame));
157 std::vector<ContextTotalSize> ContextSizeInfo;
159 auto TotalSize = AllocInfo->Info.getTotalSize();
160 assert(TotalSize);
161 assert(FullStackId != 0);
162 ContextSizeInfo.push_back({FullStackId, TotalSize});
163 }
164 AllocTrie.addCallStack(AllocType, StackIds, std::move(ContextSizeInfo));
165 return AllocType;
166}
167
168// Return true if InlinedCallStack, computed from a call instruction's debug
169// info, is a prefix of ProfileCallStack, a list of Frames from profile data
170// (either the allocation data or a callsite).
171static bool
173 ArrayRef<uint64_t> InlinedCallStack) {
174 return ProfileCallStack.size() >= InlinedCallStack.size() &&
175 llvm::equal(ProfileCallStack.take_front(InlinedCallStack.size()),
176 InlinedCallStack, [](const Frame &F, uint64_t StackId) {
177 return computeStackId(F) == StackId;
178 });
179}
180
181static bool isAllocationWithHotColdVariant(const Function *Callee,
182 const TargetLibraryInfo &TLI) {
183 if (!Callee)
184 return false;
185 LibFunc Func = TLI.getLibFunc(*Callee);
186 if (Func == NotLibFunc)
187 return false;
188 switch (Func) {
189 case LibFunc_Znwm:
190 case LibFunc_ZnwmRKSt9nothrow_t:
191 case LibFunc_ZnwmSt11align_val_t:
192 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
193 case LibFunc_Znam:
194 case LibFunc_ZnamRKSt9nothrow_t:
195 case LibFunc_ZnamSt11align_val_t:
196 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
197 case LibFunc_size_returning_new:
198 case LibFunc_size_returning_new_aligned:
199 return true;
200 case LibFunc_Znwm12__hot_cold_t:
201 case LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t:
202 case LibFunc_ZnwmSt11align_val_t12__hot_cold_t:
203 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
204 case LibFunc_Znam12__hot_cold_t:
205 case LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t:
206 case LibFunc_ZnamSt11align_val_t12__hot_cold_t:
207 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
208 case LibFunc_size_returning_new_hot_cold:
209 case LibFunc_size_returning_new_aligned_hot_cold:
211 default:
212 return false;
213 }
214}
215
217 AnnotationKind Kind) {
219 "Should not handle AnnotationOK here");
220 SmallString<32> Reason;
221 switch (Kind) {
223 ++NumOfMemProfExplicitSectionGlobalVars;
224 Reason.append("explicit section name");
225 break;
227 Reason.append("linker declaration");
228 break;
230 Reason.append("name starts with `llvm.`");
231 break;
232 default:
233 llvm_unreachable("Unexpected annotation kind");
234 }
235 LLVM_DEBUG(dbgs() << "Skip annotation for " << GVar.getName() << " due to "
236 << Reason << ".\n");
237}
238
239// Computes the LLVM version of MD5 hash for the content of a string
240// literal.
241static std::optional<uint64_t>
243 auto *Initializer = GVar.getInitializer();
244 if (!Initializer)
245 return std::nullopt;
246 if (auto *C = dyn_cast<ConstantDataSequential>(Initializer))
247 if (C->isString()) {
248 // Note the hash computed for the literal would include the null byte.
249 return llvm::MD5Hash(C->getAsString());
250 }
251 return std::nullopt;
252}
253
254// Structure for tracking info about matched allocation contexts for use with
255// -memprof-print-match-info and -memprof-print-matched-alloc-stack.
257 // Total size in bytes of matched context.
258 uint64_t TotalSize = 0;
259 // Matched allocation's type.
261 // Number of frames matched to the allocation itself (values will be >1 in
262 // cases where allocation was already inlined). Use a set because there can
263 // be multiple inlined instances and each may have a different inline depth.
264 // Use std::set to iterate in sorted order when printing.
265 std::set<unsigned> MatchedFramesSet;
266 // The full call stack of the allocation, for cases where requested via
267 // -memprof-print-matched-alloc-stack.
268 std::vector<Frame> CallStack;
269
270 // Caller responsible for inserting the matched frames and the call stack when
271 // appropriate.
274};
275
278 function_ref<bool(uint64_t)> IsPresentInProfile) {
280
281 auto GetOffset = [](const DILocation *DIL) {
282 return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) &
283 0xffff;
284 };
285
286 for (Function &F : M) {
287 if (F.isDeclaration())
288 continue;
289
290 for (auto &BB : F) {
291 for (auto &I : BB) {
293 continue;
294
295 auto *CB = dyn_cast<CallBase>(&I);
296 auto *CalledFunction = CB->getCalledFunction();
297 // Disregard indirect calls and intrinsics.
298 if (!CalledFunction || CalledFunction->isIntrinsic())
299 continue;
300
301 StringRef CalleeName = CalledFunction->getName();
302 // True if we are calling a heap allocation function that supports
303 // hot/cold variants.
304 bool IsAlloc = isAllocationWithHotColdVariant(CalledFunction, TLI);
305 // True for the first iteration below, indicating that we are looking at
306 // a leaf node.
307 bool IsLeaf = true;
308 for (const DILocation *DIL = I.getDebugLoc(); DIL;
309 DIL = DIL->getInlinedAt()) {
310 StringRef CallerName = DIL->getSubprogramLinkageName();
311 assert(!CallerName.empty() &&
312 "Be sure to enable -fdebug-info-for-profiling");
313 uint64_t CallerGUID = memprof::getGUID(CallerName);
314 uint64_t CalleeGUID = memprof::getGUID(CalleeName);
315 // Pretend that we are calling a function with GUID == 0 if we are
316 // in the inline stack leading to a heap allocation function.
317 if (IsAlloc) {
318 if (IsLeaf) {
319 // For leaf nodes, set CalleeGUID to 0 without consulting
320 // IsPresentInProfile.
321 CalleeGUID = 0;
322 } else if (!IsPresentInProfile(CalleeGUID)) {
323 // In addition to the leaf case above, continue to set CalleeGUID
324 // to 0 as long as we don't see CalleeGUID in the profile.
325 CalleeGUID = 0;
326 } else {
327 // Once we encounter a callee that exists in the profile, stop
328 // setting CalleeGUID to 0.
329 IsAlloc = false;
330 }
331 }
332
333 LineLocation Loc = {GetOffset(DIL), DIL->getColumn()};
334 Calls[CallerGUID].emplace_back(Loc, CalleeGUID);
335 CalleeName = CallerName;
336 IsLeaf = false;
337 }
338 }
339 }
340 }
341
342 // Sort each call list by the source location.
343 for (auto &[CallerGUID, CallList] : Calls) {
344 llvm::sort(CallList);
345 CallList.erase(llvm::unique(CallList), CallList.end());
346 }
347
348 return Calls;
349}
350
353 const TargetLibraryInfo &TLI) {
355
357 MemProfReader->getMemProfCallerCalleePairs();
359 extractCallsFromIR(M, TLI, [&](uint64_t GUID) {
360 return CallsFromProfile.contains(GUID);
361 });
362
363 // Compute an undrift map for each CallerGUID.
364 for (const auto &[CallerGUID, IRAnchors] : CallsFromIR) {
365 auto It = CallsFromProfile.find(CallerGUID);
366 if (It == CallsFromProfile.end())
367 continue;
368 const auto &ProfileAnchors = It->second;
369
370 LocToLocMap Matchings;
372 ProfileAnchors, IRAnchors, std::equal_to<GlobalValue::GUID>(),
373 [&](LineLocation A, LineLocation B) { Matchings.try_emplace(A, B); });
374 [[maybe_unused]] bool Inserted =
375 UndriftMaps.try_emplace(CallerGUID, std::move(Matchings)).second;
376
377 // The insertion must succeed because we visit each GUID exactly once.
378 assert(Inserted);
379 }
380
381 return UndriftMaps;
382}
383
384// Given a MemProfRecord, undrift all the source locations present in the
385// record in place.
386static void
388 memprof::MemProfRecord &MemProfRec) {
389 // Undrift a call stack in place.
390 auto UndriftCallStack = [&](std::vector<Frame> &CallStack) {
391 for (auto &F : CallStack) {
392 auto I = UndriftMaps.find(F.Function);
393 if (I == UndriftMaps.end())
394 continue;
395 auto J = I->second.find(LineLocation(F.LineOffset, F.Column));
396 if (J == I->second.end())
397 continue;
398 auto &NewLoc = J->second;
399 F.LineOffset = NewLoc.LineOffset;
400 F.Column = NewLoc.Column;
401 }
402 };
403
404 for (auto &AS : MemProfRec.AllocSites)
405 UndriftCallStack(AS.CallStack);
406
407 for (auto &CS : MemProfRec.CallSites)
408 UndriftCallStack(CS.Frames);
409}
410
411// Helper function to process CalleeGuids and create value profile metadata
413 ArrayRef<GlobalValue::GUID> CalleeGuids) {
414 if (!ClMemProfAttachCalleeGuids || CalleeGuids.empty())
415 return;
416
417 // Prepare the vector of value data, initializing from any existing
418 // value-profile metadata present on the instruction so that we merge the
419 // new CalleeGuids into the existing entries.
421 uint64_t TotalCount = 0;
422
423 if (I.getMetadata(LLVMContext::MD_prof)) {
424 // Read all existing entries so we can merge them. Use a large
425 // MaxNumValueData to retrieve all existing entries.
426 VDs = getValueProfDataFromInst(I, IPVK_IndirectCallTarget,
427 /*MaxNumValueData=*/UINT32_MAX, TotalCount);
428 }
429
430 // Save the original size for use later in detecting whether any were added.
431 const size_t OriginalSize = VDs.size();
432
433 // Initialize the set of existing guids with the original list.
434 DenseSet<uint64_t> ExistingValues(
437 VDs, [](const InstrProfValueData &Entry) { return Entry.Value; }));
438
439 // Merge CalleeGuids into list of existing VDs, by appending any that are not
440 // already included.
441 VDs.reserve(OriginalSize + CalleeGuids.size());
442 for (auto G : CalleeGuids) {
443 if (!ExistingValues.insert(G).second)
444 continue;
445 InstrProfValueData NewEntry;
446 NewEntry.Value = G;
447 // For MemProf, we don't have actual call counts, so we assign
448 // a weight of 1 to each potential target.
449 // TODO: Consider making this weight configurable or increasing it to
450 // improve effectiveness for ICP.
451 NewEntry.Count = 1;
452 TotalCount += NewEntry.Count;
453 VDs.push_back(NewEntry);
454 }
455
456 // Update the VP metadata if we added any new callee GUIDs to the list.
457 assert(VDs.size() >= OriginalSize);
458 if (VDs.size() == OriginalSize)
459 return;
460
461 // First clear the existing !prof.
462 I.setMetadata(LLVMContext::MD_prof, nullptr);
463
464 // No need to sort the updated VDs as all appended entries have the same count
465 // of 1, which is no larger than any existing entries. The incoming list of
466 // CalleeGuids should already be deterministic for a given profile.
467 annotateValueSite(M, I, VDs, TotalCount, IPVK_IndirectCallTarget, VDs.size());
468}
469
470static void handleAllocSite(
471 Instruction &I, CallBase *CI, ArrayRef<uint64_t> InlinedCallStack,
472 LLVMContext &Ctx, OptimizationRemarkEmitter &ORE, uint64_t MaxColdSize,
473 const std::set<const AllocationInfo *> &AllocInfoSet,
474 std::map<uint64_t, AllocMatchInfo> &FullStackIdToAllocMatchInfo) {
475 // TODO: Remove this once the profile creation logic deduplicates contexts
476 // that are the same other than the IsInlineFrame bool. Until then, keep the
477 // largest.
478 DenseMap<uint64_t, const AllocationInfo *> UniqueFullContextIdAllocInfo;
479 for (auto *AllocInfo : AllocInfoSet) {
480 auto FullStackId = computeFullStackId(AllocInfo->CallStack);
481 auto [It, Inserted] =
482 UniqueFullContextIdAllocInfo.insert({FullStackId, AllocInfo});
483 // If inserted entry, done.
484 if (Inserted)
485 continue;
486 // Keep the larger one, or the noncold one if they are the same size.
487 auto CurSize = It->second->Info.getTotalSize();
488 auto NewSize = AllocInfo->Info.getTotalSize();
489 if ((CurSize > NewSize) ||
490 (CurSize == NewSize &&
492 continue;
493 It->second = AllocInfo;
494 }
495 // We may match this instruction's location list to multiple MIB
496 // contexts. Add them to a Trie specialized for trimming the contexts to
497 // the minimal needed to disambiguate contexts with unique behavior.
498 CallStackTrie AllocTrie(&ORE, MaxColdSize);
499 uint64_t TotalSize = 0;
500 uint64_t TotalColdSize = 0;
501 for (auto &[FullStackId, AllocInfo] : UniqueFullContextIdAllocInfo) {
502 // Check the full inlined call stack against this one.
503 // If we found and thus matched all frames on the call, include
504 // this MIB.
506 InlinedCallStack)) {
507 NumOfMemProfMatchedAllocContexts++;
508 auto AllocType = addCallStack(AllocTrie, AllocInfo, FullStackId);
509 TotalSize += AllocInfo->Info.getTotalSize();
511 TotalColdSize += AllocInfo->Info.getTotalSize();
512 // Record information about the allocation if match info printing
513 // was requested.
515 assert(FullStackId != 0);
516 auto [Iter, Inserted] = FullStackIdToAllocMatchInfo.try_emplace(
517 FullStackId,
518 AllocMatchInfo(AllocInfo->Info.getTotalSize(), AllocType));
519 // Always insert the new matched frame count, since it may differ.
520 Iter->second.MatchedFramesSet.insert(InlinedCallStack.size());
521 if (Inserted && PrintMatchedAllocStack)
522 Iter->second.CallStack.insert(Iter->second.CallStack.begin(),
523 AllocInfo->CallStack.begin(),
524 AllocInfo->CallStack.end());
525 }
526 ORE.emit(
527 OptimizationRemark(DEBUG_TYPE, "MemProfUse", CI)
528 << ore::NV("AllocationCall", CI) << " in function "
529 << ore::NV("Caller", CI->getFunction())
530 << " matched alloc context with alloc type "
532 << " total size " << ore::NV("Size", AllocInfo->Info.getTotalSize())
533 << " full context id " << ore::NV("Context", FullStackId)
534 << " frame count " << ore::NV("Frames", InlinedCallStack.size()));
535 }
536 }
537 // If the threshold for the percent of cold bytes is less than 100%,
538 // and not all bytes are cold, see if we should still hint this
539 // allocation as cold without context sensitivity.
540 if (TotalColdSize < TotalSize && MinMatchedColdBytePercent < 100 &&
541 TotalColdSize * 100 >= MinMatchedColdBytePercent * TotalSize) {
542 AllocTrie.addSingleAllocTypeAttribute(CI, AllocationType::Cold, "dominant");
543 return;
544 }
545
546 // We might not have matched any to the full inlined call stack.
547 // But if we did, create and attach metadata, or a function attribute if
548 // all contexts have identical profiled behavior.
549 if (!AllocTrie.empty()) {
550 NumOfMemProfMatchedAllocs++;
551 // MemprofMDAttached will be false if a function attribute was
552 // attached.
553 bool MemprofMDAttached = AllocTrie.buildAndAttachMIBMetadata(CI);
554 assert(MemprofMDAttached == I.hasMetadata(LLVMContext::MD_memprof));
555 if (MemprofMDAttached) {
556 // Add callsite metadata for the instruction's location list so that
557 // it simpler later on to identify which part of the MIB contexts
558 // are from this particular instruction (including during inlining,
559 // when the callsite metadata will be updated appropriately).
560 // FIXME: can this be changed to strip out the matching stack
561 // context ids from the MIB contexts and not add any callsite
562 // metadata here to save space?
563 addCallsiteMetadata(I, InlinedCallStack, Ctx);
564 }
565 }
566}
567
568// Helper struct for maintaining refs to callsite data. As an alternative we
569// could store a pointer to the CallSiteInfo struct but we also need the frame
570// index. Using ArrayRefs instead makes it a little easier to read.
572 // Subset of frames for the corresponding CallSiteInfo.
574 // Potential targets for indirect calls.
576};
577
578static void handleCallSite(Instruction &I, const Function *CalledFunction,
579 ArrayRef<uint64_t> InlinedCallStack,
580 const std::vector<CallSiteEntry> &CallSiteEntries,
581 Module &M,
582 std::set<std::vector<uint64_t>> &MatchedCallSites,
584 auto &Ctx = M.getContext();
585 // Set of Callee GUIDs to attach to indirect calls. We accumulate all of them
586 // to support cases where the instuction's inlined frames match multiple call
587 // site entries, which can happen if the profile was collected from a binary
588 // where this instruction was eventually inlined into multiple callers.
590 bool CallsiteMDAdded = false;
591 for (const auto &CallSiteEntry : CallSiteEntries) {
592 // If we found and thus matched all frames on the call, create and
593 // attach call stack metadata.
595 InlinedCallStack)) {
596 NumOfMemProfMatchedCallSites++;
597 // Only need to find one with a matching call stack and add a single
598 // callsite metadata.
599 if (!CallsiteMDAdded) {
600 addCallsiteMetadata(I, InlinedCallStack, Ctx);
601
602 // Accumulate call site matching information upon request.
604 std::vector<uint64_t> CallStack;
605 append_range(CallStack, InlinedCallStack);
606 MatchedCallSites.insert(std::move(CallStack));
607 }
608 OptimizationRemark Remark(DEBUG_TYPE, "MemProfUse", &I);
609 Remark << ore::NV("CallSite", &I) << " in function "
610 << ore::NV("Caller", I.getFunction())
611 << " matched callsite with frame count "
612 << ore::NV("Frames", InlinedCallStack.size())
613 << " and stack ids";
614 for (uint64_t StackId : InlinedCallStack)
615 Remark << " " << ore::NV("StackId", StackId);
616 ORE.emit(Remark);
617
618 // If this is a direct call, we're done.
619 if (CalledFunction)
620 break;
621 CallsiteMDAdded = true;
622 }
623
624 assert(!CalledFunction && "Didn't expect direct call");
625
626 // Collect Callee GUIDs from all matching CallSiteEntries.
629 }
630 }
631 // Try to attach indirect call metadata if possible.
632 addVPMetadata(M, I, CalleeGuids.getArrayRef());
633}
634
635// Dump inline call stack for debugging purposes.
638 DenseSet<uint64_t> &SeenFrames,
639 DenseSet<uint64_t> &SeenStacks,
640 bool ProfileHasColumns) {
641 auto GetOffset = [](const DILocation *DIL) {
642 return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) &
643 0xffff;
644 };
645
646 // Dump frame info. Frames are deduplicated using FrameID.
647 std::string CallStack;
648 raw_string_ostream CallStackOS(CallStack);
649 bool First = true;
650 for (const DILocation *DIL = I.getDebugLoc(); DIL;
651 DIL = DIL->getInlinedAt()) {
652 StringRef Name = DIL->getScope()->getSubprogram()->getLinkageName();
653 if (Name.empty())
654 Name = DIL->getScope()->getSubprogram()->getName();
655 auto CalleeGUID = Function::getGUIDAssumingExternalLinkage(Name);
656 uint64_t FrameID = computeStackId(CalleeGUID, GetOffset(DIL),
657 ProfileHasColumns ? DIL->getColumn() : 0);
658 if (SeenFrames.insert(FrameID).second) {
659 std::string DictMsg;
660 raw_string_ostream DictOS(DictMsg);
661 DictOS << "frame: " << FrameID << " " << Name << ":" << GetOffset(DIL)
662 << ":" << (ProfileHasColumns ? DIL->getColumn() : 0);
663 ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "MemProfUse", CI)
664 << DictOS.str());
665 }
666
667 if (First)
668 First = false;
669 else
670 CallStackOS << ",";
671 CallStackOS << FrameID;
672 }
673
674 // Dump inline call stack info. Stacks are deduplicated using StackHash.
675 uint64_t StackHash = llvm::MD5Hash(CallStack);
676 if (SeenStacks.insert(StackHash).second) {
677 std::string Msg;
679 OS << "inline call stack: " << CallStack;
680 ORE.emit(OptimizationRemarkAnalysis(DEBUG_TYPE, "MemProfUse", CI)
681 << OS.str());
682 }
683}
684
685static void
687 const TargetLibraryInfo &TLI,
688 std::map<uint64_t, AllocMatchInfo> &FullStackIdToAllocMatchInfo,
689 std::set<std::vector<uint64_t>> &MatchedCallSites,
691 OptimizationRemarkEmitter &ORE, uint64_t MaxColdSize,
692 DenseSet<uint64_t> &SeenStacks, DenseSet<uint64_t> &SeenFrames) {
693 auto &Ctx = M.getContext();
694 // Previously we used getIRPGOFuncName() here. If F is local linkage,
695 // getIRPGOFuncName() returns FuncName with prefix 'FileName;'. But
696 // llvm-profdata uses FuncName in dwarf to create GUID which doesn't
697 // contain FileName's prefix. It caused local linkage function can't
698 // find MemProfRecord. So we use getName() now.
699 // 'unique-internal-linkage-names' can make MemProf work better for local
700 // linkage function.
701 auto FuncName = F.getName();
702 auto FuncGUID = Function::getGUIDAssumingExternalLinkage(FuncName);
704 errs() << "MemProf: Function GUID " << FuncGUID << " is " << FuncName
705 << "\n";
706 std::optional<memprof::MemProfRecord> MemProfRec;
707 auto Err = MemProfReader->getMemProfRecord(FuncGUID).moveInto(MemProfRec);
708 if (Err) {
709 handleAllErrors(std::move(Err), [&](const InstrProfError &IPE) {
710 auto Err = IPE.get();
711 bool SkipWarning = false;
712 LLVM_DEBUG(dbgs() << "Error in reading profile for Func " << FuncName
713 << ": ");
715 NumOfMemProfMissing++;
716 SkipWarning = !PGOWarnMissing;
717 LLVM_DEBUG(dbgs() << "unknown function");
718 } else if (Err == instrprof_error::hash_mismatch) {
719 NumOfMemProfMismatch++;
720 SkipWarning =
723 (F.hasComdat() ||
725 LLVM_DEBUG(dbgs() << "hash mismatch (skip=" << SkipWarning << ")");
726 }
727
728 if (SkipWarning)
729 return;
730
731 std::string Msg = (IPE.message() + Twine(" ") + F.getName().str() +
732 Twine(" Hash = ") + std::to_string(FuncGUID))
733 .str();
734
735 Ctx.diagnose(
736 DiagnosticInfoPGOProfile(M.getName().data(), Msg, DS_Warning));
737 });
738 return;
739 }
740
741 NumOfMemProfFunc++;
742
743 // If requested, undrfit MemProfRecord so that the source locations in it
744 // match those in the IR.
746 undriftMemProfRecord(UndriftMaps, *MemProfRec);
747
748 // Detect if there are non-zero column numbers in the profile. If not,
749 // treat all column numbers as 0 when matching (i.e. ignore any non-zero
750 // columns in the IR). The profiled binary might have been built with
751 // column numbers disabled, for example.
752 bool ProfileHasColumns = false;
753
754 // Build maps of the location hash to all profile data with that leaf location
755 // (allocation info and the callsites).
756 std::map<uint64_t, std::set<const AllocationInfo *>> LocHashToAllocInfo;
757
758 // For the callsites we need to record slices of the frame array (see comments
759 // below where the map entries are added) along with their CalleeGuids.
760 std::map<uint64_t, std::vector<CallSiteEntry>> LocHashToCallSites;
761 for (auto &AI : MemProfRec->AllocSites) {
762 NumOfMemProfAllocContextProfiles++;
763 // Associate the allocation info with the leaf frame. The later matching
764 // code will match any inlined call sequences in the IR with a longer prefix
765 // of call stack frames.
766 uint64_t StackId = computeStackId(AI.CallStack[0]);
767 LocHashToAllocInfo[StackId].insert(&AI);
768 ProfileHasColumns |= AI.CallStack[0].Column;
769 }
770 for (auto &CS : MemProfRec->CallSites) {
771 NumOfMemProfCallSiteProfiles++;
772 // Need to record all frames from leaf up to and including this function,
773 // as any of these may or may not have been inlined at this point.
774 unsigned Idx = 0;
775 for (auto &StackFrame : CS.Frames) {
776 uint64_t StackId = computeStackId(StackFrame);
777 ArrayRef<Frame> FrameSlice = ArrayRef<Frame>(CS.Frames).drop_front(Idx++);
778 // The callee guids for the slice containing all frames (due to the
779 // increment above Idx is now 1) comes from the CalleeGuids recorded in
780 // the CallSite. For the slices not containing the leaf-most frame, the
781 // callee guid is simply the function GUID of the prior frame.
782 LocHashToCallSites[StackId].push_back(
783 {FrameSlice, (Idx == 1 ? CS.CalleeGuids
785 CS.Frames[Idx - 2].Function))});
786
787 ProfileHasColumns |= StackFrame.Column;
788 // Once we find this function, we can stop recording.
789 if (StackFrame.Function == FuncGUID)
790 break;
791 }
792 assert(Idx <= CS.Frames.size() && CS.Frames[Idx - 1].Function == FuncGUID);
793 }
794
795 auto GetOffset = [](const DILocation *DIL) {
796 return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) &
797 0xffff;
798 };
799
800 // Now walk the instructions, looking up the associated profile data using
801 // debug locations.
802 for (auto &BB : F) {
803 for (auto &I : BB) {
804 if (I.isDebugOrPseudoInst())
805 continue;
806 // We are only interested in calls (allocation or interior call stack
807 // context calls).
808 auto *CI = dyn_cast<CallBase>(&I);
809 if (!CI)
810 continue;
811 auto *CalledFunction = CI->getCalledFunction();
812 if (CalledFunction && CalledFunction->isIntrinsic())
813 continue;
814
816 dumpInlineCallStack(I, CI, ORE, SeenFrames, SeenStacks,
817 ProfileHasColumns);
818
819 // List of call stack ids computed from the location hashes on debug
820 // locations (leaf to inlined at root).
821 SmallVector<uint64_t, 8> InlinedCallStack;
822 // Was the leaf location found in one of the profile maps?
823 bool LeafFound = false;
824 // If leaf was found in a map, iterators pointing to its location in both
825 // of the maps. It might exist in neither, one, or both (the latter case
826 // can happen because we don't currently have discriminators to
827 // distinguish the case when a single line/col maps to both an allocation
828 // and another callsite).
829 auto AllocInfoIter = LocHashToAllocInfo.end();
830 auto CallSitesIter = LocHashToCallSites.end();
831 for (const DILocation *DIL = I.getDebugLoc(); DIL != nullptr;
832 DIL = DIL->getInlinedAt()) {
833 // Use C++ linkage name if possible. Need to compile with
834 // -fdebug-info-for-profiling to get linkage name.
835 StringRef Name = DIL->getScope()->getSubprogram()->getLinkageName();
836 if (Name.empty())
837 Name = DIL->getScope()->getSubprogram()->getName();
838 auto CalleeGUID = Function::getGUIDAssumingExternalLinkage(Name);
839 auto StackId = computeStackId(CalleeGUID, GetOffset(DIL),
840 ProfileHasColumns ? DIL->getColumn() : 0);
841 // Check if we have found the profile's leaf frame. If yes, collect
842 // the rest of the call's inlined context starting here. If not, see if
843 // we find a match further up the inlined context (in case the profile
844 // was missing debug frames at the leaf).
845 if (!LeafFound) {
846 AllocInfoIter = LocHashToAllocInfo.find(StackId);
847 CallSitesIter = LocHashToCallSites.find(StackId);
848 if (AllocInfoIter != LocHashToAllocInfo.end() ||
849 CallSitesIter != LocHashToCallSites.end())
850 LeafFound = true;
851 }
852 if (LeafFound)
853 InlinedCallStack.push_back(StackId);
854 }
855 // If leaf not in either of the maps, skip inst.
856 if (!LeafFound)
857 continue;
858
859 // First add !memprof metadata from allocation info, if we found the
860 // instruction's leaf location in that map, and if the rest of the
861 // instruction's locations match the prefix Frame locations on an
862 // allocation context with the same leaf.
863 if (AllocInfoIter != LocHashToAllocInfo.end() &&
864 // Only consider allocations which support hinting.
865 isAllocationWithHotColdVariant(CI->getCalledFunction(), TLI))
866 handleAllocSite(I, CI, InlinedCallStack, Ctx, ORE, MaxColdSize,
867 AllocInfoIter->second, FullStackIdToAllocMatchInfo);
868 else if (CallSitesIter != LocHashToCallSites.end())
869 // Otherwise, add callsite metadata. If we reach here then we found the
870 // instruction's leaf location in the callsites map and not the
871 // allocation map.
872 handleCallSite(I, CalledFunction, InlinedCallStack,
873 CallSitesIter->second, M, MatchedCallSites, ORE);
874 }
875 }
876}
877
878MemProfUsePass::MemProfUsePass(std::string MemoryProfileFile,
880 : MemoryProfileFileName(MemoryProfileFile), FS(FS) {
881 if (!FS)
882 this->FS = vfs::getRealFileSystem();
883}
884
886 // Return immediately if the module doesn't contain any function or global
887 // variables.
888 if (M.empty() && M.globals().empty())
889 return PreservedAnalyses::all();
890
891 LLVM_DEBUG(dbgs() << "Read in memory profile:\n");
892 auto &Ctx = M.getContext();
893 auto ReaderOrErr = IndexedInstrProfReader::create(MemoryProfileFileName, *FS);
894 if (Error E = ReaderOrErr.takeError()) {
895 handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
896 Ctx.diagnose(
897 DiagnosticInfoPGOProfile(MemoryProfileFileName.data(), EI.message()));
898 });
899 return PreservedAnalyses::all();
900 }
901
902 std::unique_ptr<IndexedInstrProfReader> MemProfReader =
903 std::move(ReaderOrErr.get());
904 if (!MemProfReader) {
905 Ctx.diagnose(DiagnosticInfoPGOProfile(
906 MemoryProfileFileName.data(), StringRef("Cannot get MemProfReader")));
907 return PreservedAnalyses::all();
908 }
909
910 if (!MemProfReader->hasMemoryProfile()) {
911 Ctx.diagnose(DiagnosticInfoPGOProfile(MemoryProfileFileName.data(),
912 "Not a memory profile"));
913 return PreservedAnalyses::all();
914 }
915
916 const bool Changed =
917 annotateGlobalVariables(M, MemProfReader->getDataAccessProfileData());
918
919 // If the module doesn't contain any function, return after we process all
920 // global variables.
921 if (M.empty())
923
924 auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
925
926 TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(*M.begin());
929 UndriftMaps = computeUndriftMap(M, MemProfReader.get(), TLI);
930
931 // Map from the stack hash of each matched allocation context in the function
932 // profiles to match info such as the total profiled size (bytes), allocation
933 // type, number of frames matched to the allocation itself, and the full array
934 // of call stack ids.
935 std::map<uint64_t, AllocMatchInfo> FullStackIdToAllocMatchInfo;
936
937 // Set of the matched call sites, each expressed as a sequence of an inline
938 // call stack.
939 std::set<std::vector<uint64_t>> MatchedCallSites;
940
941 DenseSet<uint64_t> SeenStacks;
942 DenseSet<uint64_t> SeenFrames;
943
944 uint64_t MaxColdSize = 0;
945 if (auto *MemProfSum = MemProfReader->getMemProfSummary())
946 MaxColdSize = MemProfSum->getMaxColdTotalSize();
947
948 for (auto &F : M) {
949 if (F.isDeclaration())
950 continue;
951
952 const TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
953 auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(F);
954 readMemprof(M, F, MemProfReader.get(), TLI, FullStackIdToAllocMatchInfo,
955 MatchedCallSites, UndriftMaps, ORE, MaxColdSize, SeenStacks,
956 SeenFrames);
957 }
958
960 for (const auto &[Id, Info] : FullStackIdToAllocMatchInfo) {
961 for (auto Frames : Info.MatchedFramesSet) {
962 // TODO: To reduce verbosity, should we change the existing message
963 // so that we emit a list of matched frame counts in a single message
964 // about the context (instead of one message per frame count?
965 errs() << "MemProf " << getAllocTypeAttributeString(Info.AllocType)
966 << " context with id " << Id << " has total profiled size "
967 << Info.TotalSize << " is matched with " << Frames << " frames";
969 errs() << " and call stack";
970 for (auto &F : Info.CallStack)
971 errs() << " " << computeStackId(F);
972 }
973 errs() << "\n";
974 }
975 }
976
977 for (const auto &CallStack : MatchedCallSites) {
978 errs() << "MemProf callsite match for inline call stack";
979 for (uint64_t StackId : CallStack)
980 errs() << " " << StackId;
981 errs() << "\n";
982 }
983 }
984
986}
987
988bool MemProfUsePass::annotateGlobalVariables(
989 Module &M, const memprof::DataAccessProfData *DataAccessProf) {
990 if (!AnnotateStaticDataSectionPrefix || M.globals().empty())
991 return false;
992
993 if (!DataAccessProf) {
994 M.addModuleFlag(Module::Warning, "EnableDataAccessProf", 0U);
995 // FIXME: Add a diagnostic message without failing the compilation when
996 // data access profile payload is not available.
997 return false;
998 }
999 M.addModuleFlag(Module::Warning, "EnableDataAccessProf", 1U);
1000
1001 bool Changed = false;
1002 // Iterate all global variables in the module and annotate them based on
1003 // data access profiles. Note it's up to the linker to decide how to map input
1004 // sections to output sections, and one conservative practice is to map
1005 // unlikely-prefixed ones to unlikely output section, and map the rest
1006 // (hot-prefixed or prefix-less) to the canonical output section.
1007 for (GlobalVariable &GVar : M.globals()) {
1008 assert(!GVar.getSectionPrefix().has_value() &&
1009 "GVar shouldn't have section prefix yet");
1010 auto Kind = llvm::memprof::getAnnotationKind(GVar);
1013 continue;
1014 }
1015
1016 StringRef Name = GVar.getName();
1017 SymbolHandleRef Handle = SymbolHandleRef(Name);
1018 // Skip string literals as their mangled names don't stay stable across
1019 // binary releases.
1021 if (Name.starts_with(".str"))
1022 continue;
1023
1024 if (Name.starts_with(".str")) {
1025 std::optional<uint64_t> Hash = getStringContentHash(GVar);
1026 if (!Hash) {
1027 LLVM_DEBUG(dbgs() << "Cannot compute content hash for string literal "
1028 << Name << "\n");
1029 continue;
1030 }
1031 Handle = SymbolHandleRef(Hash.value());
1032 }
1033
1034 // DataAccessProfRecord's get* methods will canonicalize the name under the
1035 // hood before looking it up, so optimizer doesn't need to do it.
1036 std::optional<DataAccessProfRecord> Record =
1037 DataAccessProf->getProfileRecord(Handle);
1038 // Annotate a global variable as hot if it has non-zero sampled count, and
1039 // annotate it as cold if it's seen in the profiled binary
1040 // file but doesn't have any access sample.
1041 // For logging, optimization remark emitter requires a llvm::Function, but
1042 // it's not well defined how to associate a global variable with a function.
1043 // So we just print out the static data section prefix in LLVM_DEBUG.
1044 if (Record && Record->AccessCount > 0) {
1045 ++NumOfMemProfHotGlobalVars;
1046 Changed |= GVar.setSectionPrefix("hot");
1047 LLVM_DEBUG(dbgs() << "Global variable " << Name
1048 << " is annotated as hot\n");
1049 } else if (DataAccessProf->isKnownColdSymbol(Handle)) {
1050 ++NumOfMemProfColdGlobalVars;
1051 Changed |= GVar.setSectionPrefix("unlikely");
1052 Changed = true;
1053 LLVM_DEBUG(dbgs() << "Global variable " << Name
1054 << " is annotated as unlikely\n");
1055 } else {
1056 ++NumOfMemProfUnknownGlobalVars;
1057 LLVM_DEBUG(dbgs() << "Global variable " << Name << " is not annotated\n");
1058 }
1059 }
1060
1061 return Changed;
1062}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file defines the DenseSet and SmallDenseSet classes.
#define DEBUG_TYPE
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define G(x, y, z)
Definition MD5.cpp:55
static std::optional< uint64_t > getStringContentHash(const GlobalVariable &GVar)
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 > PrintMatchedAllocStack("memprof-print-matched-alloc-stack", cl::desc("Print full stack context for matched " "allocations with -memprof-print-match-info."), cl::Hidden, cl::init(false))
static void handleCallSite(Instruction &I, const Function *CalledFunction, ArrayRef< uint64_t > InlinedCallStack, const std::vector< CallSiteEntry > &CallSiteEntries, Module &M, std::set< std::vector< uint64_t > > &MatchedCallSites, OptimizationRemarkEmitter &ORE)
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 > PrintFunctionGuids("memprof-print-function-guids", cl::desc("Print function GUIDs computed for matching"), cl::Hidden, cl::init(false))
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 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< uint64_t, AllocMatchInfo > &FullStackIdToAllocMatchInfo)
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 void readMemprof(Module &M, Function &F, IndexedInstrProfReader *MemProfReader, const TargetLibraryInfo &TLI, std::map< uint64_t, AllocMatchInfo > &FullStackIdToAllocMatchInfo, std::set< std::vector< uint64_t > > &MatchedCallSites, DenseMap< uint64_t, LocToLocMap > &UndriftMaps, OptimizationRemarkEmitter &ORE, uint64_t MaxColdSize, DenseSet< uint64_t > &SeenStacks, DenseSet< uint64_t > &SeenFrames)
static void dumpInlineCallStack(Instruction &I, CallBase *CI, OptimizationRemarkEmitter &ORE, DenseSet< uint64_t > &SeenFrames, DenseSet< uint64_t > &SeenStacks, bool ProfileHasColumns)
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 bool stackFrameIncludesInlinedCallStack(ArrayRef< Frame > ProfileCallStack, ArrayRef< uint64_t > InlinedCallStack)
AllocType
FunctionAnalysisManager FAM
const char * Msg
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:119
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.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
ArrayRef< T > take_front(size_t N=1) const
Return a copy of *this with only the first N elements.
Definition ArrayRef.h:218
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
Definition ArrayRef.h:194
iterator end() const
Definition ArrayRef.h:130
size_t size() const
Get the array size.
Definition ArrayRef.h:141
iterator begin() const
Definition ArrayRef.h:129
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
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:223
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:299
iterator end()
Definition DenseMap.h:141
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition DenseMap.h:214
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition DenseMap.h:284
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
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:80
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
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
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:478
std::string message() const override
Return the error message as a string.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
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
Diagnostic information for optimization analysis remarks.
The optimization diagnostic interface.
bool allowExtraAnalysis(StringRef PassName) const
Whether we allow for extra compile-time budget to perform more analysis to produce fewer false positi...
LLVM_ABI void emit(DiagnosticInfoOptimizationBase &OptDiag)
Output the remark via the diagnostic handler and to the optimization record file.
Diagnostic information for applied optimization remarks.
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
A vector that has set insertion semantics.
Definition SetVector.h:57
ArrayRef< value_type > getArrayRef() const
Definition SetVector.h:91
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
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 reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
LibFunc getLibFunc(StringRef funcName) 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:319
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
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.
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
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)
DenseMap< LineLocation, LineLocation > LocToLocMap
Definition MemProfUse.h:57
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.
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 ...
std::variant< StringRef, uint64_t > SymbolHandleRef
LLVM_ABI DenseMap< uint64_t, SmallVector< CallEdgeTy, 0 > > extractCallsFromIR(Module &M, const TargetLibraryInfo &TLI, function_ref< bool(uint64_t)> IsPresentInProfile=[](uint64_t) { return true;})
LLVM_ABI 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.
DiagnosticInfoOptimizationBase::Argument NV
uint64_t MD5Hash(const FunctionId &Obj)
Definition FunctionId.h:167
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.
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:1013
constexpr from_range_t from_range
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2208
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
cl::opt< bool > PGOWarnMissing
auto unique(Range &&R, Predicate P)
Definition STLExtras.h:2134
auto map_range(ContainerTy &&C, FuncTy F)
Return a range that applies F to the elements of C.
Definition STLExtras.h:365
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:1636
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
cl::opt< bool > AnnotateStringLiteralSectionPrefix("memprof-annotate-string-literal-section-prefix", cl::init(false), cl::Hidden, cl::desc("If true, annotate the string literal data section prefix"))
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.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
Definition ModRef.h:74
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:2146
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
cl::opt< bool > NoPGOWarnMismatchComdatWeak
std::set< unsigned > MatchedFramesSet
uint64_t TotalSize
std::vector< Frame > CallStack
AllocMatchInfo(uint64_t TotalSize, AllocationType AllocType)
AllocationType AllocType
ArrayRef< GlobalValue::GUID > CalleeGuids
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:525
llvm::SmallVector< AllocationInfo > AllocSites
Definition MemProf.h:523