File indexing completed on 2026-05-10 08:43:15
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #ifndef LLVM_ANALYSIS_MEMORYPROFILEINFO_H
0014 #define LLVM_ANALYSIS_MEMORYPROFILEINFO_H
0015
0016 #include "llvm/IR/Metadata.h"
0017 #include "llvm/IR/ModuleSummaryIndex.h"
0018 #include <map>
0019
0020 namespace llvm {
0021 namespace memprof {
0022
0023
0024 AllocationType getAllocType(uint64_t TotalLifetimeAccessDensity,
0025 uint64_t AllocCount, uint64_t TotalLifetime);
0026
0027
0028
0029 MDNode *buildCallstackMetadata(ArrayRef<uint64_t> CallStack, LLVMContext &Ctx);
0030
0031
0032
0033 MDNode *buildContextSizeMetadata(ArrayRef<ContextTotalSize> ContextSizeInfo,
0034 LLVMContext &Ctx);
0035
0036
0037 MDNode *getMIBStackNode(const MDNode *MIB);
0038
0039
0040 AllocationType getMIBAllocType(const MDNode *MIB);
0041
0042
0043 std::string getAllocTypeAttributeString(AllocationType Type);
0044
0045
0046 bool hasSingleAllocType(uint8_t AllocTypes);
0047
0048
0049
0050
0051
0052
0053 class CallStackTrie {
0054 private:
0055 struct CallStackTrieNode {
0056
0057
0058 uint8_t AllocTypes;
0059
0060
0061
0062
0063 std::vector<ContextTotalSize> ContextSizeInfo;
0064
0065 std::map<uint64_t, CallStackTrieNode *> Callers;
0066 CallStackTrieNode(AllocationType Type)
0067 : AllocTypes(static_cast<uint8_t>(Type)) {}
0068 void addAllocType(AllocationType AllocType) {
0069 AllocTypes |= static_cast<uint8_t>(AllocType);
0070 }
0071 void removeAllocType(AllocationType AllocType) {
0072 AllocTypes &= ~static_cast<uint8_t>(AllocType);
0073 }
0074 bool hasAllocType(AllocationType AllocType) const {
0075 return AllocTypes & static_cast<uint8_t>(AllocType);
0076 }
0077 };
0078
0079
0080 CallStackTrieNode *Alloc = nullptr;
0081
0082 uint64_t AllocStackId = 0;
0083
0084 void deleteTrieNode(CallStackTrieNode *Node) {
0085 if (!Node)
0086 return;
0087 for (auto C : Node->Callers)
0088 deleteTrieNode(C.second);
0089 delete Node;
0090 }
0091
0092
0093
0094 void collectContextSizeInfo(CallStackTrieNode *Node,
0095 std::vector<ContextTotalSize> &ContextSizeInfo);
0096
0097
0098
0099
0100 void convertHotToNotCold(CallStackTrieNode *Node);
0101
0102
0103 bool buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
0104 std::vector<uint64_t> &MIBCallStack,
0105 std::vector<Metadata *> &MIBNodes,
0106 bool CalleeHasAmbiguousCallerContext);
0107
0108 public:
0109 CallStackTrie() = default;
0110 ~CallStackTrie() { deleteTrieNode(Alloc); }
0111
0112 bool empty() const { return Alloc == nullptr; }
0113
0114
0115
0116
0117
0118
0119 void addCallStack(AllocationType AllocType, ArrayRef<uint64_t> StackIds,
0120 std::vector<ContextTotalSize> ContextSizeInfo = {});
0121
0122
0123
0124 void addCallStack(MDNode *MIB);
0125
0126
0127
0128
0129
0130
0131
0132
0133 bool buildAndAttachMIBMetadata(CallBase *CI);
0134
0135
0136
0137
0138 void addSingleAllocTypeAttribute(CallBase *CI, AllocationType AT,
0139 StringRef Descriptor);
0140 };
0141
0142
0143
0144
0145
0146
0147 template <class NodeT, class IteratorT> class CallStack {
0148 public:
0149 CallStack(const NodeT *N = nullptr) : N(N) {}
0150
0151
0152
0153
0154
0155 struct CallStackIterator {
0156 const NodeT *N = nullptr;
0157 IteratorT Iter;
0158 CallStackIterator(const NodeT *N, bool End);
0159 uint64_t operator*();
0160 bool operator==(const CallStackIterator &rhs) { return Iter == rhs.Iter; }
0161 bool operator!=(const CallStackIterator &rhs) { return !(*this == rhs); }
0162 void operator++() { ++Iter; }
0163 };
0164
0165 bool empty() const { return N == nullptr; }
0166
0167 CallStackIterator begin() const;
0168 CallStackIterator end() const { return CallStackIterator(N, true); }
0169 CallStackIterator beginAfterSharedPrefix(CallStack &Other);
0170 uint64_t back() const;
0171
0172 private:
0173 const NodeT *N = nullptr;
0174 };
0175
0176 template <class NodeT, class IteratorT>
0177 CallStack<NodeT, IteratorT>::CallStackIterator::CallStackIterator(
0178 const NodeT *N, bool End)
0179 : N(N) {
0180 if (!N) {
0181 Iter = nullptr;
0182 return;
0183 }
0184 Iter = End ? N->StackIdIndices.end() : N->StackIdIndices.begin();
0185 }
0186
0187 template <class NodeT, class IteratorT>
0188 uint64_t CallStack<NodeT, IteratorT>::CallStackIterator::operator*() {
0189 assert(Iter != N->StackIdIndices.end());
0190 return *Iter;
0191 }
0192
0193 template <class NodeT, class IteratorT>
0194 uint64_t CallStack<NodeT, IteratorT>::back() const {
0195 assert(N);
0196 return N->StackIdIndices.back();
0197 }
0198
0199 template <class NodeT, class IteratorT>
0200 typename CallStack<NodeT, IteratorT>::CallStackIterator
0201 CallStack<NodeT, IteratorT>::begin() const {
0202 return CallStackIterator(N, false);
0203 }
0204
0205 template <class NodeT, class IteratorT>
0206 typename CallStack<NodeT, IteratorT>::CallStackIterator
0207 CallStack<NodeT, IteratorT>::beginAfterSharedPrefix(CallStack &Other) {
0208 CallStackIterator Cur = begin();
0209 for (CallStackIterator OtherCur = Other.begin();
0210 Cur != end() && OtherCur != Other.end(); ++Cur, ++OtherCur)
0211 assert(*Cur == *OtherCur);
0212 return Cur;
0213 }
0214
0215
0216 template <>
0217 CallStack<MDNode, MDNode::op_iterator>::CallStackIterator::CallStackIterator(
0218 const MDNode *N, bool End);
0219 template <>
0220 uint64_t CallStack<MDNode, MDNode::op_iterator>::CallStackIterator::operator*();
0221 template <> uint64_t CallStack<MDNode, MDNode::op_iterator>::back() const;
0222
0223 }
0224 }
0225
0226 #endif