1 //===-- MemoryProfileInfo.cpp - memory profile info ------------------------==//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains utilities to analyze memory profile information.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/Analysis/MemoryProfileInfo.h"
14 #include "llvm/Support/CommandLine.h"
17 using namespace llvm::memprof
;
19 #define DEBUG_TYPE "memory-profile-info"
21 // Upper bound on lifetime access density (accesses per byte per lifetime sec)
22 // for marking an allocation cold.
23 cl::opt
<float> MemProfLifetimeAccessDensityColdThreshold(
24 "memprof-lifetime-access-density-cold-threshold", cl::init(0.05),
26 cl::desc("The threshold the lifetime access density (accesses per byte per "
27 "lifetime sec) must be under to consider an allocation cold"));
29 // Lower bound on lifetime to mark an allocation cold (in addition to accesses
30 // per byte per sec above). This is to avoid pessimizing short lived objects.
31 cl::opt
<unsigned> MemProfAveLifetimeColdThreshold(
32 "memprof-ave-lifetime-cold-threshold", cl::init(200), cl::Hidden
,
33 cl::desc("The average lifetime (s) for an allocation to be considered "
36 // Lower bound on average lifetime accesses density (total life time access
37 // density / alloc count) for marking an allocation hot.
38 cl::opt
<unsigned> MemProfMinAveLifetimeAccessDensityHotThreshold(
39 "memprof-min-ave-lifetime-access-density-hot-threshold", cl::init(1000),
41 cl::desc("The minimum TotalLifetimeAccessDensity / AllocCount for an "
42 "allocation to be considered hot"));
44 AllocationType
llvm::memprof::getAllocType(uint64_t TotalLifetimeAccessDensity
,
46 uint64_t TotalLifetime
) {
47 // The access densities are multiplied by 100 to hold 2 decimal places of
48 // precision, so need to divide by 100.
49 if (((float)TotalLifetimeAccessDensity
) / AllocCount
/ 100 <
50 MemProfLifetimeAccessDensityColdThreshold
51 // Lifetime is expected to be in ms, so convert the threshold to ms.
52 && ((float)TotalLifetime
) / AllocCount
>=
53 MemProfAveLifetimeColdThreshold
* 1000)
54 return AllocationType::Cold
;
56 // The access densities are multiplied by 100 to hold 2 decimal places of
57 // precision, so need to divide by 100.
58 if (((float)TotalLifetimeAccessDensity
) / AllocCount
/ 100 >
59 MemProfMinAveLifetimeAccessDensityHotThreshold
)
60 return AllocationType::Hot
;
62 return AllocationType::NotCold
;
65 MDNode
*llvm::memprof::buildCallstackMetadata(ArrayRef
<uint64_t> CallStack
,
67 std::vector
<Metadata
*> StackVals
;
68 for (auto Id
: CallStack
) {
70 ValueAsMetadata::get(ConstantInt::get(Type::getInt64Ty(Ctx
), Id
));
71 StackVals
.push_back(StackValMD
);
73 return MDNode::get(Ctx
, StackVals
);
76 MDNode
*llvm::memprof::getMIBStackNode(const MDNode
*MIB
) {
77 assert(MIB
->getNumOperands() == 2);
78 // The stack metadata is the first operand of each memprof MIB metadata.
79 return cast
<MDNode
>(MIB
->getOperand(0));
82 AllocationType
llvm::memprof::getMIBAllocType(const MDNode
*MIB
) {
83 assert(MIB
->getNumOperands() == 2);
84 // The allocation type is currently the second operand of each memprof
85 // MIB metadata. This will need to change as we add additional allocation
86 // types that can be applied based on the allocation profile data.
87 auto *MDS
= dyn_cast
<MDString
>(MIB
->getOperand(1));
89 if (MDS
->getString().equals("cold")) {
90 return AllocationType::Cold
;
91 } else if (MDS
->getString().equals("hot")) {
92 return AllocationType::Hot
;
94 return AllocationType::NotCold
;
97 std::string
llvm::memprof::getAllocTypeAttributeString(AllocationType Type
) {
99 case AllocationType::NotCold
:
102 case AllocationType::Cold
:
105 case AllocationType::Hot
:
109 assert(false && "Unexpected alloc type");
111 llvm_unreachable("invalid alloc type");
114 static void addAllocTypeAttribute(LLVMContext
&Ctx
, CallBase
*CI
,
115 AllocationType AllocType
) {
116 auto AllocTypeString
= getAllocTypeAttributeString(AllocType
);
117 auto A
= llvm::Attribute::get(Ctx
, "memprof", AllocTypeString
);
121 bool llvm::memprof::hasSingleAllocType(uint8_t AllocTypes
) {
122 const unsigned NumAllocTypes
= llvm::popcount(AllocTypes
);
123 assert(NumAllocTypes
!= 0);
124 return NumAllocTypes
== 1;
127 void CallStackTrie::addCallStack(AllocationType AllocType
,
128 ArrayRef
<uint64_t> StackIds
) {
130 CallStackTrieNode
*Curr
= nullptr;
131 for (auto StackId
: StackIds
) {
132 // If this is the first stack frame, add or update alloc node.
136 assert(AllocStackId
== StackId
);
137 Alloc
->AllocTypes
|= static_cast<uint8_t>(AllocType
);
139 AllocStackId
= StackId
;
140 Alloc
= new CallStackTrieNode(AllocType
);
145 // Update existing caller node if it exists.
146 auto Next
= Curr
->Callers
.find(StackId
);
147 if (Next
!= Curr
->Callers
.end()) {
149 Curr
->AllocTypes
|= static_cast<uint8_t>(AllocType
);
152 // Otherwise add a new caller node.
153 auto *New
= new CallStackTrieNode(AllocType
);
154 Curr
->Callers
[StackId
] = New
;
160 void CallStackTrie::addCallStack(MDNode
*MIB
) {
161 MDNode
*StackMD
= getMIBStackNode(MIB
);
163 std::vector
<uint64_t> CallStack
;
164 CallStack
.reserve(StackMD
->getNumOperands());
165 for (const auto &MIBStackIter
: StackMD
->operands()) {
166 auto *StackId
= mdconst::dyn_extract
<ConstantInt
>(MIBStackIter
);
168 CallStack
.push_back(StackId
->getZExtValue());
170 addCallStack(getMIBAllocType(MIB
), CallStack
);
173 static MDNode
*createMIBNode(LLVMContext
&Ctx
,
174 std::vector
<uint64_t> &MIBCallStack
,
175 AllocationType AllocType
) {
176 std::vector
<Metadata
*> MIBPayload(
177 {buildCallstackMetadata(MIBCallStack
, Ctx
)});
178 MIBPayload
.push_back(
179 MDString::get(Ctx
, getAllocTypeAttributeString(AllocType
)));
180 return MDNode::get(Ctx
, MIBPayload
);
183 // Recursive helper to trim contexts and create metadata nodes.
184 // Caller should have pushed Node's loc to MIBCallStack. Doing this in the
185 // caller makes it simpler to handle the many early returns in this method.
186 bool CallStackTrie::buildMIBNodes(CallStackTrieNode
*Node
, LLVMContext
&Ctx
,
187 std::vector
<uint64_t> &MIBCallStack
,
188 std::vector
<Metadata
*> &MIBNodes
,
189 bool CalleeHasAmbiguousCallerContext
) {
190 // Trim context below the first node in a prefix with a single alloc type.
191 // Add an MIB record for the current call stack prefix.
192 if (hasSingleAllocType(Node
->AllocTypes
)) {
194 createMIBNode(Ctx
, MIBCallStack
, (AllocationType
)Node
->AllocTypes
));
198 // We don't have a single allocation for all the contexts sharing this prefix,
199 // so recursively descend into callers in trie.
200 if (!Node
->Callers
.empty()) {
201 bool NodeHasAmbiguousCallerContext
= Node
->Callers
.size() > 1;
202 bool AddedMIBNodesForAllCallerContexts
= true;
203 for (auto &Caller
: Node
->Callers
) {
204 MIBCallStack
.push_back(Caller
.first
);
205 AddedMIBNodesForAllCallerContexts
&=
206 buildMIBNodes(Caller
.second
, Ctx
, MIBCallStack
, MIBNodes
,
207 NodeHasAmbiguousCallerContext
);
209 MIBCallStack
.pop_back();
211 if (AddedMIBNodesForAllCallerContexts
)
213 // We expect that the callers should be forced to add MIBs to disambiguate
214 // the context in this case (see below).
215 assert(!NodeHasAmbiguousCallerContext
);
218 // If we reached here, then this node does not have a single allocation type,
219 // and we didn't add metadata for a longer call stack prefix including any of
220 // Node's callers. That means we never hit a single allocation type along all
221 // call stacks with this prefix. This can happen due to recursion collapsing
222 // or the stack being deeper than tracked by the profiler runtime, leading to
223 // contexts with different allocation types being merged. In that case, we
224 // trim the context just below the deepest context split, which is this
225 // node if the callee has an ambiguous caller context (multiple callers),
226 // since the recursive calls above returned false. Conservatively give it
227 // non-cold allocation type.
228 if (!CalleeHasAmbiguousCallerContext
)
230 MIBNodes
.push_back(createMIBNode(Ctx
, MIBCallStack
, AllocationType::NotCold
));
234 // Build and attach the minimal necessary MIB metadata. If the alloc has a
235 // single allocation type, add a function attribute instead. Returns true if
236 // memprof metadata attached, false if not (attribute added).
237 bool CallStackTrie::buildAndAttachMIBMetadata(CallBase
*CI
) {
238 auto &Ctx
= CI
->getContext();
239 if (hasSingleAllocType(Alloc
->AllocTypes
)) {
240 addAllocTypeAttribute(Ctx
, CI
, (AllocationType
)Alloc
->AllocTypes
);
243 std::vector
<uint64_t> MIBCallStack
;
244 MIBCallStack
.push_back(AllocStackId
);
245 std::vector
<Metadata
*> MIBNodes
;
246 assert(!Alloc
->Callers
.empty() && "addCallStack has not been called yet");
247 buildMIBNodes(Alloc
, Ctx
, MIBCallStack
, MIBNodes
,
248 /*CalleeHasAmbiguousCallerContext=*/true);
249 assert(MIBCallStack
.size() == 1 &&
250 "Should only be left with Alloc's location in stack");
251 CI
->setMetadata(LLVMContext::MD_memprof
, MDNode::get(Ctx
, MIBNodes
));
256 CallStack
<MDNode
, MDNode::op_iterator
>::CallStackIterator::CallStackIterator(
257 const MDNode
*N
, bool End
)
261 Iter
= End
? N
->op_end() : N
->op_begin();
266 CallStack
<MDNode
, MDNode::op_iterator
>::CallStackIterator::operator*() {
267 assert(Iter
!= N
->op_end());
268 ConstantInt
*StackIdCInt
= mdconst::dyn_extract
<ConstantInt
>(*Iter
);
270 return StackIdCInt
->getZExtValue();
273 template <> uint64_t CallStack
<MDNode
, MDNode::op_iterator
>::back() const {
275 return mdconst::dyn_extract
<ConstantInt
>(N
->operands().back())