diff --git a/llvm/include/llvm/Analysis/MemoryProfileInfo.h b/llvm/include/llvm/Analysis/MemoryProfileInfo.h index b46124a4ed0d5..215139caef696 100644 --- a/llvm/include/llvm/Analysis/MemoryProfileInfo.h +++ b/llvm/include/llvm/Analysis/MemoryProfileInfo.h @@ -117,6 +117,12 @@ class CallStackTrie { /// which is lower overhead and more direct than maintaining this metadata. /// Returns true if memprof metadata attached, false if not (attribute added). bool buildAndAttachMIBMetadata(CallBase *CI); + + /// Add an attribute for the given allocation type to the call instruction. + /// If hinted by reporting is enabled, a message is emitted with the given + /// descriptor used to identify the category of single allocation type. + void addSingleAllocTypeAttribute(CallBase *CI, AllocationType AT, + StringRef Descriptor); }; /// Helper class to iterate through stack ids in both metadata (memprof MIB and diff --git a/llvm/lib/Analysis/MemoryProfileInfo.cpp b/llvm/lib/Analysis/MemoryProfileInfo.cpp index 217f304e30de1..1c3f589e84941 100644 --- a/llvm/lib/Analysis/MemoryProfileInfo.cpp +++ b/llvm/lib/Analysis/MemoryProfileInfo.cpp @@ -278,26 +278,30 @@ bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx, return true; } +void CallStackTrie::addSingleAllocTypeAttribute(CallBase *CI, AllocationType AT, + StringRef Descriptor) { + addAllocTypeAttribute(CI->getContext(), CI, AT); + if (MemProfReportHintedSizes) { + std::vector ContextSizeInfo; + collectContextSizeInfo(Alloc, ContextSizeInfo); + for (const auto &[FullStackId, TotalSize] : ContextSizeInfo) { + errs() << "MemProf hinting: Total size for full allocation context hash " + << FullStackId << " and " << Descriptor << " alloc type " + << getAllocTypeAttributeString(AT) << ": " << TotalSize << "\n"; + } + } +} + // Build and attach the minimal necessary MIB metadata. If the alloc has a // single allocation type, add a function attribute instead. Returns true if // memprof metadata attached, false if not (attribute added). bool CallStackTrie::buildAndAttachMIBMetadata(CallBase *CI) { - auto &Ctx = CI->getContext(); if (hasSingleAllocType(Alloc->AllocTypes)) { - addAllocTypeAttribute(Ctx, CI, (AllocationType)Alloc->AllocTypes); - if (MemProfReportHintedSizes) { - std::vector ContextSizeInfo; - collectContextSizeInfo(Alloc, ContextSizeInfo); - for (const auto &[FullStackId, TotalSize] : ContextSizeInfo) { - errs() - << "MemProf hinting: Total size for full allocation context hash " - << FullStackId << " and single alloc type " - << getAllocTypeAttributeString((AllocationType)Alloc->AllocTypes) - << ": " << TotalSize << "\n"; - } - } + addSingleAllocTypeAttribute(CI, (AllocationType)Alloc->AllocTypes, + "single"); return false; } + auto &Ctx = CI->getContext(); std::vector MIBCallStack; MIBCallStack.push_back(AllocStackId); std::vector MIBNodes; @@ -314,8 +318,9 @@ bool CallStackTrie::buildAndAttachMIBMetadata(CallBase *CI) { // If there exists corner case that CallStackTrie has one chain to leaf // and all node in the chain have multi alloc type, conservatively give // it non-cold allocation type. - // FIXME: Avoid this case before memory profile created. - addAllocTypeAttribute(Ctx, CI, AllocationType::NotCold); + // FIXME: Avoid this case before memory profile created. Alternatively, select + // hint based on fraction cold. + addSingleAllocTypeAttribute(CI, AllocationType::NotCold, "indistinguishable"); return false; } diff --git a/llvm/test/Transforms/PGOProfile/memprof_loop_unroll.ll b/llvm/test/Transforms/PGOProfile/memprof_loop_unroll.ll index 746db4c7153d1..9bc1282ab4529 100644 --- a/llvm/test/Transforms/PGOProfile/memprof_loop_unroll.ll +++ b/llvm/test/Transforms/PGOProfile/memprof_loop_unroll.ll @@ -1,4 +1,5 @@ -;; Tests memprof when contains loop unroll. +;; Tests memprof when contains loop unroll of allocation, where the unrolled +;; allocations have the same context but different allocation types. ;; Avoid failures on big-endian systems that can't read the profile properly ; REQUIRES: x86_64-linux @@ -9,8 +10,12 @@ ;; $ clang++ -gmlt -fdebug-info-for-profiling -S %S/Inputs/memprof_loop_unroll_b.cc -emit-llvm ; RUN: llvm-profdata merge %S/Inputs/memprof_loop_unroll.memprofraw --profiled-binary %S/Inputs/memprof_loop_unroll.exe -o %t.memprofdata -; RUN: opt < %s -passes='memprof-use' -S | FileCheck %s +; RUN: opt < %s -passes='memprof-use' -S -memprof-report-hinted-sizes 2>&1 | FileCheck %s +;; Conservatively annotate as not cold. We get two messages as there are two +;; unrolled copies of the allocation. +; CHECK: MemProf hinting: Total size for full allocation context hash {{.*}} and indistinguishable alloc type notcold: 4 +; CHECK: MemProf hinting: Total size for full allocation context hash {{.*}} and indistinguishable alloc type notcold: 4 ; CHECK: call {{.*}} @_Znam{{.*}} #[[ATTR:[0-9]+]] ; CHECK: attributes #[[ATTR]] = { builtin allocsize(0) "memprof"="notcold" } ; CHECK-NOT: stackIds: () @@ -93,4 +98,4 @@ attributes #2 = { builtin allocsize(0) } !27 = distinct !{!27, !28, !23, !29} !28 = !DILocation(line: 5, column: 5, scope: !10) !29 = !{!"llvm.loop.mustprogress"} -!30 = !DILocation(line: 8, column: 1, scope: !10) \ No newline at end of file +!30 = !DILocation(line: 8, column: 1, scope: !10)