Skip to content

Commit cf44f19

Browse files
[MemProf] Add ambigous memprof attribute (llvm#157204)
To help track allocations that we matched with memprof profiles but for which we weren't able to disambiguate the different hotness contexts, apply an "ambiguous" memprof attribute to all allocations with matched profiles. These will be replaced if we can identify a single hotness type, possibly after cloning. Eventually we plan to translate this to a special hotness hint on the allocation call.
1 parent d949ac6 commit cf44f19

File tree

4 files changed

+46
-7
lines changed

4 files changed

+46
-7
lines changed

llvm/include/llvm/Analysis/MemoryProfileInfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,14 @@ LLVM_ABI std::string getAllocTypeAttributeString(AllocationType Type);
5959
/// True if the AllocTypes bitmask contains just a single type.
6060
LLVM_ABI bool hasSingleAllocType(uint8_t AllocTypes);
6161

62+
/// Removes any existing "ambiguous" memprof attribute. Called before we apply a
63+
/// specific allocation type such as "cold", "notcold", or "hot".
64+
LLVM_ABI void removeAnyExistingAmbiguousAttribute(CallBase *CB);
65+
66+
/// Adds an "ambiguous" memprof attribute to call with a matched allocation
67+
/// profile but that we haven't yet been able to disambiguate.
68+
LLVM_ABI void addAmbiguousAttribute(CallBase *CB);
69+
6270
/// Class to build a trie of call stack contexts for a particular profiled
6371
/// allocation call, along with their associated allocation types.
6472
/// The allocation will be at the root of the trie, which is then used to

llvm/lib/Analysis/MemoryProfileInfo.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,24 @@ bool llvm::memprof::hasSingleAllocType(uint8_t AllocTypes) {
121121
return NumAllocTypes == 1;
122122
}
123123

124+
void llvm::memprof::removeAnyExistingAmbiguousAttribute(CallBase *CB) {
125+
if (!CB->hasFnAttr("memprof"))
126+
return;
127+
assert(CB->getFnAttr("memprof").getValueAsString() == "ambiguous");
128+
CB->removeFnAttr("memprof");
129+
}
130+
131+
void llvm::memprof::addAmbiguousAttribute(CallBase *CB) {
132+
// We may have an existing ambiguous attribute if we are reanalyzing
133+
// after inlining.
134+
if (CB->hasFnAttr("memprof")) {
135+
assert(CB->getFnAttr("memprof").getValueAsString() == "ambiguous");
136+
} else {
137+
auto A = llvm::Attribute::get(CB->getContext(), "memprof", "ambiguous");
138+
CB->addFnAttr(A);
139+
}
140+
}
141+
124142
void CallStackTrie::addCallStack(
125143
AllocationType AllocType, ArrayRef<uint64_t> StackIds,
126144
std::vector<ContextTotalSize> ContextSizeInfo) {
@@ -466,6 +484,9 @@ void CallStackTrie::addSingleAllocTypeAttribute(CallBase *CI, AllocationType AT,
466484
StringRef Descriptor) {
467485
auto AllocTypeString = getAllocTypeAttributeString(AT);
468486
auto A = llvm::Attribute::get(CI->getContext(), "memprof", AllocTypeString);
487+
// After inlining we may be able to convert an existing ambiguous allocation
488+
// to an unambiguous one.
489+
removeAnyExistingAmbiguousAttribute(CI);
469490
CI->addFnAttr(A);
470491
if (MemProfReportHintedSizes) {
471492
std::vector<ContextTotalSize> ContextSizeInfo;
@@ -525,6 +546,7 @@ bool CallStackTrie::buildAndAttachMIBMetadata(CallBase *CI) {
525546
assert(MIBCallStack.size() == 1 &&
526547
"Should only be left with Alloc's location in stack");
527548
CI->setMetadata(LLVMContext::MD_memprof, MDNode::get(Ctx, MIBNodes));
549+
addAmbiguousAttribute(CI);
528550
return true;
529551
}
530552
// If there exists corner case that CallStackTrie has one chain to leaf

llvm/lib/Transforms/IPO/MemProfContextDisambiguation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3965,6 +3965,7 @@ void CallsiteContextGraph<DerivedCCG, FuncTy, CallTy>::identifyClones(
39653965
void ModuleCallsiteContextGraph::updateAllocationCall(
39663966
CallInfo &Call, AllocationType AllocType) {
39673967
std::string AllocTypeString = getAllocTypeAttributeString(AllocType);
3968+
removeAnyExistingAmbiguousAttribute(cast<CallBase>(Call.call()));
39683969
auto A = llvm::Attribute::get(Call.call()->getFunction()->getContext(),
39693970
"memprof", AllocTypeString);
39703971
cast<CallBase>(Call.call())->addFnAttr(A);
@@ -5501,6 +5502,7 @@ bool MemProfContextDisambiguation::applyImport(Module &M) {
55015502
// clone J-1 (J==0 is the original clone and does not have a VMaps
55025503
// entry).
55035504
CBClone = cast<CallBase>((*VMaps[J - 1])[CB]);
5505+
removeAnyExistingAmbiguousAttribute(CBClone);
55045506
CBClone->addFnAttr(A);
55055507
ORE.emit(OptimizationRemark(DEBUG_TYPE, "MemprofAttribute", CBClone)
55065508
<< ore::NV("AllocationCall", CBClone) << " in clone "

llvm/unittests/Analysis/MemoryProfileInfoTest.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef)
228228
CallBase *Call = findCall(*Func, "call");
229229
Trie.buildAndAttachMIBMetadata(Call);
230230

231-
EXPECT_FALSE(Call->hasFnAttr("memprof"));
231+
EXPECT_TRUE(Call->hasFnAttr("memprof"));
232+
EXPECT_EQ(Call->getFnAttr("memprof").getValueAsString(), "ambiguous");
232233
EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
233234
MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
234235
ASSERT_EQ(MemProfMD->getNumOperands(), 2u);
@@ -277,7 +278,8 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef)
277278
CallBase *Call = findCall(*Func, "call");
278279
Trie.buildAndAttachMIBMetadata(Call);
279280

280-
EXPECT_FALSE(Call->hasFnAttr("memprof"));
281+
EXPECT_TRUE(Call->hasFnAttr("memprof"));
282+
EXPECT_EQ(Call->getFnAttr("memprof").getValueAsString(), "ambiguous");
281283
EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
282284
MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
283285
ASSERT_EQ(MemProfMD->getNumOperands(), 2u);
@@ -331,7 +333,8 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef)
331333
CallBase *Call = findCall(*Func, "call");
332334
Trie.buildAndAttachMIBMetadata(Call);
333335

334-
EXPECT_FALSE(Call->hasFnAttr("memprof"));
336+
EXPECT_TRUE(Call->hasFnAttr("memprof"));
337+
EXPECT_EQ(Call->getFnAttr("memprof").getValueAsString(), "ambiguous");
335338
EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
336339
MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
337340
ASSERT_EQ(MemProfMD->getNumOperands(), 2u);
@@ -390,7 +393,8 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef)
390393
CallBase *Call = findCall(*Func, "call");
391394
Trie.buildAndAttachMIBMetadata(Call);
392395

393-
EXPECT_FALSE(Call->hasFnAttr("memprof"));
396+
EXPECT_TRUE(Call->hasFnAttr("memprof"));
397+
EXPECT_EQ(Call->getFnAttr("memprof").getValueAsString(), "ambiguous");
394398
EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
395399
MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
396400
ASSERT_EQ(MemProfMD->getNumOperands(), 2u);
@@ -461,7 +465,8 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef)
461465
ASSERT_NE(Call, nullptr);
462466
Trie.buildAndAttachMIBMetadata(Call);
463467

464-
EXPECT_FALSE(Call->hasFnAttr("memprof"));
468+
EXPECT_TRUE(Call->hasFnAttr("memprof"));
469+
EXPECT_EQ(Call->getFnAttr("memprof").getValueAsString(), "ambiguous");
465470
EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
466471
MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
467472
EXPECT_THAT(MemProfMD, MemprofMetadataEquals(ExpectedVals));
@@ -534,7 +539,8 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef)
534539
// Restore original option value.
535540
MemProfKeepAllNotColdContexts = OrigMemProfKeepAllNotColdContexts;
536541

537-
EXPECT_FALSE(Call->hasFnAttr("memprof"));
542+
EXPECT_TRUE(Call->hasFnAttr("memprof"));
543+
EXPECT_EQ(Call->getFnAttr("memprof").getValueAsString(), "ambiguous");
538544
EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
539545
MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
540546
EXPECT_THAT(MemProfMD, MemprofMetadataEquals(ExpectedVals));
@@ -662,7 +668,8 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef)
662668
// The hot allocations will be converted to NotCold and pruned as they
663669
// are unnecessary to determine how to clone the cold allocation.
664670

665-
EXPECT_FALSE(Call->hasFnAttr("memprof"));
671+
EXPECT_TRUE(Call->hasFnAttr("memprof"));
672+
EXPECT_EQ(Call->getFnAttr("memprof").getValueAsString(), "ambiguous");
666673
EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
667674
MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
668675
ASSERT_EQ(MemProfMD->getNumOperands(), 2u);

0 commit comments

Comments
 (0)