Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions llvm/include/llvm/Analysis/MemoryProfileInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ class CallStackTrie {
// The maximum size of a cold allocation context, from the profile summary.
uint64_t MaxColdSize;

// Tracks whether we have built the Trie from existing MD_memprof metadata. We
// apply different heuristics for determining whether to discard non-cold
// contexts when rebuilding as we have lost information available during the
// original profile match.
bool BuiltFromExistingMetadata = false;

void deleteTrieNode(CallStackTrieNode *Node) {
if (!Node)
return;
Expand Down
41 changes: 28 additions & 13 deletions llvm/lib/Analysis/MemoryProfileInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ void CallStackTrie::addCallStack(
}

void CallStackTrie::addCallStack(MDNode *MIB) {
// Note that we are building this from existing MD_memprof metadata.
BuiltFromExistingMetadata = true;
MDNode *StackMD = getMIBStackNode(MIB);
assert(StackMD);
std::vector<uint64_t> CallStack;
Expand Down Expand Up @@ -187,8 +189,9 @@ void CallStackTrie::addCallStack(MDNode *MIB) {
static MDNode *createMIBNode(LLVMContext &Ctx, ArrayRef<uint64_t> MIBCallStack,
AllocationType AllocType,
ArrayRef<ContextTotalSize> ContextSizeInfo,
const uint64_t MaxColdSize, uint64_t &TotalBytes,
uint64_t &ColdBytes) {
const uint64_t MaxColdSize,
bool BuiltFromExistingMetadata,
uint64_t &TotalBytes, uint64_t &ColdBytes) {
SmallVector<Metadata *> MIBPayload(
{buildCallstackMetadata(MIBCallStack, Ctx)});
MIBPayload.push_back(
Expand All @@ -197,8 +200,9 @@ static MDNode *createMIBNode(LLVMContext &Ctx, ArrayRef<uint64_t> MIBCallStack,
if (ContextSizeInfo.empty()) {
// The profile matcher should have provided context size info if there was a
// MinCallsiteColdBytePercent < 100. Here we check >=100 to gracefully
// handle a user-provided percent larger than 100.
assert(MinCallsiteColdBytePercent >= 100);
// handle a user-provided percent larger than 100. However, we may not have
// this information if we built the Trie from existing MD_memprof metadata.
assert(BuiltFromExistingMetadata || MinCallsiteColdBytePercent >= 100);
return MDNode::get(Ctx, MIBPayload);
}

Expand Down Expand Up @@ -252,9 +256,19 @@ void CallStackTrie::convertHotToNotCold(CallStackTrieNode *Node) {
static void saveFilteredNewMIBNodes(std::vector<Metadata *> &NewMIBNodes,
std::vector<Metadata *> &SavedMIBNodes,
unsigned CallerContextLength,
uint64_t TotalBytes, uint64_t ColdBytes) {
uint64_t TotalBytes, uint64_t ColdBytes,
bool BuiltFromExistingMetadata) {
const bool MostlyCold =
MinCallsiteColdBytePercent < 100 &&
// If we have built the Trie from existing MD_memprof metadata, we may or
// may not have context size information (in which case ColdBytes and
// TotalBytes are 0, which is not also guarded against below). Even if we
// do have some context size information from the the metadata, we have
// already gone through a round of discarding of small non-cold contexts
// during matching, and it would be overly aggressive to do it again, and
// we also want to maintain the same behavior with and without reporting
// of hinted bytes enabled.
!BuiltFromExistingMetadata && MinCallsiteColdBytePercent < 100 &&
ColdBytes > 0 &&
ColdBytes * 100 >= MinCallsiteColdBytePercent * TotalBytes;

// In the simplest case, with pruning disabled, keep all the new MIB nodes.
Expand Down Expand Up @@ -386,9 +400,9 @@ bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
if (hasSingleAllocType(Node->AllocTypes)) {
std::vector<ContextTotalSize> ContextSizeInfo;
collectContextSizeInfo(Node, ContextSizeInfo);
MIBNodes.push_back(
createMIBNode(Ctx, MIBCallStack, (AllocationType)Node->AllocTypes,
ContextSizeInfo, MaxColdSize, TotalBytes, ColdBytes));
MIBNodes.push_back(createMIBNode(
Ctx, MIBCallStack, (AllocationType)Node->AllocTypes, ContextSizeInfo,
MaxColdSize, BuiltFromExistingMetadata, TotalBytes, ColdBytes));
return true;
}

Expand Down Expand Up @@ -416,7 +430,8 @@ bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
// Pass in the stack length of the MIB nodes added for the immediate caller,
// which is the current stack length plus 1.
saveFilteredNewMIBNodes(NewMIBNodes, MIBNodes, MIBCallStack.size() + 1,
CallerTotalBytes, CallerColdBytes);
CallerTotalBytes, CallerColdBytes,
BuiltFromExistingMetadata);
TotalBytes += CallerTotalBytes;
ColdBytes += CallerColdBytes;

Expand All @@ -441,9 +456,9 @@ bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,
return false;
std::vector<ContextTotalSize> ContextSizeInfo;
collectContextSizeInfo(Node, ContextSizeInfo);
MIBNodes.push_back(createMIBNode(Ctx, MIBCallStack, AllocationType::NotCold,
ContextSizeInfo, MaxColdSize, TotalBytes,
ColdBytes));
MIBNodes.push_back(createMIBNode(
Ctx, MIBCallStack, AllocationType::NotCold, ContextSizeInfo, MaxColdSize,
BuiltFromExistingMetadata, TotalBytes, ColdBytes));
return true;
}

Expand Down
3 changes: 3 additions & 0 deletions llvm/test/Transforms/Inline/memprof_inline2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
;; }

; RUN: opt -passes=inline %s -S | FileCheck %s
;; We should not perform additional discarding of non-cold contexts when
;; rebuilding the tries after inlining, even with a very low threshold.
; RUN: opt -passes=inline -memprof-callsite-cold-threshold=1 %s -S | FileCheck %s

; ModuleID = 'memprof_inline2.cc'
source_filename = "memprof_inline2.cc"
Expand Down
Loading
Loading