From b4f734094a97a2e98f1ca46e652eca2af4dac3e1 Mon Sep 17 00:00:00 2001 From: Teresa Johnson Date: Thu, 23 Oct 2025 11:34:07 -0700 Subject: [PATCH] [MemProf] Fix the propagation of context/size info after inlining In certain cases the context/size info we use for reporting of hinted bytes in the LTO link was being dropped when we re-constructed context tries and memprof metadata after inlining. This only affected cases where we were using the -memprof-min-percent-max-cold-size option to only keep that information for the largest cold contexts, and where the pre-LTO compile did *not* specify -memprof-report-hinted-sizes. The issue is that we don't have a MaxSize, which is only available during the profile matching step. Use an existing bool indicating that we are redoing this from existing metadata to always propagate any context size metadata in that case. --- llvm/lib/Analysis/MemoryProfileInfo.cpp | 10 ++++++--- .../Analysis/MemoryProfileInfoTest.cpp | 22 ++++++++++++++++--- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/llvm/lib/Analysis/MemoryProfileInfo.cpp b/llvm/lib/Analysis/MemoryProfileInfo.cpp index 92a5b6f378aab..b09f4ed78ca7e 100644 --- a/llvm/lib/Analysis/MemoryProfileInfo.cpp +++ b/llvm/lib/Analysis/MemoryProfileInfo.cpp @@ -241,9 +241,13 @@ static MDNode *createMIBNode(LLVMContext &Ctx, ArrayRef MIBCallStack, ColdBytes += TotalSize; // If we have the max cold context size from summary information and have // requested identification of contexts above a percentage of the max, see - // if this context qualifies. - if (MaxColdSize > 0 && MinPercentMaxColdSize < 100 && - TotalSize * 100 >= MaxColdSize * MinPercentMaxColdSize) + // if this context qualifies. We should assume this is large if we rebuilt + // the trie from existing metadata (i.e. to update after inlining), in + // which case we don't have a MaxSize from the profile - we assume any + // context size info in existence on the metadata should be propagated. + if (BuiltFromExistingMetadata || + (MaxColdSize > 0 && MinPercentMaxColdSize < 100 && + TotalSize * 100 >= MaxColdSize * MinPercentMaxColdSize)) LargeColdContext = true; } // Only add the context size info as metadata if we need it in the thin diff --git a/llvm/unittests/Analysis/MemoryProfileInfoTest.cpp b/llvm/unittests/Analysis/MemoryProfileInfoTest.cpp index d1c0f643f5cd7..113b05299252b 100644 --- a/llvm/unittests/Analysis/MemoryProfileInfoTest.cpp +++ b/llvm/unittests/Analysis/MemoryProfileInfoTest.cpp @@ -638,7 +638,7 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef) !0 = !{!1, !3, !5, !7, !9, !11} !1 = !{!2, !"cold"} !2 = !{i64 1, i64 2, i64 3} -!3 = !{!4, !"cold"} +!3 = !{!4, !"cold", !13} !4 = !{i64 1, i64 2, i64 4} !5 = !{!6, !"notcold"} !6 = !{i64 1, i64 5, i64 6} @@ -648,6 +648,7 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef) !10 = !{i64 1, i64 8, i64 9} !11 = !{!12, !"hot"} !12 = !{i64 1, i64 8, i64 10} +!13 = !{i64 123, i64 456} )IR"); Function *Func = M->getFunction("test"); @@ -683,10 +684,25 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef) auto *StackId = mdconst::dyn_extract(StackMD->getOperand(0)); EXPECT_EQ(StackId->getZExtValue(), 1u); StackId = mdconst::dyn_extract(StackMD->getOperand(1)); - if (StackId->getZExtValue() == 2u) + if (StackId->getZExtValue() == 2u) { EXPECT_EQ(getMIBAllocType(MIB), AllocationType::Cold); - else if (StackId->getZExtValue() == 5u) + // We should propagate the single context size info from the second cold + // context above onto the new merged/trimmed context. + ASSERT_EQ(MIB->getNumOperands(), 3u); + MDNode *ContextSizePair = dyn_cast(MIB->getOperand(2)); + assert(ContextSizePair->getNumOperands() == 2); + EXPECT_EQ( + mdconst::dyn_extract(ContextSizePair->getOperand(0)) + ->getZExtValue(), + 123u); + EXPECT_EQ( + mdconst::dyn_extract(ContextSizePair->getOperand(1)) + ->getZExtValue(), + 456u); + } else if (StackId->getZExtValue() == 5u) { EXPECT_EQ(getMIBAllocType(MIB), AllocationType::NotCold); + ASSERT_EQ(MIB->getNumOperands(), 2u); + } } }