[llvm] [MemProf] Handle profiles with missing column numbers (PR #70520)

via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 27 15:48:28 PDT 2023


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-pgo

Author: Teresa Johnson (teresajohnson)

<details>
<summary>Changes</summary>

Detect when we are matching a memprof profile with no column numbers,
and in that case treat all column numbers as 0 when matching. The
profiled binary might have been built with -gno-column-info, for
example.


---
Full diff: https://github.com/llvm/llvm-project/pull/70520.diff


5 Files Affected:

- (modified) llvm/lib/Transforms/Instrumentation/MemProfiler.cpp (+10-2) 
- (added) llvm/test/Transforms/PGOProfile/Inputs/memprof.nocolinfo.exe () 
- (added) llvm/test/Transforms/PGOProfile/Inputs/memprof.nocolinfo.memprofraw () 
- (modified) llvm/test/Transforms/PGOProfile/Inputs/update_memprof_inputs.sh (+4) 
- (modified) llvm/test/Transforms/PGOProfile/memprof.ll (+46) 


``````````diff
diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
index 8cd06f878897b38..2b29ea2a65fdc87 100644
--- a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp
@@ -729,6 +729,12 @@ static void readMemprof(Module &M, Function &F,
     return;
   }
 
+  // Detect if there are non-zero column numbers in the profile. If not,
+  // treat all column numbers as 0 when matching (i.e. ignore any non-zero
+  // columns in the IR). The profiled binary might have been built with
+  // column numbers disabled, for example.
+  bool ProfileHasColumns = false;
+
   // Build maps of the location hash to all profile data with that leaf location
   // (allocation info and the callsites).
   std::map<uint64_t, std::set<const AllocationInfo *>> LocHashToAllocInfo;
@@ -742,6 +748,7 @@ static void readMemprof(Module &M, Function &F,
     // of call stack frames.
     uint64_t StackId = computeStackId(AI.CallStack[0]);
     LocHashToAllocInfo[StackId].insert(&AI);
+    ProfileHasColumns |= AI.CallStack[0].Column;
   }
   for (auto &CS : MemProfRec->CallSites) {
     // Need to record all frames from leaf up to and including this function,
@@ -750,6 +757,7 @@ static void readMemprof(Module &M, Function &F,
     for (auto &StackFrame : CS) {
       uint64_t StackId = computeStackId(StackFrame);
       LocHashToCallSites[StackId].insert(std::make_pair(&CS, Idx++));
+      ProfileHasColumns |= StackFrame.Column;
       // Once we find this function, we can stop recording.
       if (StackFrame.Function == FuncGUID)
         break;
@@ -798,8 +806,8 @@ static void readMemprof(Module &M, Function &F,
         if (Name.empty())
           Name = DIL->getScope()->getSubprogram()->getName();
         auto CalleeGUID = Function::getGUID(Name);
-        auto StackId =
-            computeStackId(CalleeGUID, GetOffset(DIL), DIL->getColumn());
+        auto StackId = computeStackId(CalleeGUID, GetOffset(DIL),
+                                      ProfileHasColumns ? DIL->getColumn() : 0);
         // LeafFound will only be false on the first iteration, since we either
         // set it true or break out of the loop below.
         if (!LeafFound) {
diff --git a/llvm/test/Transforms/PGOProfile/Inputs/memprof.nocolinfo.exe b/llvm/test/Transforms/PGOProfile/Inputs/memprof.nocolinfo.exe
new file mode 100755
index 000000000000000..3000e2b8515a25c
Binary files /dev/null and b/llvm/test/Transforms/PGOProfile/Inputs/memprof.nocolinfo.exe differ
diff --git a/llvm/test/Transforms/PGOProfile/Inputs/memprof.nocolinfo.memprofraw b/llvm/test/Transforms/PGOProfile/Inputs/memprof.nocolinfo.memprofraw
new file mode 100644
index 000000000000000..c0db6d2e0f56ca6
Binary files /dev/null and b/llvm/test/Transforms/PGOProfile/Inputs/memprof.nocolinfo.memprofraw differ
diff --git a/llvm/test/Transforms/PGOProfile/Inputs/update_memprof_inputs.sh b/llvm/test/Transforms/PGOProfile/Inputs/update_memprof_inputs.sh
index a88e6d73ecb7171..cbf9a401a607235 100755
--- a/llvm/test/Transforms/PGOProfile/Inputs/update_memprof_inputs.sh
+++ b/llvm/test/Transforms/PGOProfile/Inputs/update_memprof_inputs.sh
@@ -82,6 +82,10 @@ COMMON_FLAGS="-fuse-ld=lld -Wl,--no-rosegment -gmlt -fdebug-info-for-profiling -
 ${CLANG} ${COMMON_FLAGS} -fmemory-profile ${OUTDIR}/memprof.cc -o ${OUTDIR}/memprof.exe
 env MEMPROF_OPTIONS=log_path=stdout ${OUTDIR}/memprof.exe > ${OUTDIR}/memprof.memprofraw
 
+# Generate another profile without any column numbers.
+${CLANG} ${COMMON_FLAGS} -gno-column-info -fmemory-profile ${OUTDIR}/memprof.cc -o ${OUTDIR}/memprof.nocolinfo.exe
+env MEMPROF_OPTIONS=log_path=stdout ${OUTDIR}/memprof.nocolinfo.exe > ${OUTDIR}/memprof.nocolinfo.memprofraw
+
 ${CLANG} ${COMMON_FLAGS} -fprofile-generate=. \
   ${OUTDIR}/memprof.cc -o ${OUTDIR}/pgo.exe
 env LLVM_PROFILE_FILE=${OUTDIR}/memprof_pgo.profraw ${OUTDIR}/pgo.exe
diff --git a/llvm/test/Transforms/PGOProfile/memprof.ll b/llvm/test/Transforms/PGOProfile/memprof.ll
index 5bd97b0e934af60..13f370a4071e8aa 100644
--- a/llvm/test/Transforms/PGOProfile/memprof.ll
+++ b/llvm/test/Transforms/PGOProfile/memprof.ll
@@ -16,6 +16,7 @@
 ; RUN: llvm-profdata merge %S/Inputs/memprof.memprofraw --profiled-binary %S/Inputs/memprof.exe -o %t.memprofdata
 ; RUN: llvm-profdata merge %S/Inputs/memprof_pgo.proftext %S/Inputs/memprof.memprofraw --profiled-binary %S/Inputs/memprof.exe -o %t.pgomemprofdata
 ; RUN: llvm-profdata merge %S/Inputs/memprof_pgo.proftext -o %t.pgoprofdata
+; RUN: llvm-profdata merge %S/Inputs/memprof.nocolinfo.memprofraw --profiled-binary %S/Inputs/memprof.nocolinfo.exe -o %t.nocolinfo.memprofdata
 
 ;; In all below cases we should not get any messages about missing profile data
 ;; for any functions. Either we are not performing any matching for a particular
@@ -28,6 +29,12 @@
 ; There should not be any PGO metadata
 ; MEMPROFONLY-NOT: !prof
 
+;; Try again but using a profile with missing columns. The memprof matcher
+;; should recognize that there are no non-zero columns in the profile and
+;; not attempt to include column numbers in the matching (which means that the
+;; stack ids will be different).
+; RUN: opt < %s -passes='memprof-use<profile-filename=%t.nocolinfo.memprofdata>' -pgo-warn-missing-function -S 2>&1 | FileCheck %s --check-prefixes=MEMPROFNOCOLINFO,ALL,MEMPROFONLY
+
 ;; Test the same thing but by passing the memory profile through to a default
 ;; pipeline via -memory-profile-file=, which should cause the necessary field
 ;; of the PGOOptions structure to be populated with the profile filename.
@@ -66,6 +73,7 @@ target triple = "x86_64-unknown-linux-gnu"
 define dso_local noundef ptr @_Z3foov() #0 !dbg !10 {
 entry:
   ; MEMPROF: call {{.*}} @_Znam{{.*}} !memprof ![[M1:[0-9]+]], !callsite ![[C1:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Znam{{.*}} !memprof ![[M1:[0-9]+]], !callsite ![[C1:[0-9]+]]
   %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6, !dbg !13
   ret ptr %call, !dbg !14
 }
@@ -78,6 +86,7 @@ declare noundef nonnull ptr @_Znam(i64 noundef) #1
 define dso_local noundef ptr @_Z4foo2v() #0 !dbg !15 {
 entry:
   ; MEMPROF: call {{.*}} @_Z3foov{{.*}} !callsite ![[C2:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z3foov{{.*}} !callsite ![[C2:[0-9]+]]
   %call = call noundef ptr @_Z3foov(), !dbg !16
   ret ptr %call, !dbg !17
 }
@@ -86,6 +95,7 @@ entry:
 define dso_local noundef ptr @_Z3barv() #0 !dbg !18 {
 entry:
   ; MEMPROF: call {{.*}} @_Z4foo2v{{.*}} !callsite ![[C3:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z4foo2v{{.*}} !callsite ![[C3:[0-9]+]]
   %call = call noundef ptr @_Z4foo2v(), !dbg !19
   ret ptr %call, !dbg !20
 }
@@ -94,6 +104,7 @@ entry:
 define dso_local noundef ptr @_Z3bazv() #0 !dbg !21 {
 entry:
   ; MEMPROF: call {{.*}} @_Z4foo2v{{.*}} !callsite ![[C4:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z4foo2v{{.*}} !callsite ![[C4:[0-9]+]]
   %call = call noundef ptr @_Z4foo2v(), !dbg !22
   ret ptr %call, !dbg !23
 }
@@ -110,6 +121,7 @@ entry:
 
 if.then:                                          ; preds = %entry
   ; MEMPROF: call {{.*}} @_Z3foov{{.*}} !callsite ![[C5:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z3foov{{.*}} !callsite ![[C5:[0-9]+]]
   %call = call noundef ptr @_Z3foov(), !dbg !27
   store ptr %call, ptr %retval, align 8, !dbg !28
   br label %return, !dbg !28
@@ -118,6 +130,7 @@ if.end:                                           ; preds = %entry
   %1 = load i32, ptr %n.addr, align 4, !dbg !29
   %sub = sub i32 %1, 1, !dbg !30
   ; MEMPROF: call {{.*}} @_Z7recursej{{.*}} !callsite ![[C6:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z7recursej{{.*}} !callsite ![[C6:[0-9]+]]
   %call1 = call noundef ptr @_Z7recursej(i32 noundef %sub), !dbg !31
   store ptr %call1, ptr %retval, align 8, !dbg !32
   br label %return, !dbg !32
@@ -145,21 +158,27 @@ entry:
   store i32 %argc, ptr %argc.addr, align 4
   store ptr %argv, ptr %argv.addr, align 8
   ; MEMPROF: call {{.*}} @_Znam{{.*}} #[[A1:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Znam{{.*}} #[[A1:[0-9]+]]
   %call = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6, !dbg !35
   store ptr %call, ptr %a, align 8, !dbg !36
   ; MEMPROF: call {{.*}} @_Znam{{.*}} #[[A2:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Znam{{.*}} #[[A2:[0-9]+]]
   %call1 = call noalias noundef nonnull ptr @_Znam(i64 noundef 10) #6, !dbg !37
   store ptr %call1, ptr %b, align 8, !dbg !38
   ; MEMPROF: call {{.*}} @_Z3foov{{.*}} !callsite ![[C7:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z3foov{{.*}} !callsite ![[C7:[0-9]+]]
   %call2 = call noundef ptr @_Z3foov(), !dbg !39
   store ptr %call2, ptr %c, align 8, !dbg !40
   ; MEMPROF: call {{.*}} @_Z3foov{{.*}} !callsite ![[C8:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z3foov{{.*}} !callsite ![[C8:[0-9]+]]
   %call3 = call noundef ptr @_Z3foov(), !dbg !41
   store ptr %call3, ptr %d, align 8, !dbg !42
   ; MEMPROF: call {{.*}} @_Z3barv{{.*}} !callsite ![[C9:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z3barv{{.*}} !callsite ![[C9:[0-9]+]]
   %call4 = call noundef ptr @_Z3barv(), !dbg !43
   store ptr %call4, ptr %e, align 8, !dbg !44
   ; MEMPROF: call {{.*}} @_Z3bazv{{.*}} !callsite ![[C10:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z3bazv{{.*}} !callsite ![[C10:[0-9]+]]
   %call5 = call noundef ptr @_Z3bazv(), !dbg !45
   store ptr %call5, ptr %f, align 8, !dbg !46
   %0 = load ptr, ptr %a, align 8, !dbg !47
@@ -241,6 +260,7 @@ for.body:                                         ; preds = %for.cond
   %13 = load i32, ptr %i, align 4, !dbg !84
   %add = add i32 %13, 3, !dbg !85
   ; MEMPROF: call {{.*}} @_Z7recursej{{.*}} !callsite ![[C11:[0-9]+]]
+  ; MEMPROFNOCOLINFO: call {{.*}} @_Z7recursej{{.*}} !callsite ![[C11:[0-9]+]]
   %call22 = call noundef ptr @_Z7recursej(i32 noundef %add), !dbg !86
   store ptr %call22, ptr %g, align 8, !dbg !87
   %14 = load ptr, ptr %g, align 8, !dbg !88
@@ -300,6 +320,32 @@ for.end:                                          ; preds = %for.cond
 ; MEMPROF: ![[C10]] = !{i64 2061451396820446691}
 ; MEMPROF: ![[C11]] = !{i64 1544787832369987002}
 
+
+; MEMPROFNOCOLINFO: #[[A1]] = { builtin allocsize(0) "memprof"="notcold" }
+; MEMPROFNOCOLINFO: #[[A2]] = { builtin allocsize(0) "memprof"="cold" }
+; MEMPROFNOCOLINFO: ![[M1]] = !{![[MIB1:[0-9]+]], ![[MIB2:[0-9]+]], ![[MIB3:[0-9]+]], ![[MIB4:[0-9]+]], ![[MIB5:[0-9]+]]}
+; MEMPROFNOCOLINFO: ![[MIB1]] = !{![[STACK1:[0-9]+]], !"cold"}
+; MEMPROFNOCOLINFO: ![[STACK1]] = !{i64 5281664982037379640, i64 6362220161075421157, i64 -5772587307814069790, i64 -5772587307814069790, i64 -5772587307814069790, i64 3577763375057267810}
+; MEMPROFNOCOLINFO: ![[MIB2]] = !{![[STACK2:[0-9]+]], !"notcold"}
+; MEMPROFNOCOLINFO: ![[STACK2]] = !{i64 5281664982037379640, i64 6362220161075421157, i64 -5772587307814069790, i64 -5772587307814069790, i64 -5772587307814069790, i64 -5772587307814069790}
+; MEMPROFNOCOLINFO: ![[MIB3]] = !{![[STACK3:[0-9]+]], !"notcold"}
+; MEMPROFNOCOLINFO: ![[STACK3]] = !{i64 5281664982037379640, i64 -6896091699916449732}
+; MEMPROFNOCOLINFO: ![[MIB4]] = !{![[STACK4:[0-9]+]], !"cold"}
+; MEMPROFNOCOLINFO: ![[STACK4]] = !{i64 5281664982037379640, i64 -6871734214936418908}
+; MEMPROFNOCOLINFO: ![[MIB5]] = !{![[STACK5:[0-9]+]], !"cold"}
+; MEMPROFNOCOLINFO: ![[STACK5]] = !{i64 5281664982037379640, i64 -6201180255894224618}
+; MEMPROFNOCOLINFO: ![[C1]] = !{i64 5281664982037379640}
+; MEMPROFNOCOLINFO: ![[C2]] = !{i64 -6871734214936418908}
+; MEMPROFNOCOLINFO: ![[C3]] = !{i64 -5588766871448036195}
+; MEMPROFNOCOLINFO: ![[C4]] = !{i64 -8990226808646054327}
+; MEMPROFNOCOLINFO: ![[C5]] = !{i64 6362220161075421157}
+; MEMPROFNOCOLINFO: ![[C6]] = !{i64 -5772587307814069790}
+; MEMPROFNOCOLINFO: ![[C7]] = !{i64 -6896091699916449732}
+; MEMPROFNOCOLINFO: ![[C8]] = !{i64 -6201180255894224618}
+; MEMPROFNOCOLINFO: ![[C9]] = !{i64 -962804290746547393}
+; MEMPROFNOCOLINFO: ![[C10]] = !{i64 -4535090212904553409}
+; MEMPROFNOCOLINFO: ![[C11]] = !{i64 3577763375057267810}
+
 ; Function Attrs: argmemonly nofree nounwind willreturn writeonly
 declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #3
 

``````````

</details>


https://github.com/llvm/llvm-project/pull/70520


More information about the llvm-commits mailing list