Skip to content

Commit c618324

Browse files
[memprof] Teach extractCallsFromIR to look into inline stacks (#115441)
To undrift the profile, we need to extract as many caller-callee pairs from the IR as we can to maximize the number of call sites in the profile we can undrift. Now, since MemProfUsePass runs after early inlining, some functions have been inlined, and we may no longer have bodies for those functions in the IR. To cope with this, this patch teaches extractCallsFromIR to extract caller-calee pairs from inline stacks. The output format of extractCallsFromIR remains the same. We still return a map from caller GUIDs to lists of corresponding call sites.
1 parent 60ea60e commit c618324

File tree

2 files changed

+130
-9
lines changed

2 files changed

+130
-9
lines changed

llvm/lib/Transforms/Instrumentation/MemProfiler.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -810,10 +810,6 @@ memprof::extractCallsFromIR(Module &M) {
810810

811811
for (auto &BB : F) {
812812
for (auto &I : BB) {
813-
const DILocation *DIL = I.getDebugLoc();
814-
if (!DIL)
815-
continue;
816-
817813
if (!isa<CallBase>(&I) || isa<IntrinsicInst>(&I))
818814
continue;
819815

@@ -824,11 +820,17 @@ memprof::extractCallsFromIR(Module &M) {
824820
continue;
825821

826822
StringRef CalleeName = CalledFunction->getName();
827-
uint64_t CallerGUID =
828-
IndexedMemProfRecord::getGUID(DIL->getSubprogramLinkageName());
829-
uint64_t CalleeGUID = IndexedMemProfRecord::getGUID(CalleeName);
830-
LineLocation Loc = {GetOffset(DIL), DIL->getColumn()};
831-
Calls[CallerGUID].emplace_back(Loc, CalleeGUID);
823+
for (const DILocation *DIL = I.getDebugLoc(); DIL;
824+
DIL = DIL->getInlinedAt()) {
825+
StringRef CallerName = DIL->getSubprogramLinkageName();
826+
assert(!CallerName.empty() &&
827+
"Be sure to enable -fdebug-info-for-profiling");
828+
uint64_t CallerGUID = IndexedMemProfRecord::getGUID(CallerName);
829+
uint64_t CalleeGUID = IndexedMemProfRecord::getGUID(CalleeName);
830+
LineLocation Loc = {GetOffset(DIL), DIL->getColumn()};
831+
Calls[CallerGUID].emplace_back(Loc, CalleeGUID);
832+
CalleeName = CallerName;
833+
}
832834
}
833835
}
834836
}

llvm/unittests/Transforms/Instrumentation/MemProfUseTest.cpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,123 @@ declare !dbg !19 void @_Z2f3v()
101101
EXPECT_THAT(CallSites[2],
102102
Pair(FieldsAre(2U, 9U), IndexedMemProfRecord::getGUID("_Z2f3v")));
103103
}
104+
105+
TEST(MemProf, ExtractDirectCallsFromIRInline) {
106+
// The following IR is generated from:
107+
//
108+
// void f1();
109+
// static inline void f2() {
110+
// // For an interesting line number.
111+
// f1();
112+
// }
113+
// static inline void f3() {
114+
// /****/ f2(); // For an interesting column number.
115+
// }
116+
//
117+
// void g1();
118+
// void g2();
119+
// static inline void g3() {
120+
// /**/ g1(); // For an interesting column number.
121+
// g2();
122+
// }
123+
//
124+
// void foo() {
125+
// f3();
126+
// /***/ g3(); // For an interesting column number.
127+
// }
128+
StringRef IR = R"IR(
129+
define dso_local void @_Z3foov() local_unnamed_addr !dbg !10 {
130+
entry:
131+
tail call void @_Z2f1v(), !dbg !13
132+
tail call void @_Z2g1v(), !dbg !18
133+
tail call void @_Z2g2v(), !dbg !21
134+
ret void, !dbg !22
135+
}
136+
137+
declare !dbg !23 void @_Z2f1v() local_unnamed_addr
138+
139+
declare !dbg !24 void @_Z2g1v() local_unnamed_addr
140+
141+
declare !dbg !25 void @_Z2g2v() local_unnamed_addr
142+
143+
!llvm.dbg.cu = !{!0}
144+
!llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
145+
!llvm.ident = !{!9}
146+
147+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang", isOptimized: true, runtimeVersion: 0, emissionKind: LineTablesOnly, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None)
148+
!1 = !DIFile(filename: "foobar.cc", directory: "/")
149+
!2 = !{i32 7, !"Dwarf Version", i32 5}
150+
!3 = !{i32 2, !"Debug Info Version", i32 3}
151+
!4 = !{i32 1, !"wchar_size", i32 4}
152+
!5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
153+
!6 = !{i32 8, !"PIC Level", i32 2}
154+
!7 = !{i32 7, !"PIE Level", i32 2}
155+
!8 = !{i32 7, !"uwtable", i32 2}
156+
!9 = !{!"clang"}
157+
!10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 17, type: !11, scopeLine: 17, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
158+
!11 = !DISubroutineType(types: !12)
159+
!12 = !{}
160+
!13 = !DILocation(line: 4, column: 3, scope: !14, inlinedAt: !15)
161+
!14 = distinct !DISubprogram(name: "f2", linkageName: "_ZL2f2v", scope: !1, file: !1, line: 2, type: !11, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)
162+
!15 = distinct !DILocation(line: 7, column: 10, scope: !16, inlinedAt: !17)
163+
!16 = distinct !DISubprogram(name: "f3", linkageName: "_ZL2f3v", scope: !1, file: !1, line: 6, type: !11, scopeLine: 6, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)
164+
!17 = distinct !DILocation(line: 18, column: 3, scope: !10)
165+
!18 = !DILocation(line: 13, column: 8, scope: !19, inlinedAt: !20)
166+
!19 = distinct !DISubprogram(name: "g3", linkageName: "_ZL2g3v", scope: !1, file: !1, line: 12, type: !11, scopeLine: 12, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition | DISPFlagOptimized, unit: !0)
167+
!20 = distinct !DILocation(line: 19, column: 9, scope: !10)
168+
!21 = !DILocation(line: 14, column: 3, scope: !19, inlinedAt: !20)
169+
!22 = !DILocation(line: 20, column: 1, scope: !10)
170+
!23 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
171+
!24 = !DISubprogram(name: "g1", linkageName: "_Z2g1v", scope: !1, file: !1, line: 10, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
172+
!25 = !DISubprogram(name: "g2", linkageName: "_Z2g2v", scope: !1, file: !1, line: 11, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
173+
)IR";
174+
175+
LLVMContext Ctx;
176+
SMDiagnostic Err;
177+
std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);
178+
ASSERT_TRUE(M);
179+
180+
auto Calls = extractCallsFromIR(*M);
181+
182+
// Expect exactly 4 callers.
183+
ASSERT_THAT(Calls, SizeIs(4));
184+
185+
// Verify each key-value pair.
186+
187+
auto FooIt = Calls.find(IndexedMemProfRecord::getGUID("_Z3foov"));
188+
ASSERT_NE(FooIt, Calls.end());
189+
const auto &[FooCallerGUID, FooCallSites] = *FooIt;
190+
EXPECT_EQ(FooCallerGUID, IndexedMemProfRecord::getGUID("_Z3foov"));
191+
ASSERT_THAT(FooCallSites, SizeIs(2));
192+
EXPECT_THAT(FooCallSites[0], Pair(FieldsAre(1U, 3U),
193+
IndexedMemProfRecord::getGUID("_ZL2f3v")));
194+
EXPECT_THAT(FooCallSites[1], Pair(FieldsAre(2U, 9U),
195+
IndexedMemProfRecord::getGUID("_ZL2g3v")));
196+
197+
auto F2It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2f2v"));
198+
ASSERT_NE(F2It, Calls.end());
199+
const auto &[F2CallerGUID, F2CallSites] = *F2It;
200+
EXPECT_EQ(F2CallerGUID, IndexedMemProfRecord::getGUID("_ZL2f2v"));
201+
ASSERT_THAT(F2CallSites, SizeIs(1));
202+
EXPECT_THAT(F2CallSites[0],
203+
Pair(FieldsAre(2U, 3U), IndexedMemProfRecord::getGUID("_Z2f1v")));
204+
205+
auto F3It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2f3v"));
206+
ASSERT_NE(F3It, Calls.end());
207+
const auto &[F3CallerGUID, F3CallSites] = *F3It;
208+
EXPECT_EQ(F3CallerGUID, IndexedMemProfRecord::getGUID("_ZL2f3v"));
209+
ASSERT_THAT(F3CallSites, SizeIs(1));
210+
EXPECT_THAT(F3CallSites[0], Pair(FieldsAre(1U, 10U),
211+
IndexedMemProfRecord::getGUID("_ZL2f2v")));
212+
213+
auto G3It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2g3v"));
214+
ASSERT_NE(G3It, Calls.end());
215+
const auto &[G3CallerGUID, G3CallSites] = *G3It;
216+
EXPECT_EQ(G3CallerGUID, IndexedMemProfRecord::getGUID("_ZL2g3v"));
217+
ASSERT_THAT(G3CallSites, SizeIs(2));
218+
EXPECT_THAT(G3CallSites[0],
219+
Pair(FieldsAre(1U, 8U), IndexedMemProfRecord::getGUID("_Z2g1v")));
220+
EXPECT_THAT(G3CallSites[1],
221+
Pair(FieldsAre(2U, 3U), IndexedMemProfRecord::getGUID("_Z2g2v")));
222+
}
104223
} // namespace

0 commit comments

Comments
 (0)