@@ -27,6 +27,7 @@ extern cl::opt<float> MemProfLifetimeAccessDensityColdThreshold;
2727extern cl::opt<unsigned > MemProfAveLifetimeColdThreshold;
2828extern cl::opt<unsigned > MemProfMinAveLifetimeAccessDensityHotThreshold;
2929extern cl::opt<bool > MemProfUseHotHints;
30+ extern cl::opt<bool > MemProfKeepAllNotColdContexts;
3031
3132namespace {
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