LLVM: lib/Transforms/Instrumentation/MemProfiler.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
47#include
48#include
49
50using namespace llvm;
52
53#define DEBUG_TYPE "memprof"
54
55namespace llvm {
59}
60
62
63
65
66
68
69
71
74
78 "__memprof_version_mismatch_check_v";
79
81 "__memprof_shadow_memory_dynamic_address";
82
84
86
87
88
90 "memprof-guard-against-version-mismatch",
91 cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden,
93
94
96 cl::desc("instrument read instructions"),
98
103
105 "memprof-instrument-atomics",
106 cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
108
110 "memprof-use-callbacks",
111 cl::desc("Use callbacks instead of inline instrumentation sequences."),
113
116 cl::desc("Prefix for memory access callbacks"),
118
119
120
121
122
124 cl::desc("scale of memprof shadow mapping"),
126
129 cl::desc("granularity of memprof shadow mapping"),
131
133 cl::desc("Instrument scalar stack variables"),
135
136
137
140
143
146
149
150
151
152
154 "memprof-match-hot-cold-new",
156 "Match allocation profiles onto existing hot/cold operator new calls"),
158
160 cl::desc("Collect access count histograms"),
162
165 cl::desc("Print matching stats for each allocation "
166 "context in this module's profiles"),
168
171 cl::desc("The default memprof options"),
173
176 cl::desc("Salvage stale MemProf profile"),
178
181 cl::desc("Min percent of cold bytes to hint alloc cold during cloning"));
182
184
187 cl::desc("Min percent of cold bytes matched to hint allocation cold"));
188
189
190STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
191STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
192STATISTIC(NumSkippedStackReads, "Number of non-instrumented stack reads");
193STATISTIC(NumSkippedStackWrites, "Number of non-instrumented stack writes");
194
195
196STATISTIC(NumOfMemProfMissing, "Number of functions without memory profile.");
198 "Number of functions having mismatched memory profile hash.");
199STATISTIC(NumOfMemProfFunc, "Number of functions having valid memory profile.");
201 "Number of alloc contexts in memory profile.");
203 "Number of callsites in memory profile.");
205 "Number of matched memory profile alloc contexts.");
207 "Number of matched memory profile allocs.");
209 "Number of matched memory profile callsites.");
210
211namespace {
212
213
214
215struct ShadowMapping {
216 ShadowMapping() {
219 Mask = ~(Granularity - 1);
220 }
221
222 int Scale;
223 int Granularity;
225};
226
227static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) {
230}
231
232struct InterestingMemoryAccess {
234 bool IsWrite;
235 Type *AccessTy;
236 Value *MaybeMask = nullptr;
237};
238
239
240class MemProfiler {
241public:
242 MemProfiler(Module &M) {
244 LongSize = M.getDataLayout().getPointerSizeInBits();
246 PtrTy = PointerType::getUnqual(*C);
247 }
248
249
250
251
252 std::optional
253 isInterestingMemoryAccess(Instruction *I) const;
254
256 InterestingMemoryAccess &Access);
259 void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,
261 bool IsWrite);
264 bool instrumentFunction(Function &F);
265 bool maybeInsertMemProfInitAtFunctionEntry(Function &F);
266 bool insertDynamicShadowAtFunctionEntry(Function &F);
267
268private:
269 void initializeCallbacks(Module &M);
270
272 int LongSize;
273 Type *IntptrTy;
275 ShadowMapping Mapping;
276
277
279
280 FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset;
281 Value *DynamicShadowOffset = nullptr;
282};
283
284class ModuleMemProfiler {
285public:
286 ModuleMemProfiler(Module &M) { TargetTriple = Triple(M.getTargetTriple()); }
287
288 bool instrumentModule(Module &);
289
290private:
292 ShadowMapping Mapping;
293 Function *MemProfCtorFunction = nullptr;
294};
295
296}
297
299
303 "Memprof with histogram only supports default mapping granularity");
304 Module &M = *F.getParent();
305 MemProfiler Profiler(M);
306 if (Profiler.instrumentFunction(F))
309}
310
312
315
316 ModuleMemProfiler Profiler(M);
317 if (Profiler.instrumentModule(M))
320}
321
323
324 Shadow = IRB.CreateAnd(Shadow, Mapping.Mask);
325 Shadow = IRB.CreateLShr(Shadow, Mapping.Scale);
326
327 assert(DynamicShadowOffset);
328 return IRB.CreateAdd(Shadow, DynamicShadowOffset);
329}
330
331
332void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) {
334 if (isa(MI)) {
335 IRB.CreateCall(isa(MI) ? MemProfMemmove : MemProfMemcpy,
336 {MI->getOperand(0), MI->getOperand(1),
338 } else if (isa(MI)) {
340 MemProfMemset,
341 {MI->getOperand(0),
344 }
345 MI->eraseFromParent();
346}
347
348std::optional
349MemProfiler::isInterestingMemoryAccess(Instruction *I) const {
350
351 if (DynamicShadowOffset == I)
352 return std::nullopt;
353
354 InterestingMemoryAccess Access;
355
356 if (LoadInst *LI = dyn_cast(I)) {
358 return std::nullopt;
359 Access.IsWrite = false;
360 Access.AccessTy = LI->getType();
361 Access.Addr = LI->getPointerOperand();
362 } else if (StoreInst *SI = dyn_cast(I)) {
364 return std::nullopt;
365 Access.IsWrite = true;
366 Access.AccessTy = SI->getValueOperand()->getType();
367 Access.Addr = SI->getPointerOperand();
368 } else if (AtomicRMWInst *RMW = dyn_cast(I)) {
370 return std::nullopt;
371 Access.IsWrite = true;
372 Access.AccessTy = RMW->getValOperand()->getType();
373 Access.Addr = RMW->getPointerOperand();
374 } else if (AtomicCmpXchgInst *XCHG = dyn_cast(I)) {
376 return std::nullopt;
377 Access.IsWrite = true;
378 Access.AccessTy = XCHG->getCompareOperand()->getType();
379 Access.Addr = XCHG->getPointerOperand();
380 } else if (auto *CI = dyn_cast(I)) {
381 auto *F = CI->getCalledFunction();
382 if (F && (F->getIntrinsicID() == Intrinsic::masked_load ||
383 F->getIntrinsicID() == Intrinsic::masked_store)) {
384 unsigned OpOffset = 0;
385 if (F->getIntrinsicID() == Intrinsic::masked_store) {
387 return std::nullopt;
388
389 OpOffset = 1;
390 Access.AccessTy = CI->getArgOperand(0)->getType();
391 Access.IsWrite = true;
392 } else {
394 return std::nullopt;
395 Access.AccessTy = CI->getType();
396 Access.IsWrite = false;
397 }
398
399 auto *BasePtr = CI->getOperand(0 + OpOffset);
400 Access.MaybeMask = CI->getOperand(2 + OpOffset);
402 }
403 }
404
406 return std::nullopt;
407
408
409
410 Type *PtrTy = cast(Access.Addr->getType()->getScalarType());
412 return std::nullopt;
413
414
415
416
417
418 if (Access.Addr->isSwiftError())
419 return std::nullopt;
420
421
422 auto *Addr = Access.Addr->stripInBoundsOffsets();
423
425
426 if (GV->hasSection()) {
428
432 return std::nullopt;
433 }
434
435
436 if (GV->getName().starts_with("__llvm"))
437 return std::nullopt;
438 }
439
441}
442
443void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,
445 Type *AccessTy, bool IsWrite) {
446 auto *VTy = cast(AccessTy);
447 unsigned Num = VTy->getNumElements();
448 auto *Zero = ConstantInt::get(IntptrTy, 0);
449 for (unsigned Idx = 0; Idx < Num; ++Idx) {
450 Value *InstrumentedAddress = nullptr;
452 if (auto *Vector = dyn_cast(Mask)) {
453
454 if (auto *Masked = dyn_cast(Vector->getOperand(Idx))) {
455 if (Masked->isZero())
456
457 continue;
458
459
460 }
461 } else {
465 InsertBefore = ThenTerm;
466 }
467
469 InstrumentedAddress =
472 }
473}
474
476 InterestingMemoryAccess &Access) {
477
480 ++NumSkippedStackWrites;
481 else
482 ++NumSkippedStackReads;
483 return;
484 }
485
487 NumInstrumentedWrites++;
488 else
489 NumInstrumentedReads++;
490
491 if (Access.MaybeMask) {
492 instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr,
494 } else {
495
496
497
499 }
500}
501
502void MemProfiler::instrumentAddress(Instruction *OrigIns,
504 bool IsWrite) {
507
509 IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong);
510 return;
511 }
512
515
516 Value *ShadowPtr = memToShadow(AddrLong, IRB);
518 Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr);
519
526 }
527 Value *Inc = ConstantInt::get(ShadowTy, 1);
528 ShadowValue = IRB.CreateAdd(ShadowValue, Inc);
529 IRB.CreateStore(ShadowValue, ShadowAddr);
530}
531
532
534 const MDString *MemProfFilename =
535 dyn_cast_or_null(M.getModuleFlag("MemProfProfileFilename"));
536 if (!MemProfFilename)
537 return;
539 "Unexpected MemProfProfileFilename metadata with empty string");
541 M.getContext(), MemProfFilename->getString(), true);
543 M, ProfileNameConst->getType(), true,
545 Triple TT(M.getTargetTriple());
546 if (TT.supportsCOMDAT()) {
549 }
550}
551
552
553
560 Triple TT(M.getTargetTriple());
561 if (TT.supportsCOMDAT()) {
563 MemprofHistogramFlag->setComdat(M.getOrInsertComdat(VarName));
564 }
566}
567
574 "__memprof_default_options_str");
575 Triple TT(M.getTargetTriple());
576 if (TT.supportsCOMDAT()) {
578 OptionsVar->setComdat(M.getOrInsertComdat(OptionsVar->getName()));
579 }
580}
581
582bool ModuleMemProfiler::instrumentModule(Module &M) {
583
584
586 std::string VersionCheckName =
588 : "";
589 std::tie(MemProfCtorFunction, std::ignore) =
592 {}, VersionCheckName);
593
594 const uint64_t Priority = getCtorAndDtorPriority(TargetTriple);
596
598
600
602
603 return true;
604}
605
606void MemProfiler::initializeCallbacks(Module &M) {
608
609 for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
610 const std::string TypeStr = AccessIsWrite ? "store" : "load";
611 const std::string HistPrefix = ClHistogram ? "hist_" : "";
612
614 MemProfMemoryAccessCallback[AccessIsWrite] = M.getOrInsertFunction(
617 }
618 MemProfMemmove = M.getOrInsertFunction(
621 PtrTy, PtrTy, PtrTy, IntptrTy);
622 MemProfMemset =
625}
626
627bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) {
628
629
630
631
632
633
634
635 if (F.getName().contains(" load]")) {
639 IRB.CreateCall(MemProfInitFunction, {});
640 return true;
641 }
642 return false;
643}
644
645bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) {
647 Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal(
650 cast(GlobalDynamicAddress)->setDSOLocal(true);
651 DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress);
652 return true;
653}
654
655bool MemProfiler::instrumentFunction(Function &F) {
657 return false;
659 return false;
660 if (F.getName().starts_with("__memprof_"))
661 return false;
662
663 bool FunctionModified = false;
664
665
666
667
668 if (maybeInsertMemProfInitAtFunctionEntry(F))
669 FunctionModified = true;
670
671 LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n");
672
673 initializeCallbacks(*F.getParent());
674
676
677
678 for (auto &BB : F) {
679 for (auto &Inst : BB) {
680 if (isInterestingMemoryAccess(&Inst) || isa(Inst))
682 }
683 }
684
685 if (ToInstrument.empty()) {
686 LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified
687 << " " << F << "\n");
688
689 return FunctionModified;
690 }
691
692 FunctionModified |= insertDynamicShadowAtFunctionEntry(F);
693
694 int NumInstrumented = 0;
695 for (auto *Inst : ToInstrument) {
698 std::optional Access =
699 isInterestingMemoryAccess(Inst);
701 instrumentMop(Inst, F.getDataLayout(), *Access);
702 else
703 instrumentMemIntrinsic(cast(Inst));
704 }
705 NumInstrumented++;
706 }
707
708 if (NumInstrumented > 0)
709 FunctionModified = true;
710
711 LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " "
712 << F << "\n");
713
714 return FunctionModified;
715}
716
720 I.setMetadata(LLVMContext::MD_callsite,
722}
723
731 std::memcpy(&Id, Hash.data(), sizeof(Hash));
732 return Id;
733}
734
737}
738
739
740
748 std::memcpy(&Id, Hash.data(), sizeof(Hash));
749 return Id;
750}
751
756 for (const auto &StackFrame : AllocInfo->CallStack)
760 AllocInfo->Info.getTotalLifetime());
761 std::vector ContextSizeInfo;
763 auto TotalSize = AllocInfo->Info.getTotalSize();
765 assert(FullStackId != 0);
766 ContextSizeInfo.push_back({FullStackId, TotalSize});
767 }
770}
771
772
773
774
775
776static bool
779 auto StackFrame = ProfileCallStack.begin();
780 auto InlCallStackIter = InlinedCallStack.begin();
781 for (; StackFrame != ProfileCallStack.end() &&
782 InlCallStackIter != InlinedCallStack.end();
783 ++StackFrame, ++InlCallStackIter) {
785 if (StackId != *InlCallStackIter)
786 return false;
787 }
788
789
790 return InlCallStackIter == InlinedCallStack.end();
791}
792
795 if (!Callee)
796 return false;
799 return false;
800 switch (Func) {
801 case LibFunc_Znwm:
802 case LibFunc_ZnwmRKSt9nothrow_t:
803 case LibFunc_ZnwmSt11align_val_t:
804 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
805 case LibFunc_Znam:
806 case LibFunc_ZnamRKSt9nothrow_t:
807 case LibFunc_ZnamSt11align_val_t:
808 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
809 case LibFunc_size_returning_new:
810 case LibFunc_size_returning_new_aligned:
811 return true;
812 case LibFunc_Znwm12__hot_cold_t:
813 case LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t:
814 case LibFunc_ZnwmSt11align_val_t12__hot_cold_t:
815 case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
816 case LibFunc_Znam12__hot_cold_t:
817 case LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t:
818 case LibFunc_ZnamSt11align_val_t12__hot_cold_t:
819 case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
820 case LibFunc_size_returning_new_hot_cold:
821 case LibFunc_size_returning_new_aligned_hot_cold:
823 default:
824 return false;
825 }
826}
827
831 bool Matched = false;
832};
833
838
839 auto GetOffset = [](const DILocation *DIL) {
840 return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) &
841 0xffff;
842 };
843
845 if (F.isDeclaration())
846 continue;
847
848 for (auto &BB : F) {
849 for (auto &I : BB) {
851 continue;
852
853 auto *CB = dyn_cast(&I);
854 auto *CalledFunction = CB->getCalledFunction();
855
856 if (!CalledFunction || CalledFunction->isIntrinsic())
857 continue;
858
859 StringRef CalleeName = CalledFunction->getName();
860
861
863
864
865 bool IsLeaf = true;
866 for (const DILocation *DIL = I.getDebugLoc(); DIL;
867 DIL = DIL->getInlinedAt()) {
868 StringRef CallerName = DIL->getSubprogramLinkageName();
870 "Be sure to enable -fdebug-info-for-profiling");
873
874
875 if (IsAlloc) {
876 if (IsLeaf) {
877
878
879 CalleeGUID = 0;
880 } else if (!IsPresentInProfile(CalleeGUID)) {
881
882
883 CalleeGUID = 0;
884 } else {
885
886
887 IsAlloc = false;
888 }
889 }
890
891 LineLocation Loc = {GetOffset(DIL), DIL->getColumn()};
892 Calls[CallerGUID].emplace_back(Loc, CalleeGUID);
893 CalleeName = CallerName;
894 IsLeaf = false;
895 }
896 }
897 }
898 }
899
900
901 for (auto &[CallerGUID, CallList] : Calls) {
903 CallList.erase(llvm::unique(CallList), CallList.end());
904 }
905
906 return Calls;
907}
908
913
918 return CallsFromProfile.contains(GUID);
919 });
920
921
922 for (const auto &[CallerGUID, IRAnchors] : CallsFromIR) {
923 auto It = CallsFromProfile.find(CallerGUID);
924 if (It == CallsFromProfile.end())
925 continue;
926 const auto &ProfileAnchors = It->second;
927
929 longestCommonSequence<LineLocation, GlobalValue::GUID>(
930 ProfileAnchors, IRAnchors, std::equal_toGlobalValue::GUID(),
932 bool Inserted = UndriftMaps.try_emplace(CallerGUID, Matchings).second;
933
934
936 (void)Inserted;
937 }
938
939 return UndriftMaps;
940}
941
942
943
944static void
947
948 auto UndriftCallStack = [&](std::vector &CallStack) {
950 auto I = UndriftMaps.find(F.Function);
951 if (I == UndriftMaps.end())
952 continue;
953 auto J = I->second.find(LineLocation(F.LineOffset, F.Column));
954 if (J == I->second.end())
955 continue;
956 auto &NewLoc = J->second;
957 F.LineOffset = NewLoc.LineOffset;
958 F.Column = NewLoc.Column;
959 }
960 };
961
962 for (auto &AS : MemProfRec.AllocSites)
963 UndriftCallStack(AS.CallStack);
964
965 for (auto &CS : MemProfRec.CallSites)
966 UndriftCallStack(CS);
967}
968
969static void
972 std::map<uint64_t, AllocMatchInfo> &FullStackIdToAllocMatchInfo,
974 auto &Ctx = M.getContext();
975
976
977
978
979
980
981
982 auto FuncName = F.getName();
984 std::optionalmemprof::MemProfRecord MemProfRec;
985 auto Err = MemProfReader->getMemProfRecord(FuncGUID).moveInto(MemProfRec);
986 if (Err) {
988 auto Err = IPE.get();
989 bool SkipWarning = false;
990 LLVM_DEBUG(dbgs() << "Error in reading profile for Func " << FuncName
991 << ": ");
993 NumOfMemProfMissing++;
997 NumOfMemProfMismatch++;
998 SkipWarning =
1001 (F.hasComdat() ||
1003 LLVM_DEBUG(dbgs() << "hash mismatch (skip=" << SkipWarning << ")");
1004 }
1005
1006 if (SkipWarning)
1007 return;
1008
1009 std::string Msg = (IPE.message() + Twine(" ") + F.getName().str() +
1010 Twine(" Hash = ") + std::to_string(FuncGUID))
1011 .str();
1012
1013 Ctx.diagnose(
1015 });
1016 return;
1017 }
1018
1019 NumOfMemProfFunc++;
1020
1021
1022
1025
1026
1027
1028
1029
1030 bool ProfileHasColumns = false;
1031
1032
1033
1034 std::map<uint64_t, std::set<const AllocationInfo *>> LocHashToAllocInfo;
1035
1036 struct CallStackHash {
1039 }
1040 };
1041
1042
1043 std::map<uint64_t, std::unordered_set<ArrayRef, CallStackHash>>
1044 LocHashToCallSites;
1045 for (auto &AI : MemProfRec->AllocSites) {
1046 NumOfMemProfAllocContextProfiles++;
1047
1048
1049
1051 LocHashToAllocInfo[StackId].insert(&AI);
1052 ProfileHasColumns |= AI.CallStack[0].Column;
1053 }
1054 for (auto &CS : MemProfRec->CallSites) {
1055 NumOfMemProfCallSiteProfiles++;
1056
1057
1058 unsigned Idx = 0;
1059 for (auto &StackFrame : CS) {
1061 LocHashToCallSites[StackId].insert(ArrayRef(CS).drop_front(Idx++));
1062 ProfileHasColumns |= StackFrame.Column;
1063
1064 if (StackFrame.Function == FuncGUID)
1065 break;
1066 }
1067 assert(Idx <= CS.size() && CS[Idx - 1].Function == FuncGUID);
1068 }
1069
1070 auto GetOffset = [](const DILocation *DIL) {
1071 return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) &
1072 0xffff;
1073 };
1074
1075
1076
1077 for (auto &BB : F) {
1078 for (auto &I : BB) {
1079 if (I.isDebugOrPseudoInst())
1080 continue;
1081
1082
1083 auto *CI = dyn_cast(&I);
1084 if (!CI)
1085 continue;
1086 auto *CalledFunction = CI->getCalledFunction();
1087 if (CalledFunction && CalledFunction->isIntrinsic())
1088 continue;
1089
1090
1092
1093 bool LeafFound = false;
1094
1095
1096
1097
1098
1099 std::map<uint64_t, std::set<const AllocationInfo *>>::iterator
1100 AllocInfoIter;
1101 decltype(LocHashToCallSites)::iterator CallSitesIter;
1102 for (const DILocation *DIL = I.getDebugLoc(); DIL != nullptr;
1103 DIL = DIL->getInlinedAt()) {
1104
1105
1106 StringRef Name = DIL->getScope()->getSubprogram()->getLinkageName();
1107 if (Name.empty())
1108 Name = DIL->getScope()->getSubprogram()->getName();
1110 auto StackId = computeStackId(CalleeGUID, GetOffset(DIL),
1111 ProfileHasColumns ? DIL->getColumn() : 0);
1112
1113
1114
1115
1116 if (!LeafFound) {
1117 AllocInfoIter = LocHashToAllocInfo.find(StackId);
1118 CallSitesIter = LocHashToCallSites.find(StackId);
1119 if (AllocInfoIter != LocHashToAllocInfo.end() ||
1120 CallSitesIter != LocHashToCallSites.end())
1121 LeafFound = true;
1122 }
1123 if (LeafFound)
1124 InlinedCallStack.push_back(StackId);
1125 }
1126
1127 if (!LeafFound)
1128 continue;
1129
1130
1131
1132
1133
1134 if (AllocInfoIter != LocHashToAllocInfo.end()) {
1135
1137 continue;
1138
1139
1140
1144 for (auto *AllocInfo : AllocInfoIter->second) {
1145
1146
1147
1149 InlinedCallStack)) {
1150 NumOfMemProfMatchedAllocContexts++;
1156 TotalSize += AllocInfo->Info.getTotalSize();
1158 TotalColdSize += AllocInfo->Info.getTotalSize();
1159
1160
1162 assert(FullStackId != 0);
1163 FullStackIdToAllocMatchInfo[FullStackId] = {
1165 }
1166 }
1167 }
1168
1169
1170
1174 "dominant");
1175 continue;
1176 }
1177
1178
1179
1180
1181 if (!AllocTrie.empty()) {
1182 NumOfMemProfMatchedAllocs++;
1183
1184
1186 assert(MemprofMDAttached == I.hasMetadata(LLVMContext::MD_memprof));
1187 if (MemprofMDAttached) {
1188
1189
1190
1191
1192
1193
1194
1196 }
1197 }
1198 continue;
1199 }
1200
1201
1202
1203
1204 assert(CallSitesIter != LocHashToCallSites.end());
1205 for (auto CallStackIdx : CallSitesIter->second) {
1206
1207
1209 InlinedCallStack)) {
1210 NumOfMemProfMatchedCallSites++;
1212
1213
1214 break;
1215 }
1216 }
1217 }
1218 }
1219}
1220
1223 : MemoryProfileFileName(MemoryProfileFile), FS(FS) {
1224 if (!FS)
1226}
1227
1229
1230 if (M.empty())
1232
1234 auto &Ctx = M.getContext();
1236 if (Error E = ReaderOrErr.takeError()) {
1238 Ctx.diagnose(
1240 });
1242 }
1243
1244 std::unique_ptr MemProfReader =
1245 std::move(ReaderOrErr.get());
1248 MemoryProfileFileName.data(), StringRef("Cannot get MemProfReader")));
1250 }
1251
1254 "Not a memory profile"));
1256 }
1257
1259
1264
1265
1266
1267
1268 std::map<uint64_t, AllocMatchInfo> FullStackIdToAllocMatchInfo;
1269
1270 for (auto &F : M) {
1271 if (F.isDeclaration())
1272 continue;
1273
1276 UndriftMaps);
1277 }
1278
1280 for (const auto &[Id, Info] : FullStackIdToAllocMatchInfo)
1282 << " context with id " << Id << " has total profiled size "
1283 << Info.TotalSize << (Info.Matched ? " is" : " not")
1284 << " matched\n";
1285 }
1286
1288}
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static cl::opt< int > ClDebugMin("asan-debug-min", cl::desc("Debug min inst"), cl::Hidden, cl::init(-1))
static cl::opt< std::string > ClMemoryAccessCallbackPrefix("asan-memory-access-callback-prefix", cl::desc("Prefix for memory access callbacks"), cl::Hidden, cl::init("__asan_"))
static cl::opt< bool > ClInsertVersionCheck("asan-guard-against-version-mismatch", cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden, cl::init(true))
static cl::opt< bool > ClInstrumentWrites("asan-instrument-writes", cl::desc("instrument write instructions"), cl::Hidden, cl::init(true))
static cl::opt< int > ClDebugMax("asan-debug-max", cl::desc("Debug max inst"), cl::Hidden, cl::init(-1))
static cl::opt< bool > ClStack("asan-stack", cl::desc("Handle stack memory"), cl::Hidden, cl::init(true))
static cl::opt< bool > ClInstrumentAtomics("asan-instrument-atomics", cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, cl::init(true))
static cl::opt< int > ClMappingScale("asan-mapping-scale", cl::desc("scale of asan shadow mapping"), cl::Hidden, cl::init(0))
static cl::opt< std::string > ClDebugFunc("asan-debug-func", cl::Hidden, cl::desc("Debug func"))
static cl::opt< bool > ClInstrumentReads("asan-instrument-reads", cl::desc("instrument read instructions"), cl::Hidden, cl::init(true))
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Analysis containing CSE Info
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Module.h This file contains the declarations for the Module class.
static cl::opt< int > ClMappingGranularity("memprof-mapping-granularity", cl::desc("granularity of memprof shadow mapping"), cl::Hidden, cl::init(DefaultMemGranularity))
constexpr char MemProfVersionCheckNamePrefix[]
static cl::opt< int > ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"), cl::Hidden, cl::init(-1))
void createMemprofHistogramFlagVar(Module &M)
constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority
static uint64_t computeFullStackId(ArrayRef< Frame > CallStack)
static cl::opt< std::string > MemprofRuntimeDefaultOptions("memprof-runtime-default-options", cl::desc("The default memprof options"), cl::Hidden, cl::init(""))
static cl::opt< std::string > ClDebugFunc("memprof-debug-func", cl::Hidden, cl::desc("Debug func"))
constexpr char MemProfShadowMemoryDynamicAddress[]
static void addCallsiteMetadata(Instruction &I, ArrayRef< uint64_t > InlinedCallStack, LLVMContext &Ctx)
static bool isAllocationWithHotColdVariant(const Function *Callee, const TargetLibraryInfo &TLI)
constexpr uint64_t MemProfCtorAndDtorPriority
constexpr int LLVM_MEM_PROFILER_VERSION
static cl::opt< bool > ClUseCalls("memprof-use-callbacks", cl::desc("Use callbacks instead of inline instrumentation sequences."), cl::Hidden, cl::init(false))
static cl::opt< bool > ClInstrumentAtomics("memprof-instrument-atomics", cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, cl::init(true))
static cl::opt< bool > ClInsertVersionCheck("memprof-guard-against-version-mismatch", cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden, cl::init(true))
constexpr char MemProfInitName[]
constexpr char MemProfFilenameVar[]
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 > ClStack("memprof-instrument-stack", cl::desc("Instrument scalar stack variables"), cl::Hidden, cl::init(false))
static cl::opt< bool > ClHistogram("memprof-histogram", cl::desc("Collect access count histograms"), cl::Hidden, cl::init(false))
constexpr uint64_t DefaultMemGranularity
void createMemprofDefaultOptionsVar(Module &M)
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))
constexpr uint64_t HistogramGranularity
constexpr uint64_t DefaultShadowScale
cl::opt< bool > MemProfReportHintedSizes
static cl::opt< std::string > ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix", cl::desc("Prefix for memory access callbacks"), cl::Hidden, cl::init("__memprof_"))
constexpr char MemProfModuleCtorName[]
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 > ClInstrumentReads("memprof-instrument-reads", cl::desc("instrument read instructions"), cl::Hidden, cl::init(true))
static cl::opt< int > ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"), cl::Hidden, cl::init(-1))
static cl::opt< bool > ClInstrumentWrites("memprof-instrument-writes", cl::desc("instrument write instructions"), cl::Hidden, cl::init(true))
static cl::opt< int > ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden, cl::init(0))
static cl::opt< int > ClMappingScale("memprof-mapping-scale", cl::desc("scale of memprof shadow mapping"), cl::Hidden, cl::init(DefaultShadowScale))
static void readMemprof(Module &M, Function &F, IndexedInstrProfReader *MemProfReader, const TargetLibraryInfo &TLI, std::map< uint64_t, AllocMatchInfo > &FullStackIdToAllocMatchInfo, DenseMap< uint64_t, LocToLocMap > &UndriftMaps)
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)
constexpr char MemProfHistogramFlagVar[]
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"))
static bool stackFrameIncludesInlinedCallStack(ArrayRef< Frame > ProfileCallStack, ArrayRef< uint64_t > InlinedCallStack)
cl::opt< bool > MemProfReportHintedSizes("memprof-report-hinted-sizes", cl::init(false), cl::Hidden, cl::desc("Report total allocation sizes of hinted allocations"))
FunctionAnalysisManager FAM
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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)
Defines the virtual file system interface vfs::FileSystem.
Class for arbitrary precision integers.
A container for analyses that lazily runs them and caches their results.
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),...
An instruction that atomically checks whether a specified value is in a memory location,...
an instruction that atomically reads a memory location, combines it with another value,...
static Constant * getString(LLVMContext &Context, StringRef Initializer, bool AddNull=true)
This method constructs a CDS and initializes it with a text string.
This is an important base class in LLVM.
static Constant * getIntegerValue(Type *Ty, const APInt &V)
Return the value for an integer or pointer constant, or a vector thereof, with the given scalar value...
A parsed version of the target data layout string in and methods for querying it.
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Diagnostic information for the PGO profiler.
Base class for error info classes.
virtual std::string message() const
Return the error message as a string.
Lightweight error class with error context and mandatory checking.
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
void setComdat(Comdat *C)
void setLinkage(LinkageTypes LT)
GUID getGUID() const
Return a 64-bit global unique ID constructed from global value name (i.e.
@ ExternalLinkage
Externally visible function.
@ WeakAnyLinkage
Keep one copy of named function when linking (weak)
@ AvailableExternallyLinkage
Available for inspection, not emission.
HashResultTy< HasherT_ > final()
Forward to HasherT::final() if available.
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.
Value * CreateICmpULT(Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Value * CreatePointerCast(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Value * CreateGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Type * getVoidTy()
Fetch the type representing void.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
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.
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
instrprof_error get() const
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.
An instruction for reading from memory.
StringRef getString() const
This is the common base class for memset/memcpy/memmove.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
MemProfUsePass(std::string MemoryProfileFile, IntrusiveRefCntPtr< vfs::FileSystem > FS=nullptr)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
A Module instance is used to store all the information related to an LLVM module.
static PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
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.
Triple - Helper class for working with autoconf configuration names.
ObjectFormatType getObjectFormat() const
Get the object format for this triple.
bool isOSEmscripten() const
Tests whether the OS is Emscripten.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt1Ty(LLVMContext &C)
unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
static IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static IntegerType * getInt8Ty(LLVMContext &C)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
StringRef getName() const
Return a constant reference to the value's name.
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,...
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.
void addSingleAllocTypeAttribute(CallBase *CI, AllocationType AT, StringRef Descriptor)
Add an attribute for the given allocation type to the call instruction.
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...
void instrumentAddress(Module &M, IRBuilder<> &IRB, Instruction *OrigIns, Instruction *InsertBefore, Value *Addr, Align Alignment, TypeSize TypeStoreSize, bool IsWrite, Value *SizeArgument, bool UseCalls, bool Recover, int AsanScale, int AsanOffset)
Instrument the memory operand Addr.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ C
The default llvm calling convention, compatible with C.
initializer< Ty > init(const Ty &Val)
DenseMap< uint64_t, LocToLocMap > computeUndriftMap(Module &M, IndexedInstrProfReader *MemProfReader, const TargetLibraryInfo &TLI)
MDNode * buildCallstackMetadata(ArrayRef< uint64_t > CallStack, LLVMContext &Ctx)
Build callstack metadata from the provided list of call stack ids.
AllocationType getAllocType(uint64_t TotalLifetimeAccessDensity, uint64_t AllocCount, uint64_t TotalLifetime)
Return the allocation type for a given set of memory profile values.
DenseMap< uint64_t, SmallVector< CallEdgeTy, 0 > > extractCallsFromIR(Module &M, const TargetLibraryInfo &TLI, function_ref< bool(uint64_t)> IsPresentInProfile=[](uint64_t) { return true;})
std::unordered_map< LineLocation, LineLocation, LineLocationHash > LocToLocMap
std::string getAllocTypeAttributeString(AllocationType Type)
Returns the string to use in attributes with the given type.
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.
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=6)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
cl::opt< bool > PGOWarnMissing
auto unique(Range &&R, Predicate P)
std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
std::array< uint8_t, NumBytes > BLAKE3Result
The constant LLVM_BLAKE3_OUT_LEN provides the default output length, 32 bytes, which is recommended f...
FunctionCallee declareSanitizerInitFunction(Module &M, StringRef InitName, ArrayRef< Type * > InitArgTypes, bool Weak=false)
std::pair< Function *, FunctionCallee > createSanitizerCtorAndInitFunctions(Module &M, StringRef CtorName, StringRef InitName, ArrayRef< Type * > InitArgTypes, ArrayRef< Value * > InitArgs, StringRef VersionCheckName=StringRef(), bool Weak=false)
Creates sanitizer constructor function, and calls sanitizer's init function from it.
void sort(IteratorTy Start, IteratorTy End)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
cl::opt< bool > NoPGOWarnMismatch
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
void appendToCompilerUsed(Module &M, ArrayRef< GlobalValue * > Values)
Adds global values to the llvm.compiler.used list.
void createProfileFileNameVar(Module &M, StringRef InstrProfileOutput)
void appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Append F to the list of global ctors of module M with the given Priority.
Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
cl::opt< bool > NoPGOWarnMismatchComdatWeak
Summary of memprof metadata on allocations.
GlobalValue::GUID Function
static GlobalValue::GUID getGUID(const StringRef FunctionName)
llvm::SmallVector< std::vector< Frame > > CallSites
llvm::SmallVector< AllocationInfo > AllocSites