[memprof] Remove an unused using directive (#117004)
[llvm-project.git] / llvm / unittests / Transforms / Instrumentation / MemProfUseTest.cpp
blobf672ed2b1251fcac2d93f407affd513cacade68c
1 //===- MemProfUseTest.cpp - MemProf use tests -----------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Analysis/TargetLibraryInfo.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/LLVMContext.h"
12 #include "llvm/IR/Module.h"
13 #include "llvm/Passes/PassBuilder.h"
14 #include "llvm/ProfileData/InstrProfReader.h"
15 #include "llvm/ProfileData/InstrProfWriter.h"
16 #include "llvm/ProfileData/MemProf.h"
17 #include "llvm/Support/SourceMgr.h"
18 #include "llvm/Testing/Support/Error.h"
19 #include "llvm/Transforms/Instrumentation/MemProfiler.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
24 namespace {
25 using namespace llvm;
26 using namespace llvm::memprof;
27 using testing::Contains;
28 using testing::ElementsAre;
29 using testing::Pair;
30 using testing::SizeIs;
31 using testing::UnorderedElementsAre;
33 TEST(MemProf, ExtractDirectCallsFromIR) {
34 // The following IR is generated from:
36 // void f1();
37 // void f2();
38 // void f3();
40 // void foo() {
41 // f1();
42 // f2(); f3();
43 // }
44 StringRef IR = R"IR(
45 define dso_local void @_Z3foov() !dbg !10 {
46 entry:
47 call void @_Z2f1v(), !dbg !13
48 call void @_Z2f2v(), !dbg !14
49 call void @_Z2f3v(), !dbg !15
50 ret void, !dbg !16
53 declare !dbg !17 void @_Z2f1v()
55 declare !dbg !18 void @_Z2f2v()
57 declare !dbg !19 void @_Z2f3v()
59 !llvm.dbg.cu = !{!0}
60 !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
61 !llvm.ident = !{!9}
63 !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)
64 !1 = !DIFile(filename: "foobar.cc", directory: "/")
65 !2 = !{i32 7, !"Dwarf Version", i32 5}
66 !3 = !{i32 2, !"Debug Info Version", i32 3}
67 !4 = !{i32 1, !"wchar_size", i32 4}
68 !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
69 !6 = !{i32 8, !"PIC Level", i32 2}
70 !7 = !{i32 7, !"PIE Level", i32 2}
71 !8 = !{i32 7, !"uwtable", i32 2}
72 !9 = !{!"clang"}
73 !10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 5, type: !11, scopeLine: 5, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
74 !11 = !DISubroutineType(types: !12)
75 !12 = !{}
76 !13 = !DILocation(line: 6, column: 3, scope: !10)
77 !14 = !DILocation(line: 7, column: 3, scope: !10)
78 !15 = !DILocation(line: 7, column: 9, scope: !10)
79 !16 = !DILocation(line: 8, column: 1, scope: !10)
80 !17 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
81 !18 = !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
82 !19 = !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !1, file: !1, line: 3, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
83 )IR";
85 LLVMContext Ctx;
86 SMDiagnostic Err;
87 std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);
88 ASSERT_TRUE(M);
90 auto *F = M->getFunction("_Z3foov");
91 ASSERT_NE(F, nullptr);
93 TargetLibraryInfoWrapperPass WrapperPass;
94 auto &TLI = WrapperPass.getTLI(*F);
95 auto Calls = extractCallsFromIR(*M, TLI);
97 // Expect exactly one caller.
98 ASSERT_THAT(Calls, SizeIs(1));
100 auto It = Calls.begin();
101 ASSERT_NE(It, Calls.end());
103 const auto &[CallerGUID, CallSites] = *It;
104 EXPECT_EQ(CallerGUID, IndexedMemProfRecord::getGUID("_Z3foov"));
105 ASSERT_THAT(CallSites, SizeIs(3));
107 // Verify that call sites show up in the ascending order of their source
108 // locations.
109 EXPECT_THAT(CallSites[0], Pair(LineLocation(1, 3),
110 IndexedMemProfRecord::getGUID("_Z2f1v")));
111 EXPECT_THAT(CallSites[1], Pair(LineLocation(2, 3),
112 IndexedMemProfRecord::getGUID("_Z2f2v")));
113 EXPECT_THAT(CallSites[2], Pair(LineLocation(2, 9),
114 IndexedMemProfRecord::getGUID("_Z2f3v")));
117 TEST(MemProf, ExtractDirectCallsFromIRInline) {
118 // The following IR is generated from:
120 // void f1();
121 // static inline void f2() {
122 // // For an interesting line number.
123 // f1();
124 // }
125 // static inline void f3() {
126 // /****/ f2(); // For an interesting column number.
127 // }
129 // void g1();
130 // void g2();
131 // static inline void g3() {
132 // /**/ g1(); // For an interesting column number.
133 // g2();
134 // }
136 // void foo() {
137 // f3();
138 // /***/ g3(); // For an interesting column number.
139 // }
140 StringRef IR = R"IR(
141 define dso_local void @_Z3foov() local_unnamed_addr !dbg !10 {
142 entry:
143 tail call void @_Z2f1v(), !dbg !13
144 tail call void @_Z2g1v(), !dbg !18
145 tail call void @_Z2g2v(), !dbg !21
146 ret void, !dbg !22
149 declare !dbg !23 void @_Z2f1v() local_unnamed_addr
151 declare !dbg !24 void @_Z2g1v() local_unnamed_addr
153 declare !dbg !25 void @_Z2g2v() local_unnamed_addr
155 !llvm.dbg.cu = !{!0}
156 !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
157 !llvm.ident = !{!9}
159 !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)
160 !1 = !DIFile(filename: "foobar.cc", directory: "/")
161 !2 = !{i32 7, !"Dwarf Version", i32 5}
162 !3 = !{i32 2, !"Debug Info Version", i32 3}
163 !4 = !{i32 1, !"wchar_size", i32 4}
164 !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
165 !6 = !{i32 8, !"PIC Level", i32 2}
166 !7 = !{i32 7, !"PIE Level", i32 2}
167 !8 = !{i32 7, !"uwtable", i32 2}
168 !9 = !{!"clang"}
169 !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)
170 !11 = !DISubroutineType(types: !12)
171 !12 = !{}
172 !13 = !DILocation(line: 4, column: 3, scope: !14, inlinedAt: !15)
173 !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)
174 !15 = distinct !DILocation(line: 7, column: 10, scope: !16, inlinedAt: !17)
175 !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)
176 !17 = distinct !DILocation(line: 18, column: 3, scope: !10)
177 !18 = !DILocation(line: 13, column: 8, scope: !19, inlinedAt: !20)
178 !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)
179 !20 = distinct !DILocation(line: 19, column: 9, scope: !10)
180 !21 = !DILocation(line: 14, column: 3, scope: !19, inlinedAt: !20)
181 !22 = !DILocation(line: 20, column: 1, scope: !10)
182 !23 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
183 !24 = !DISubprogram(name: "g1", linkageName: "_Z2g1v", scope: !1, file: !1, line: 10, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
184 !25 = !DISubprogram(name: "g2", linkageName: "_Z2g2v", scope: !1, file: !1, line: 11, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
185 )IR";
187 LLVMContext Ctx;
188 SMDiagnostic Err;
189 std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);
190 ASSERT_TRUE(M);
192 auto *F = M->getFunction("_Z3foov");
193 ASSERT_NE(F, nullptr);
195 TargetLibraryInfoWrapperPass WrapperPass;
196 auto &TLI = WrapperPass.getTLI(*F);
197 auto Calls = extractCallsFromIR(*M, TLI);
199 // Expect exactly 4 callers.
200 ASSERT_THAT(Calls, SizeIs(4));
202 // Verify each key-value pair.
204 auto FooIt = Calls.find(IndexedMemProfRecord::getGUID("_Z3foov"));
205 ASSERT_NE(FooIt, Calls.end());
206 const auto &[FooCallerGUID, FooCallSites] = *FooIt;
207 EXPECT_EQ(FooCallerGUID, IndexedMemProfRecord::getGUID("_Z3foov"));
208 ASSERT_THAT(FooCallSites, SizeIs(2));
209 EXPECT_THAT(FooCallSites[0], Pair(LineLocation(1, 3),
210 IndexedMemProfRecord::getGUID("_ZL2f3v")));
211 EXPECT_THAT(FooCallSites[1], Pair(LineLocation(2, 9),
212 IndexedMemProfRecord::getGUID("_ZL2g3v")));
214 auto F2It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2f2v"));
215 ASSERT_NE(F2It, Calls.end());
216 const auto &[F2CallerGUID, F2CallSites] = *F2It;
217 EXPECT_EQ(F2CallerGUID, IndexedMemProfRecord::getGUID("_ZL2f2v"));
218 ASSERT_THAT(F2CallSites, SizeIs(1));
219 EXPECT_THAT(F2CallSites[0], Pair(LineLocation(2, 3),
220 IndexedMemProfRecord::getGUID("_Z2f1v")));
222 auto F3It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2f3v"));
223 ASSERT_NE(F3It, Calls.end());
224 const auto &[F3CallerGUID, F3CallSites] = *F3It;
225 EXPECT_EQ(F3CallerGUID, IndexedMemProfRecord::getGUID("_ZL2f3v"));
226 ASSERT_THAT(F3CallSites, SizeIs(1));
227 EXPECT_THAT(F3CallSites[0], Pair(LineLocation(1, 10),
228 IndexedMemProfRecord::getGUID("_ZL2f2v")));
230 auto G3It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2g3v"));
231 ASSERT_NE(G3It, Calls.end());
232 const auto &[G3CallerGUID, G3CallSites] = *G3It;
233 EXPECT_EQ(G3CallerGUID, IndexedMemProfRecord::getGUID("_ZL2g3v"));
234 ASSERT_THAT(G3CallSites, SizeIs(2));
235 EXPECT_THAT(G3CallSites[0], Pair(LineLocation(1, 8),
236 IndexedMemProfRecord::getGUID("_Z2g1v")));
237 EXPECT_THAT(G3CallSites[1], Pair(LineLocation(2, 3),
238 IndexedMemProfRecord::getGUID("_Z2g2v")));
241 TEST(MemProf, ExtractDirectCallsFromIRCallingNew) {
242 // The following IR is generated from:
244 // int *foo() {
245 // return ::new (int);
246 // }
247 StringRef IR = R"IR(
248 define dso_local noundef ptr @_Z3foov() #0 !dbg !10 {
249 entry:
250 %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 4) #2, !dbg !13
251 ret ptr %call, !dbg !14
254 ; Function Attrs: nobuiltin allocsize(0)
255 declare noundef nonnull ptr @_Znwm(i64 noundef) #1
257 attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
258 attributes #1 = { nobuiltin allocsize(0) "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
259 attributes #2 = { builtin allocsize(0) }
261 !llvm.dbg.cu = !{!0}
262 !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
263 !llvm.ident = !{!9}
265 !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)
266 !1 = !DIFile(filename: "foobar.cc", directory: "/")
267 !2 = !{i32 7, !"Dwarf Version", i32 5}
268 !3 = !{i32 2, !"Debug Info Version", i32 3}
269 !4 = !{i32 1, !"wchar_size", i32 4}
270 !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
271 !6 = !{i32 8, !"PIC Level", i32 2}
272 !7 = !{i32 7, !"PIE Level", i32 2}
273 !8 = !{i32 7, !"uwtable", i32 2}
274 !9 = !{!"clang"}
275 !10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
276 !11 = !DISubroutineType(types: !12)
277 !12 = !{}
278 !13 = !DILocation(line: 2, column: 10, scope: !10)
279 !14 = !DILocation(line: 2, column: 3, scope: !10)
280 )IR";
282 LLVMContext Ctx;
283 SMDiagnostic Err;
284 std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx);
285 ASSERT_TRUE(M);
287 auto *F = M->getFunction("_Z3foov");
288 ASSERT_NE(F, nullptr);
290 TargetLibraryInfoWrapperPass WrapperPass;
291 auto &TLI = WrapperPass.getTLI(*F);
292 auto Calls = extractCallsFromIR(*M, TLI);
294 // Expect exactly one caller.
295 ASSERT_THAT(Calls, SizeIs(1));
297 // Verify each key-value pair.
299 auto FooIt = Calls.find(IndexedMemProfRecord::getGUID("_Z3foov"));
300 ASSERT_NE(FooIt, Calls.end());
301 const auto &[FooCallerGUID, FooCallSites] = *FooIt;
302 EXPECT_EQ(FooCallerGUID, IndexedMemProfRecord::getGUID("_Z3foov"));
303 ASSERT_THAT(FooCallSites, SizeIs(1));
304 EXPECT_THAT(FooCallSites[0], Pair(LineLocation(1, 10), 0));
307 // Populate those fields returned by getHotColdSchema.
308 MemInfoBlock makePartialMIB() {
309 MemInfoBlock MIB;
310 MIB.AllocCount = 1;
311 MIB.TotalSize = 5;
312 MIB.TotalLifetime = 10;
313 MIB.TotalLifetimeAccessDensity = 23;
314 return MIB;
317 IndexedMemProfRecord
318 makeRecordV2(std::initializer_list<::llvm::memprof::CallStackId> AllocFrames,
319 std::initializer_list<::llvm::memprof::CallStackId> CallSiteFrames,
320 const MemInfoBlock &Block, const memprof::MemProfSchema &Schema) {
321 llvm::memprof::IndexedMemProfRecord MR;
322 for (const auto &CSId : AllocFrames) {
323 // We don't populate IndexedAllocationInfo::CallStack because we use it only
324 // in Version1.
325 MR.AllocSites.emplace_back(CSId, Block, Schema);
327 for (const auto &CSId : CallSiteFrames)
328 MR.CallSiteIds.push_back(CSId);
329 return MR;
332 static const auto Err = [](Error E) {
333 FAIL() << E;
334 consumeError(std::move(E));
337 // Make sure that we can undrift direct calls.
338 TEST(MemProf, ComputeUndriftingMap) {
339 // Suppose that the source code has changed from:
341 // void bar();
342 // void baz();
343 // void zzz();
345 // void foo() {
346 // /**/ bar(); // LineLocation(1, 8)
347 // zzz(); // LineLocation(2, 3)
348 // baz(); // LineLocation(3, 3)
349 // }
351 // to:
353 // void bar();
354 // void baz();
356 // void foo() {
357 // bar(); // LineLocation(1, 3)
358 // /**/ baz(); // LineLocation(2, 8)
359 // }
361 // Notice that the calls to bar and baz have drifted while zzz has been
362 // removed.
363 StringRef IR = R"IR(
364 define dso_local void @_Z3foov() #0 !dbg !10 {
365 entry:
366 call void @_Z3barv(), !dbg !13
367 call void @_Z3bazv(), !dbg !14
368 ret void, !dbg !15
371 declare !dbg !16 void @_Z3barv() #1
373 declare !dbg !17 void @_Z3bazv() #1
375 attributes #0 = { mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
376 attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
378 !llvm.dbg.cu = !{!0}
379 !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8}
380 !llvm.ident = !{!9}
382 !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)
383 !1 = !DIFile(filename: "foobar.cc", directory: "/")
384 !2 = !{i32 7, !"Dwarf Version", i32 5}
385 !3 = !{i32 2, !"Debug Info Version", i32 3}
386 !4 = !{i32 1, !"wchar_size", i32 4}
387 !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"}
388 !6 = !{i32 8, !"PIC Level", i32 2}
389 !7 = !{i32 7, !"PIE Level", i32 2}
390 !8 = !{i32 7, !"uwtable", i32 2}
391 !9 = !{!"clang"}
392 !10 = distinct !DISubprogram(name: "foo", linkageName: "_Z3foov", scope: !1, file: !1, line: 4, type: !11, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0)
393 !11 = !DISubroutineType(types: !12)
394 !12 = !{}
395 !13 = !DILocation(line: 5, column: 3, scope: !10)
396 !14 = !DILocation(line: 6, column: 8, scope: !10)
397 !15 = !DILocation(line: 7, column: 1, scope: !10)
398 !16 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
399 !17 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized)
400 )IR";
402 LLVMContext Ctx;
403 SMDiagnostic SMErr;
404 std::unique_ptr<Module> M = parseAssemblyString(IR, SMErr, Ctx);
405 ASSERT_TRUE(M);
407 auto *F = M->getFunction("_Z3foov");
408 ASSERT_NE(F, nullptr);
410 TargetLibraryInfoWrapperPass WrapperPass;
411 auto &TLI = WrapperPass.getTLI(*F);
412 auto Calls = extractCallsFromIR(*M, TLI);
414 uint64_t GUIDFoo = IndexedMemProfRecord::getGUID("_Z3foov");
415 uint64_t GUIDBar = IndexedMemProfRecord::getGUID("_Z3barv");
416 uint64_t GUIDBaz = IndexedMemProfRecord::getGUID("_Z3bazv");
417 uint64_t GUIDZzz = IndexedMemProfRecord::getGUID("_Z3zzzv");
419 // Verify that extractCallsFromIR extracts caller-callee pairs as expected.
420 EXPECT_THAT(Calls,
421 UnorderedElementsAre(Pair(
422 GUIDFoo, ElementsAre(Pair(LineLocation(1, 3), GUIDBar),
423 Pair(LineLocation(2, 8), GUIDBaz)))));
425 llvm::InstrProfWriter Writer;
426 std::unique_ptr<IndexedInstrProfReader> Reader;
428 const MemInfoBlock MIB = makePartialMIB();
430 Writer.setMemProfVersionRequested(memprof::Version3);
431 Writer.setMemProfFullSchema(false);
433 ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf),
434 Succeeded());
436 const IndexedMemProfRecord IndexedMR = makeRecordV2(
437 /*AllocFrames=*/{0x111, 0x222, 0x333},
438 /*CallSiteFrames=*/{}, MIB, memprof::getHotColdSchema());
440 memprof::IndexedMemProfData MemProfData;
441 // The call sites within foo.
442 MemProfData.Frames.try_emplace(0, GUIDFoo, 1, 8, false);
443 MemProfData.Frames.try_emplace(1, GUIDFoo, 2, 3, false);
444 MemProfData.Frames.try_emplace(2, GUIDFoo, 3, 3, false);
445 // Line/column numbers below don't matter.
446 MemProfData.Frames.try_emplace(3, GUIDBar, 9, 9, false);
447 MemProfData.Frames.try_emplace(4, GUIDZzz, 9, 9, false);
448 MemProfData.Frames.try_emplace(5, GUIDBaz, 9, 9, false);
449 MemProfData.CallStacks.try_emplace(
450 0x111,
451 std::initializer_list<memprof::FrameId>{3, 0}); // bar called by foo
452 MemProfData.CallStacks.try_emplace(
453 0x222,
454 std::initializer_list<memprof::FrameId>{4, 1}); // zzz called by foo
455 MemProfData.CallStacks.try_emplace(
456 0x333,
457 std::initializer_list<memprof::FrameId>{5, 2}); // baz called by foo
458 MemProfData.Records.try_emplace(0x9999, IndexedMR);
459 Writer.addMemProfData(MemProfData, Err);
461 auto Profile = Writer.writeBuffer();
463 auto ReaderOrErr =
464 IndexedInstrProfReader::create(std::move(Profile), nullptr);
465 EXPECT_THAT_ERROR(ReaderOrErr.takeError(), Succeeded());
466 Reader = std::move(ReaderOrErr.get());
468 // Verify that getMemProfCallerCalleePairs extracts caller-callee pairs as
469 // expected.
470 auto Pairs = Reader->getMemProfCallerCalleePairs();
471 ASSERT_THAT(Pairs, SizeIs(4));
472 ASSERT_THAT(
473 Pairs,
474 Contains(Pair(GUIDFoo, ElementsAre(Pair(LineLocation(1, 8), GUIDBar),
475 Pair(LineLocation(2, 3), GUIDZzz),
476 Pair(LineLocation(3, 3), GUIDBaz)))));
478 // Verify that computeUndriftMap identifies undrifting opportunities:
480 // Profile IR
481 // (Line: 1, Column: 8) -> (Line: 1, Column: 3)
482 // (Line: 3, Column: 3) -> (Line: 2, Column: 8)
483 auto UndriftMap = computeUndriftMap(*M, Reader.get(), TLI);
484 ASSERT_THAT(UndriftMap,
485 UnorderedElementsAre(Pair(
486 GUIDFoo, UnorderedElementsAre(
487 Pair(LineLocation(1, 8), LineLocation(1, 3)),
488 Pair(LineLocation(3, 3), LineLocation(2, 8))))));
490 } // namespace