LLVM: lib/Analysis/MemoryProfileInfo.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
19
20using namespace llvm;
22
23#define DEBUG_TYPE "memory-profile-info"
24
25namespace llvm {
26
29 cl::desc("Report total allocation sizes of hinted allocations"));
30
31
32
33
36 cl::desc("Keep all non-cold contexts (increases cloning overheads)"));
37
40 cl::desc("Min percent of cold bytes to hint alloc cold during cloning"));
41
42
43
44
45
48 cl::desc("Min percent of cold bytes at a callsite to discard non-cold "
49 "contexts"));
50
51
52
55 cl::desc("Min percent of max cold bytes for critical cold context"));
56
59 cl::desc("Apply ambiguous memprof attribute to ambiguous allocations"));
60
61}
62
66
70
75
81 auto *StackValMD =
84 }
86}
87
93
96
97
98
101 if (MDS->getString() == "cold") {
103 } else if (MDS->getString() == "hot") {
105 }
107}
108
110 switch (Type) {
112 return "notcold";
113 break;
115 return "cold";
116 break;
118 return "hot";
119 break;
120 default:
121 assert(false && "Unexpected alloc type");
122 }
124}
125
127 const unsigned NumAllocTypes = llvm::popcount(AllocTypes);
128 assert(NumAllocTypes != 0);
129 return NumAllocTypes == 1;
130}
131
138
141 return;
142
143
146 } else {
149 }
150}
151
154 std::vector ContextSizeInfo) {
155 bool First = true;
156 CallStackTrieNode *Curr = nullptr;
157 for (auto StackId : StackIds) {
158
161 if (Alloc) {
162 assert(AllocStackId == StackId);
163 Alloc->addAllocType(AllocType);
164 } else {
165 AllocStackId = StackId;
166 Alloc = new CallStackTrieNode(AllocType);
167 }
168 Curr = Alloc;
169 continue;
170 }
171
172 auto [Next, Inserted] = Curr->Callers.try_emplace(StackId);
173 if (!Inserted) {
174 Curr = Next->second;
175 Curr->addAllocType(AllocType);
176 continue;
177 }
178
179 auto *New = new CallStackTrieNode(AllocType);
180 Next->second = New;
181 Curr = New;
182 }
185}
186
188
189 BuiltFromExistingMetadata = true;
194 for (const auto &MIBStackIter : StackMD->operands()) {
197 CallStack.push_back(StackId->getZExtValue());
198 }
199 std::vector ContextSizeInfo;
200
207 ->getZExtValue();
210 ->getZExtValue();
211 ContextSizeInfo.push_back({FullStackId, TotalSize});
212 }
213 }
215}
216
221 bool BuiltFromExistingMetadata,
227
228 if (ContextSizeInfo.empty()) {
229
230
231
232
235 }
236
237 for (const auto &[FullStackId, TotalSize] : ContextSizeInfo) {
238 TotalBytes += TotalSize;
239 bool LargeColdContext = false;
241 ColdBytes += TotalSize;
242
243
244
245
246
247
248 if (BuiltFromExistingMetadata ||
251 LargeColdContext = true;
252 }
253
254
255
256
262 auto *ContextSizeMD = MDNode::get(Ctx, {FullStackIdMD, TotalSizeMD});
263 MIBPayload.push_back(ContextSizeMD);
264 }
265 }
266 assert(TotalBytes > 0);
268}
269
270void CallStackTrie::collectContextSizeInfo(
271 CallStackTrieNode *Node, std::vector &ContextSizeInfo) {
273 for (auto &Caller : Node->Callers)
274 collectContextSizeInfo(Caller.second, ContextSizeInfo);
275}
276
277void CallStackTrie::convertHotToNotCold(CallStackTrieNode *Node) {
281 }
282 for (auto &Caller : Node->Callers)
283 convertHotToNotCold(Caller.second);
284}
285
286
287
289 std::vector<Metadata *> &SavedMIBNodes,
290 unsigned CallerContextLength,
292 bool BuiltFromExistingMetadata) {
293 const bool MostlyCold =
294
295
296
297
298
299
300
301
303 ColdBytes > 0 &&
305
306
309 return;
310 }
311
312 auto EmitMessageForRemovedContexts = [](const MDNode *MIBMD, StringRef Tag,
320 ->getZExtValue();
323 ->getZExtValue();
324 errs() << "MemProf hinting: Total size for " << Tag
325 << " non-cold full allocation context hash " << FullStackId
326 << Extra << ": " << TS << "\n";
327 }
328 };
329
330
331
332
333 if (MostlyCold) {
334 auto NewColdMIBNodes =
337
339 return true;
341 const float PercentCold = ColdBytes * 100.0 / TotalBytes;
342 std::string PercentStr;
344 OS << format(" for %5.2f%% cold bytes", PercentCold);
345 EmitMessageForRemovedContexts(MIBMD, "discarded", OS.str());
346 }
347 return false;
348 });
349 for (auto *M : NewColdMIBNodes)
350 SavedMIBNodes.push_back(M);
351 return;
352 }
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 bool LongerNotColdContextKept = false;
382 for (auto *MIB : NewMIBNodes) {
385 continue;
388 if (StackMD->getNumOperands() > CallerContextLength) {
389 LongerNotColdContextKept = true;
390 break;
391 }
392 }
393
394
395 bool KeepFirstNewNotCold = !LongerNotColdContextKept;
398
402
404 return true;
405
406
407 if (KeepFirstNewNotCold) {
408 KeepFirstNewNotCold = false;
409 return true;
410 }
412 EmitMessageForRemovedContexts(MIBMD, "pruned", "");
413 return false;
414 }
415 return true;
416 });
417 for (auto *M : NewColdMIBNodes)
418 SavedMIBNodes.push_back(M);
419}
420
421
422
423
424
425bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
426 std::vector<uint64_t> &MIBCallStack,
427 std::vector<Metadata *> &MIBNodes,
428 bool CalleeHasAmbiguousCallerContext,
429 uint64_t &TotalBytes, uint64_t &ColdBytes) {
430
431
433 std::vector ContextSizeInfo;
434 collectContextSizeInfo(Node, ContextSizeInfo);
436 Ctx, MIBCallStack, (AllocationType)Node->AllocTypes, ContextSizeInfo,
437 MaxColdSize, BuiltFromExistingMetadata, TotalBytes, ColdBytes));
438 return true;
439 }
440
441
442
443 if (->Callers.empty()) {
444 bool NodeHasAmbiguousCallerContext = Node->Callers.size() > 1;
445 bool AddedMIBNodesForAllCallerContexts = true;
446
447
448
449 std::vector<Metadata *> NewMIBNodes;
450
451
452 uint64_t CallerTotalBytes = 0;
453 uint64_t CallerColdBytes = 0;
454 for (auto &Caller : Node->Callers) {
455 MIBCallStack.push_back(Caller.first);
456 AddedMIBNodesForAllCallerContexts &= buildMIBNodes(
457 Caller.second, Ctx, MIBCallStack, NewMIBNodes,
458 NodeHasAmbiguousCallerContext, CallerTotalBytes, CallerColdBytes);
459
460 MIBCallStack.pop_back();
461 }
462
463
465 CallerTotalBytes, CallerColdBytes,
466 BuiltFromExistingMetadata);
467 TotalBytes += CallerTotalBytes;
468 ColdBytes += CallerColdBytes;
469
470 if (AddedMIBNodesForAllCallerContexts)
471 return true;
472
473
474 assert(!NodeHasAmbiguousCallerContext);
475 }
476
477
478
479
480
481
482
483
484
485
486
487 if (!CalleeHasAmbiguousCallerContext)
488 return false;
489 std::vector ContextSizeInfo;
490 collectContextSizeInfo(Node, ContextSizeInfo);
493 BuiltFromExistingMetadata, TotalBytes, ColdBytes));
494 return true;
495}
496
501
502
506 std::vector ContextSizeInfo;
507 collectContextSizeInfo(Alloc, ContextSizeInfo);
508 for (const auto &[FullStackId, TotalSize] : ContextSizeInfo) {
509 errs() << "MemProf hinting: Total size for full allocation context hash "
510 << FullStackId << " and " << Descriptor << " alloc type "
512 }
513 }
514 if (ORE)
516 << ore::NV("AllocationCall", CI) << " in function "
518 << " marked with memprof allocation attribute "
519 << ore::NV("Attribute", AllocTypeString));
520}
521
522
523
524
528 "single");
529 return false;
530 }
531
532
533
534
535
536
537
539 convertHotToNotCold(Alloc);
540
543 "single");
544 return false;
545 }
546 }
548 std::vector<uint64_t> MIBCallStack;
549 MIBCallStack.push_back(AllocStackId);
550 std::vector<Metadata *> MIBNodes;
553 assert(!Alloc->Callers.empty() && "addCallStack has not been called yet");
554
555
556
557 if (buildMIBNodes(Alloc, Ctx, MIBCallStack, MIBNodes,
558 false, TotalBytes,
559 ColdBytes)) {
560 assert(MIBCallStack.size() == 1 &&
561 "Should only be left with Alloc's location in stack");
564 return true;
565 }
566
567
568
569
570
572 return false;
573}
574
575template <>
577 const MDNode *N, bool End)
579 if ()
580 return;
581 Iter = End ? N->op_end() : N->op_begin();
582}
583
584template <>
591}
592
596 ->getZExtValue();
597}
598
600
601
602
603 if (A)
604 return A;
605 return B;
606}
607
609
610
611 if (A)
612 return A;
613 return B;
614}
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")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static MDNode * createMIBNode(LLVMContext &Ctx, ArrayRef< uint64_t > MIBCallStack, AllocationType AllocType, ArrayRef< ContextTotalSize > ContextSizeInfo, const uint64_t MaxColdSize, bool BuiltFromExistingMetadata, uint64_t &TotalBytes, uint64_t &ColdBytes)
Definition MemoryProfileInfo.cpp:217
static void saveFilteredNewMIBNodes(std::vector< Metadata * > &NewMIBNodes, std::vector< Metadata * > &SavedMIBNodes, unsigned CallerContextLength, uint64_t TotalBytes, uint64_t ColdBytes, bool BuiltFromExistingMetadata)
Definition MemoryProfileInfo.cpp:288
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
bool empty() const
empty - Check if the array is empty.
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
LLVM_ABI StringRef getValueAsString() const
Return the attribute's value as a string.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void addFnAttr(Attribute::AttrKind Kind)
Adds the attribute to the function.
bool hasFnAttr(Attribute::AttrKind Kind) const
Determine whether this call has the given attribute.
Attribute getFnAttr(StringRef Kind) const
Get the attribute of a given kind for the function.
void removeFnAttr(Attribute::AttrKind Kind)
Removes the attribute from the function.
This is the shared class of boolean and integer constants.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
This is an important class for using LLVM in a threaded context.
static LLVM_ABI MDNode * getMergedCallsiteMetadata(MDNode *A, MDNode *B)
Definition MemoryProfileInfo.cpp:608
const MDOperand & getOperand(unsigned I) const
ArrayRef< MDOperand > operands() const
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
unsigned getNumOperands() const
Return number of MDNode operands.
LLVM_ABI MDNode(LLVMContext &Context, unsigned ID, StorageType Storage, ArrayRef< Metadata * > Ops1, ArrayRef< Metadata * > Ops2={})
static LLVM_ABI MDNode * getMergedMemProfMetadata(MDNode *A, MDNode *B)
Definition MemoryProfileInfo.cpp:599
static LLVM_ABI MDString * get(LLVMContext &Context, StringRef Str)
void push_back(Metadata *MD)
Append an element to the tuple. This will resize the node.
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.
StringRef - Represent a constant reference to a string, i.e.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt64Ty(LLVMContext &C)
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
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.
Definition MemoryProfileInfo.cpp:152
LLVM_ABI void addSingleAllocTypeAttribute(CallBase *CI, AllocationType AT, StringRef Descriptor)
Add an attribute for the given allocation type to the call instruction.
Definition MemoryProfileInfo.cpp:497
LLVM_ABI bool buildAndAttachMIBMetadata(CallBase *CI)
Build and attach the minimal necessary MIB metadata.
Definition MemoryProfileInfo.cpp:525
Helper class to iterate through stack ids in both metadata (memprof MIB and callsite) and the corresp...
A raw_ostream that writes to an std::string.
std::string & str()
Returns the string's reference.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract(Y &&MD)
Extract a Value from Metadata, if any.
LLVM_ABI MDNode * buildCallstackMetadata(ArrayRef< uint64_t > CallStack, LLVMContext &Ctx)
Build callstack metadata from the provided list of call stack ids.
Definition MemoryProfileInfo.cpp:76
LLVM_ABI bool recordContextSizeInfoForAnalysis()
Whether we need to record the context size info in the alloc trie used to build metadata.
Definition MemoryProfileInfo.cpp:71
LLVM_ABI bool metadataIncludesAllContextSizeInfo()
Whether the alloc memeprof metadata will include context size info for all MIBs.
Definition MemoryProfileInfo.cpp:63
LLVM_ABI AllocationType getMIBAllocType(const MDNode *MIB)
Returns the allocation type from an MIB metadata node.
Definition MemoryProfileInfo.cpp:94
LLVM_ABI bool metadataMayIncludeContextSizeInfo()
Whether the alloc memprof metadata may include context size info for some MIBs (but possibly not all)...
Definition MemoryProfileInfo.cpp:67
LLVM_ABI bool hasSingleAllocType(uint8_t AllocTypes)
True if the AllocTypes bitmask contains just a single type.
Definition MemoryProfileInfo.cpp:126
LLVM_ABI std::string getAllocTypeAttributeString(AllocationType Type)
Returns the string to use in attributes with the given type.
Definition MemoryProfileInfo.cpp:109
LLVM_ABI MDNode * getMIBStackNode(const MDNode *MIB)
Returns the stack node from an MIB metadata node.
Definition MemoryProfileInfo.cpp:88
LLVM_ABI void removeAnyExistingAmbiguousAttribute(CallBase *CB)
Removes any existing "ambiguous" memprof attribute.
Definition MemoryProfileInfo.cpp:132
LLVM_ABI void addAmbiguousAttribute(CallBase *CB)
Adds an "ambiguous" memprof attribute to call with a matched allocation profile but that we haven't y...
Definition MemoryProfileInfo.cpp:139
DiagnosticInfoOptimizationBase::Argument NV
NodeAddr< NodeBase * > Node
This is an optimization pass for GlobalISel generic memory operations.
cl::opt< unsigned > MinClonedColdBytePercent("memprof-cloning-cold-threshold", cl::init(100), cl::Hidden, cl::desc("Min percent of cold bytes to hint alloc cold during cloning"))
cl::opt< bool > MemProfReportHintedSizes("memprof-report-hinted-sizes", cl::init(false), cl::Hidden, cl::desc("Report total allocation sizes of hinted allocations"))
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
LLVM_ABI cl::opt< bool > MemProfKeepAllNotColdContexts("memprof-keep-all-not-cold-contexts", cl::init(false), cl::Hidden, cl::desc("Keep all non-cold contexts (increases cloning overheads)"))
LLVM_ABI cl::opt< bool > MemProfUseAmbiguousAttributes("memprof-ambiguous-attributes", cl::init(true), cl::Hidden, cl::desc("Apply ambiguous memprof attribute to ambiguous allocations"))
cl::opt< unsigned > MinCallsiteColdBytePercent("memprof-callsite-cold-threshold", cl::init(100), cl::Hidden, cl::desc("Min percent of cold bytes at a callsite to discard non-cold " "contexts"))
iterator_range< filter_iterator< detail::IterOfRange< RangeT >, PredicateT > > make_filter_range(RangeT &&Range, PredicateT Pred)
Convenience function that takes a range of elements and a predicate, and return a new filter_iterator...
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
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.
FunctionAddr VTableAddr Next
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
cl::opt< unsigned > MinPercentMaxColdSize("memprof-min-percent-max-cold-size", cl::init(100), cl::Hidden, cl::desc("Min percent of max cold bytes for critical cold context"))
CallStackIterator(const NodeT *N, bool End)