Skip to content

Commit 9c4c242

Browse files
[MemProf] Fix bug introduced by restructuring in optional handling (#139092)
The restructuring of the context pruning patch in PR138792 (764614e) introduced a bug under the non-default -memprof-keep-all-not-cold-contexts handling. Added more testing of this mode which would have caught the issue. While here, fix the newly added function name to match code style.
1 parent 55517f5 commit 9c4c242

File tree

2 files changed

+79
-4
lines changed

2 files changed

+79
-4
lines changed

llvm/lib/Analysis/MemoryProfileInfo.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ cl::opt<bool> MemProfReportHintedSizes(
5454
// This is useful if we have enabled reporting of hinted sizes, and want to get
5555
// information from the indexing step for all contexts (especially for testing),
5656
// or have specified a value less than 100% for -memprof-cloning-cold-threshold.
57-
static cl::opt<bool> MemProfKeepAllNotColdContexts(
57+
cl::opt<bool> MemProfKeepAllNotColdContexts(
5858
"memprof-keep-all-not-cold-contexts", cl::init(false), cl::Hidden,
5959
cl::desc("Keep all non-cold contexts (increases cloning overheads)"));
6060

@@ -244,12 +244,14 @@ void CallStackTrie::convertHotToNotCold(CallStackTrieNode *Node) {
244244

245245
// Copy over some or all of NewMIBNodes to the SavedMIBNodes vector, depending
246246
// on options that enable filtering out some NotCold contexts.
247-
static void SaveFilteredNewMIBNodes(std::vector<Metadata *> &NewMIBNodes,
247+
static void saveFilteredNewMIBNodes(std::vector<Metadata *> &NewMIBNodes,
248248
std::vector<Metadata *> &SavedMIBNodes,
249249
unsigned CallerContextLength) {
250250
// In the simplest case, with pruning disabled, keep all the new MIB nodes.
251-
if (MemProfKeepAllNotColdContexts)
251+
if (MemProfKeepAllNotColdContexts) {
252252
append_range(SavedMIBNodes, NewMIBNodes);
253+
return;
254+
}
253255

254256
auto EmitMessageForRemovedContexts = [](const MDNode *MIBMD, StringRef Tag,
255257
StringRef Extra) {
@@ -372,7 +374,7 @@ bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
372374
}
373375
// Pass in the stack length of the MIB nodes added for the immediate caller,
374376
// which is the current stack length plus 1.
375-
SaveFilteredNewMIBNodes(NewMIBNodes, MIBNodes, MIBCallStack.size() + 1);
377+
saveFilteredNewMIBNodes(NewMIBNodes, MIBNodes, MIBCallStack.size() + 1);
376378
if (AddedMIBNodesForAllCallerContexts)
377379
return true;
378380
// We expect that the callers should be forced to add MIBs to disambiguate

llvm/unittests/Analysis/MemoryProfileInfoTest.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ extern cl::opt<float> MemProfLifetimeAccessDensityColdThreshold;
2727
extern cl::opt<unsigned> MemProfAveLifetimeColdThreshold;
2828
extern cl::opt<unsigned> MemProfMinAveLifetimeAccessDensityHotThreshold;
2929
extern cl::opt<bool> MemProfUseHotHints;
30+
extern cl::opt<bool> MemProfKeepAllNotColdContexts;
3031

3132
namespace {
3233

@@ -530,6 +531,78 @@ declare dso_local noalias noundef i8* @malloc(i64 noundef)
530531
EXPECT_THAT(MemProfMD, MemprofMetadataEquals(ExpectedVals));
531532
}
532533

534+
// Test to ensure that we keep optionally keep unneeded NotCold contexts.
535+
// Same as PruneUnneededNotColdContexts test but with the
536+
// MemProfKeepAllNotColdContexts set to true.
537+
TEST_F(MemoryProfileInfoTest, KeepUnneededNotColdContexts) {
538+
LLVMContext C;
539+
std::unique_ptr<Module> M = makeLLVMModule(C,
540+
R"IR(
541+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
542+
target triple = "x86_64-pc-linux-gnu"
543+
define i32* @test() {
544+
entry:
545+
%call = call noalias dereferenceable_or_null(40) i8* @malloc(i64 noundef 40)
546+
%0 = bitcast i8* %call to i32*
547+
ret i32* %0
548+
}
549+
declare dso_local noalias noundef i8* @malloc(i64 noundef)
550+
)IR");
551+
552+
Function *Func = M->getFunction("test");
553+
554+
CallStackTrie Trie;
555+
556+
Trie.addCallStack(AllocationType::Cold, {1, 2, 3, 4});
557+
Trie.addCallStack(AllocationType::Cold, {1, 2, 3, 5, 6, 7});
558+
// This NotCold context is needed to know where the above two Cold contexts
559+
// must be cloned from:
560+
Trie.addCallStack(AllocationType::NotCold, {1, 2, 3, 5, 6, 13});
561+
562+
Trie.addCallStack(AllocationType::Cold, {1, 2, 3, 8, 9, 10});
563+
// This NotCold context is needed to know where the above Cold context must be
564+
// cloned from:
565+
Trie.addCallStack(AllocationType::NotCold, {1, 2, 3, 8, 9, 14});
566+
// This NotCold context is not needed since the above is sufficient (we pick
567+
// the first in sorted order).
568+
Trie.addCallStack(AllocationType::NotCold, {1, 2, 3, 8, 9, 15});
569+
570+
// None of these NotCold contexts are needed as the Cold contexts they
571+
// overlap with are covered by longer overlapping NotCold contexts.
572+
Trie.addCallStack(AllocationType::NotCold, {1, 2, 3, 12});
573+
Trie.addCallStack(AllocationType::NotCold, {1, 2, 11});
574+
Trie.addCallStack(AllocationType::NotCold, {1, 16});
575+
576+
// We should keep all of the above contexts, even those that are unneeded by
577+
// default, because we will set the option to keep them.
578+
std::vector<std::pair<AllocationType, std::vector<unsigned>>> ExpectedVals = {
579+
{AllocationType::Cold, {1, 2, 3, 4}},
580+
{AllocationType::Cold, {1, 2, 3, 5, 6, 7}},
581+
{AllocationType::NotCold, {1, 2, 3, 5, 6, 13}},
582+
{AllocationType::Cold, {1, 2, 3, 8, 9, 10}},
583+
{AllocationType::NotCold, {1, 2, 3, 8, 9, 14}},
584+
{AllocationType::NotCold, {1, 2, 3, 8, 9, 15}},
585+
{AllocationType::NotCold, {1, 2, 3, 12}},
586+
{AllocationType::NotCold, {1, 2, 11}},
587+
{AllocationType::NotCold, {1, 16}}};
588+
589+
CallBase *Call = findCall(*Func, "call");
590+
ASSERT_NE(Call, nullptr);
591+
592+
// Specify that all non-cold contexts should be kept.
593+
MemProfKeepAllNotColdContexts = true;
594+
595+
Trie.buildAndAttachMIBMetadata(Call);
596+
597+
// Undo the manual set of the MemProfKeepAllNotColdContexts above.
598+
cl::ResetAllOptionOccurrences();
599+
600+
EXPECT_FALSE(Call->hasFnAttr("memprof"));
601+
EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
602+
MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
603+
EXPECT_THAT(MemProfMD, MemprofMetadataEquals(ExpectedVals));
604+
}
605+
533606
// Test CallStackTrie::addCallStack interface taking memprof MIB metadata.
534607
// Check that allocations annotated with memprof metadata with a single
535608
// allocation type get simplified to an attribute.

0 commit comments

Comments
 (0)