1e189d619SKazu Hirata //===- MemProfUseTest.cpp - MemProf use tests -----------------------------===// 2e189d619SKazu Hirata // 3e189d619SKazu Hirata // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e189d619SKazu Hirata // See https://llvm.org/LICENSE.txt for license information. 5e189d619SKazu Hirata // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e189d619SKazu Hirata // 7e189d619SKazu Hirata //===----------------------------------------------------------------------===// 8e189d619SKazu Hirata 995554cbdSKazu Hirata #include "llvm/Analysis/TargetLibraryInfo.h" 10e189d619SKazu Hirata #include "llvm/AsmParser/Parser.h" 11e189d619SKazu Hirata #include "llvm/IR/LLVMContext.h" 12e189d619SKazu Hirata #include "llvm/IR/Module.h" 1395554cbdSKazu Hirata #include "llvm/Passes/PassBuilder.h" 14a2e266b3SKazu Hirata #include "llvm/ProfileData/InstrProfReader.h" 15a2e266b3SKazu Hirata #include "llvm/ProfileData/InstrProfWriter.h" 16e189d619SKazu Hirata #include "llvm/ProfileData/MemProf.h" 17e189d619SKazu Hirata #include "llvm/Support/SourceMgr.h" 18a2e266b3SKazu Hirata #include "llvm/Testing/Support/Error.h" 19e189d619SKazu Hirata #include "llvm/Transforms/Instrumentation/MemProfiler.h" 20e189d619SKazu Hirata 21e189d619SKazu Hirata #include "gmock/gmock.h" 22e189d619SKazu Hirata #include "gtest/gtest.h" 23e189d619SKazu Hirata 24624e89bcSKazu Hirata namespace llvm { 25624e89bcSKazu Hirata namespace memprof { 26e189d619SKazu Hirata namespace { 27a2e266b3SKazu Hirata using testing::Contains; 28a2e266b3SKazu Hirata using testing::ElementsAre; 29e189d619SKazu Hirata using testing::Pair; 30e189d619SKazu Hirata using testing::SizeIs; 31a2e266b3SKazu Hirata using testing::UnorderedElementsAre; 32e189d619SKazu Hirata 33e189d619SKazu Hirata TEST(MemProf, ExtractDirectCallsFromIR) { 34e189d619SKazu Hirata // The following IR is generated from: 35e189d619SKazu Hirata // 36e189d619SKazu Hirata // void f1(); 37e189d619SKazu Hirata // void f2(); 38e189d619SKazu Hirata // void f3(); 39e189d619SKazu Hirata // 40e189d619SKazu Hirata // void foo() { 41e189d619SKazu Hirata // f1(); 42e189d619SKazu Hirata // f2(); f3(); 43e189d619SKazu Hirata // } 44e189d619SKazu Hirata StringRef IR = R"IR( 45e189d619SKazu Hirata define dso_local void @_Z3foov() !dbg !10 { 46e189d619SKazu Hirata entry: 47e189d619SKazu Hirata call void @_Z2f1v(), !dbg !13 48e189d619SKazu Hirata call void @_Z2f2v(), !dbg !14 49e189d619SKazu Hirata call void @_Z2f3v(), !dbg !15 50e189d619SKazu Hirata ret void, !dbg !16 51e189d619SKazu Hirata } 52e189d619SKazu Hirata 53e189d619SKazu Hirata declare !dbg !17 void @_Z2f1v() 54e189d619SKazu Hirata 55e189d619SKazu Hirata declare !dbg !18 void @_Z2f2v() 56e189d619SKazu Hirata 57e189d619SKazu Hirata declare !dbg !19 void @_Z2f3v() 58e189d619SKazu Hirata 59e189d619SKazu Hirata !llvm.dbg.cu = !{!0} 60e189d619SKazu Hirata !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} 61e189d619SKazu Hirata !llvm.ident = !{!9} 62e189d619SKazu Hirata 63e189d619SKazu Hirata !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) 64e189d619SKazu Hirata !1 = !DIFile(filename: "foobar.cc", directory: "/") 65e189d619SKazu Hirata !2 = !{i32 7, !"Dwarf Version", i32 5} 66e189d619SKazu Hirata !3 = !{i32 2, !"Debug Info Version", i32 3} 67e189d619SKazu Hirata !4 = !{i32 1, !"wchar_size", i32 4} 68e189d619SKazu Hirata !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"} 69e189d619SKazu Hirata !6 = !{i32 8, !"PIC Level", i32 2} 70e189d619SKazu Hirata !7 = !{i32 7, !"PIE Level", i32 2} 71e189d619SKazu Hirata !8 = !{i32 7, !"uwtable", i32 2} 72e189d619SKazu Hirata !9 = !{!"clang"} 73e189d619SKazu Hirata !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) 74e189d619SKazu Hirata !11 = !DISubroutineType(types: !12) 75e189d619SKazu Hirata !12 = !{} 76e189d619SKazu Hirata !13 = !DILocation(line: 6, column: 3, scope: !10) 77e189d619SKazu Hirata !14 = !DILocation(line: 7, column: 3, scope: !10) 78e189d619SKazu Hirata !15 = !DILocation(line: 7, column: 9, scope: !10) 79e189d619SKazu Hirata !16 = !DILocation(line: 8, column: 1, scope: !10) 80e189d619SKazu Hirata !17 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) 81e189d619SKazu Hirata !18 = !DISubprogram(name: "f2", linkageName: "_Z2f2v", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) 82e189d619SKazu Hirata !19 = !DISubprogram(name: "f3", linkageName: "_Z2f3v", scope: !1, file: !1, line: 3, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) 83e189d619SKazu Hirata )IR"; 84e189d619SKazu Hirata 85e189d619SKazu Hirata LLVMContext Ctx; 86e189d619SKazu Hirata SMDiagnostic Err; 87e189d619SKazu Hirata std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx); 88e189d619SKazu Hirata ASSERT_TRUE(M); 89e189d619SKazu Hirata 9095554cbdSKazu Hirata auto *F = M->getFunction("_Z3foov"); 9195554cbdSKazu Hirata ASSERT_NE(F, nullptr); 9295554cbdSKazu Hirata 9395554cbdSKazu Hirata TargetLibraryInfoWrapperPass WrapperPass; 9495554cbdSKazu Hirata auto &TLI = WrapperPass.getTLI(*F); 9595554cbdSKazu Hirata auto Calls = extractCallsFromIR(*M, TLI); 96e189d619SKazu Hirata 97e189d619SKazu Hirata // Expect exactly one caller. 98e189d619SKazu Hirata ASSERT_THAT(Calls, SizeIs(1)); 99e189d619SKazu Hirata 100e189d619SKazu Hirata auto It = Calls.begin(); 101e189d619SKazu Hirata ASSERT_NE(It, Calls.end()); 102e189d619SKazu Hirata 103e189d619SKazu Hirata const auto &[CallerGUID, CallSites] = *It; 104e189d619SKazu Hirata EXPECT_EQ(CallerGUID, IndexedMemProfRecord::getGUID("_Z3foov")); 105e189d619SKazu Hirata 106e189d619SKazu Hirata // Verify that call sites show up in the ascending order of their source 107e189d619SKazu Hirata // locations. 108*ad635b41SKazu Hirata EXPECT_THAT( 109*ad635b41SKazu Hirata CallSites, 110*ad635b41SKazu Hirata ElementsAre( 111*ad635b41SKazu Hirata Pair(LineLocation(1, 3), IndexedMemProfRecord::getGUID("_Z2f1v")), 112*ad635b41SKazu Hirata Pair(LineLocation(2, 3), IndexedMemProfRecord::getGUID("_Z2f2v")), 113*ad635b41SKazu Hirata Pair(LineLocation(2, 9), IndexedMemProfRecord::getGUID("_Z2f3v")))); 114e189d619SKazu Hirata } 115c6183244SKazu Hirata 116c6183244SKazu Hirata TEST(MemProf, ExtractDirectCallsFromIRInline) { 117c6183244SKazu Hirata // The following IR is generated from: 118c6183244SKazu Hirata // 119c6183244SKazu Hirata // void f1(); 120c6183244SKazu Hirata // static inline void f2() { 121c6183244SKazu Hirata // // For an interesting line number. 122c6183244SKazu Hirata // f1(); 123c6183244SKazu Hirata // } 124c6183244SKazu Hirata // static inline void f3() { 125c6183244SKazu Hirata // /****/ f2(); // For an interesting column number. 126c6183244SKazu Hirata // } 127c6183244SKazu Hirata // 128c6183244SKazu Hirata // void g1(); 129c6183244SKazu Hirata // void g2(); 130c6183244SKazu Hirata // static inline void g3() { 131c6183244SKazu Hirata // /**/ g1(); // For an interesting column number. 132c6183244SKazu Hirata // g2(); 133c6183244SKazu Hirata // } 134c6183244SKazu Hirata // 135c6183244SKazu Hirata // void foo() { 136c6183244SKazu Hirata // f3(); 137c6183244SKazu Hirata // /***/ g3(); // For an interesting column number. 138c6183244SKazu Hirata // } 139c6183244SKazu Hirata StringRef IR = R"IR( 140c6183244SKazu Hirata define dso_local void @_Z3foov() local_unnamed_addr !dbg !10 { 141c6183244SKazu Hirata entry: 142c6183244SKazu Hirata tail call void @_Z2f1v(), !dbg !13 143c6183244SKazu Hirata tail call void @_Z2g1v(), !dbg !18 144c6183244SKazu Hirata tail call void @_Z2g2v(), !dbg !21 145c6183244SKazu Hirata ret void, !dbg !22 146c6183244SKazu Hirata } 147c6183244SKazu Hirata 148c6183244SKazu Hirata declare !dbg !23 void @_Z2f1v() local_unnamed_addr 149c6183244SKazu Hirata 150c6183244SKazu Hirata declare !dbg !24 void @_Z2g1v() local_unnamed_addr 151c6183244SKazu Hirata 152c6183244SKazu Hirata declare !dbg !25 void @_Z2g2v() local_unnamed_addr 153c6183244SKazu Hirata 154c6183244SKazu Hirata !llvm.dbg.cu = !{!0} 155c6183244SKazu Hirata !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} 156c6183244SKazu Hirata !llvm.ident = !{!9} 157c6183244SKazu Hirata 158c6183244SKazu Hirata !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) 159c6183244SKazu Hirata !1 = !DIFile(filename: "foobar.cc", directory: "/") 160c6183244SKazu Hirata !2 = !{i32 7, !"Dwarf Version", i32 5} 161c6183244SKazu Hirata !3 = !{i32 2, !"Debug Info Version", i32 3} 162c6183244SKazu Hirata !4 = !{i32 1, !"wchar_size", i32 4} 163c6183244SKazu Hirata !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"} 164c6183244SKazu Hirata !6 = !{i32 8, !"PIC Level", i32 2} 165c6183244SKazu Hirata !7 = !{i32 7, !"PIE Level", i32 2} 166c6183244SKazu Hirata !8 = !{i32 7, !"uwtable", i32 2} 167c6183244SKazu Hirata !9 = !{!"clang"} 168c6183244SKazu Hirata !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) 169c6183244SKazu Hirata !11 = !DISubroutineType(types: !12) 170c6183244SKazu Hirata !12 = !{} 171c6183244SKazu Hirata !13 = !DILocation(line: 4, column: 3, scope: !14, inlinedAt: !15) 172c6183244SKazu Hirata !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) 173c6183244SKazu Hirata !15 = distinct !DILocation(line: 7, column: 10, scope: !16, inlinedAt: !17) 174c6183244SKazu Hirata !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) 175c6183244SKazu Hirata !17 = distinct !DILocation(line: 18, column: 3, scope: !10) 176c6183244SKazu Hirata !18 = !DILocation(line: 13, column: 8, scope: !19, inlinedAt: !20) 177c6183244SKazu Hirata !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) 178c6183244SKazu Hirata !20 = distinct !DILocation(line: 19, column: 9, scope: !10) 179c6183244SKazu Hirata !21 = !DILocation(line: 14, column: 3, scope: !19, inlinedAt: !20) 180c6183244SKazu Hirata !22 = !DILocation(line: 20, column: 1, scope: !10) 181c6183244SKazu Hirata !23 = !DISubprogram(name: "f1", linkageName: "_Z2f1v", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) 182c6183244SKazu Hirata !24 = !DISubprogram(name: "g1", linkageName: "_Z2g1v", scope: !1, file: !1, line: 10, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) 183c6183244SKazu Hirata !25 = !DISubprogram(name: "g2", linkageName: "_Z2g2v", scope: !1, file: !1, line: 11, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) 184c6183244SKazu Hirata )IR"; 185c6183244SKazu Hirata 186c6183244SKazu Hirata LLVMContext Ctx; 187c6183244SKazu Hirata SMDiagnostic Err; 188c6183244SKazu Hirata std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx); 189c6183244SKazu Hirata ASSERT_TRUE(M); 190c6183244SKazu Hirata 19195554cbdSKazu Hirata auto *F = M->getFunction("_Z3foov"); 19295554cbdSKazu Hirata ASSERT_NE(F, nullptr); 19395554cbdSKazu Hirata 19495554cbdSKazu Hirata TargetLibraryInfoWrapperPass WrapperPass; 19595554cbdSKazu Hirata auto &TLI = WrapperPass.getTLI(*F); 19695554cbdSKazu Hirata auto Calls = extractCallsFromIR(*M, TLI); 197c6183244SKazu Hirata 198c6183244SKazu Hirata // Expect exactly 4 callers. 199c6183244SKazu Hirata ASSERT_THAT(Calls, SizeIs(4)); 200c6183244SKazu Hirata 201c6183244SKazu Hirata // Verify each key-value pair. 202c6183244SKazu Hirata 203c6183244SKazu Hirata auto FooIt = Calls.find(IndexedMemProfRecord::getGUID("_Z3foov")); 204c6183244SKazu Hirata ASSERT_NE(FooIt, Calls.end()); 205c6183244SKazu Hirata const auto &[FooCallerGUID, FooCallSites] = *FooIt; 206c6183244SKazu Hirata EXPECT_EQ(FooCallerGUID, IndexedMemProfRecord::getGUID("_Z3foov")); 207*ad635b41SKazu Hirata EXPECT_THAT( 208*ad635b41SKazu Hirata FooCallSites, 209*ad635b41SKazu Hirata ElementsAre( 210*ad635b41SKazu Hirata Pair(LineLocation(1, 3), IndexedMemProfRecord::getGUID("_ZL2f3v")), 211*ad635b41SKazu Hirata Pair(LineLocation(2, 9), IndexedMemProfRecord::getGUID("_ZL2g3v")))); 212c6183244SKazu Hirata 213c6183244SKazu Hirata auto F2It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2f2v")); 214c6183244SKazu Hirata ASSERT_NE(F2It, Calls.end()); 215c6183244SKazu Hirata const auto &[F2CallerGUID, F2CallSites] = *F2It; 216c6183244SKazu Hirata EXPECT_EQ(F2CallerGUID, IndexedMemProfRecord::getGUID("_ZL2f2v")); 217*ad635b41SKazu Hirata EXPECT_THAT(F2CallSites, 218*ad635b41SKazu Hirata ElementsAre(Pair(LineLocation(2, 3), 219*ad635b41SKazu Hirata IndexedMemProfRecord::getGUID("_Z2f1v")))); 220c6183244SKazu Hirata 221c6183244SKazu Hirata auto F3It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2f3v")); 222c6183244SKazu Hirata ASSERT_NE(F3It, Calls.end()); 223c6183244SKazu Hirata const auto &[F3CallerGUID, F3CallSites] = *F3It; 224c6183244SKazu Hirata EXPECT_EQ(F3CallerGUID, IndexedMemProfRecord::getGUID("_ZL2f3v")); 225*ad635b41SKazu Hirata EXPECT_THAT(F3CallSites, 226*ad635b41SKazu Hirata ElementsAre(Pair(LineLocation(1, 10), 227*ad635b41SKazu Hirata IndexedMemProfRecord::getGUID("_ZL2f2v")))); 228c6183244SKazu Hirata 229c6183244SKazu Hirata auto G3It = Calls.find(IndexedMemProfRecord::getGUID("_ZL2g3v")); 230c6183244SKazu Hirata ASSERT_NE(G3It, Calls.end()); 231c6183244SKazu Hirata const auto &[G3CallerGUID, G3CallSites] = *G3It; 232c6183244SKazu Hirata EXPECT_EQ(G3CallerGUID, IndexedMemProfRecord::getGUID("_ZL2g3v")); 233*ad635b41SKazu Hirata EXPECT_THAT( 234*ad635b41SKazu Hirata G3CallSites, 235*ad635b41SKazu Hirata ElementsAre( 236*ad635b41SKazu Hirata Pair(LineLocation(1, 8), IndexedMemProfRecord::getGUID("_Z2g1v")), 237*ad635b41SKazu Hirata Pair(LineLocation(2, 3), IndexedMemProfRecord::getGUID("_Z2g2v")))); 238c6183244SKazu Hirata } 23995554cbdSKazu Hirata 24095554cbdSKazu Hirata TEST(MemProf, ExtractDirectCallsFromIRCallingNew) { 24195554cbdSKazu Hirata // The following IR is generated from: 24295554cbdSKazu Hirata // 24395554cbdSKazu Hirata // int *foo() { 24495554cbdSKazu Hirata // return ::new (int); 24595554cbdSKazu Hirata // } 24695554cbdSKazu Hirata StringRef IR = R"IR( 24795554cbdSKazu Hirata define dso_local noundef ptr @_Z3foov() #0 !dbg !10 { 24895554cbdSKazu Hirata entry: 24995554cbdSKazu Hirata %call = call noalias noundef nonnull ptr @_Znwm(i64 noundef 4) #2, !dbg !13 25095554cbdSKazu Hirata ret ptr %call, !dbg !14 25195554cbdSKazu Hirata } 25295554cbdSKazu Hirata 25395554cbdSKazu Hirata ; Function Attrs: nobuiltin allocsize(0) 25495554cbdSKazu Hirata declare noundef nonnull ptr @_Znwm(i64 noundef) #1 25595554cbdSKazu Hirata 25695554cbdSKazu Hirata 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" } 25795554cbdSKazu Hirata 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" } 25895554cbdSKazu Hirata attributes #2 = { builtin allocsize(0) } 25995554cbdSKazu Hirata 26095554cbdSKazu Hirata !llvm.dbg.cu = !{!0} 26195554cbdSKazu Hirata !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} 26295554cbdSKazu Hirata !llvm.ident = !{!9} 26395554cbdSKazu Hirata 26495554cbdSKazu Hirata !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) 26595554cbdSKazu Hirata !1 = !DIFile(filename: "foobar.cc", directory: "/") 26695554cbdSKazu Hirata !2 = !{i32 7, !"Dwarf Version", i32 5} 26795554cbdSKazu Hirata !3 = !{i32 2, !"Debug Info Version", i32 3} 26895554cbdSKazu Hirata !4 = !{i32 1, !"wchar_size", i32 4} 26995554cbdSKazu Hirata !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"} 27095554cbdSKazu Hirata !6 = !{i32 8, !"PIC Level", i32 2} 27195554cbdSKazu Hirata !7 = !{i32 7, !"PIE Level", i32 2} 27295554cbdSKazu Hirata !8 = !{i32 7, !"uwtable", i32 2} 27395554cbdSKazu Hirata !9 = !{!"clang"} 27495554cbdSKazu Hirata !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) 27595554cbdSKazu Hirata !11 = !DISubroutineType(types: !12) 27695554cbdSKazu Hirata !12 = !{} 27795554cbdSKazu Hirata !13 = !DILocation(line: 2, column: 10, scope: !10) 27895554cbdSKazu Hirata !14 = !DILocation(line: 2, column: 3, scope: !10) 27995554cbdSKazu Hirata )IR"; 28095554cbdSKazu Hirata 28195554cbdSKazu Hirata LLVMContext Ctx; 28295554cbdSKazu Hirata SMDiagnostic Err; 28395554cbdSKazu Hirata std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Ctx); 28495554cbdSKazu Hirata ASSERT_TRUE(M); 28595554cbdSKazu Hirata 28695554cbdSKazu Hirata auto *F = M->getFunction("_Z3foov"); 28795554cbdSKazu Hirata ASSERT_NE(F, nullptr); 28895554cbdSKazu Hirata 28995554cbdSKazu Hirata TargetLibraryInfoWrapperPass WrapperPass; 29095554cbdSKazu Hirata auto &TLI = WrapperPass.getTLI(*F); 29195554cbdSKazu Hirata auto Calls = extractCallsFromIR(*M, TLI); 29295554cbdSKazu Hirata 29395554cbdSKazu Hirata // Expect exactly one caller. 29495554cbdSKazu Hirata ASSERT_THAT(Calls, SizeIs(1)); 29595554cbdSKazu Hirata 29695554cbdSKazu Hirata // Verify each key-value pair. 29795554cbdSKazu Hirata 29895554cbdSKazu Hirata auto FooIt = Calls.find(IndexedMemProfRecord::getGUID("_Z3foov")); 29995554cbdSKazu Hirata ASSERT_NE(FooIt, Calls.end()); 30095554cbdSKazu Hirata const auto &[FooCallerGUID, FooCallSites] = *FooIt; 30195554cbdSKazu Hirata EXPECT_EQ(FooCallerGUID, IndexedMemProfRecord::getGUID("_Z3foov")); 302*ad635b41SKazu Hirata EXPECT_THAT(FooCallSites, ElementsAre(Pair(LineLocation(1, 10), 0))); 30395554cbdSKazu Hirata } 304a2e266b3SKazu Hirata 305a2e266b3SKazu Hirata // Populate those fields returned by getHotColdSchema. 306a2e266b3SKazu Hirata MemInfoBlock makePartialMIB() { 307a2e266b3SKazu Hirata MemInfoBlock MIB; 308a2e266b3SKazu Hirata MIB.AllocCount = 1; 309a2e266b3SKazu Hirata MIB.TotalSize = 5; 310a2e266b3SKazu Hirata MIB.TotalLifetime = 10; 311a2e266b3SKazu Hirata MIB.TotalLifetimeAccessDensity = 23; 312a2e266b3SKazu Hirata return MIB; 313a2e266b3SKazu Hirata } 314a2e266b3SKazu Hirata 315a2e266b3SKazu Hirata IndexedMemProfRecord 316624e89bcSKazu Hirata makeRecordV2(std::initializer_list<CallStackId> AllocFrames, 317624e89bcSKazu Hirata std::initializer_list<CallStackId> CallSiteFrames, 318624e89bcSKazu Hirata const MemInfoBlock &Block, const MemProfSchema &Schema) { 319624e89bcSKazu Hirata IndexedMemProfRecord MR; 320624e89bcSKazu Hirata for (const auto &CSId : AllocFrames) 3214acba069SKazu Hirata MR.AllocSites.emplace_back(CSId, Block, Schema); 322a2e266b3SKazu Hirata for (const auto &CSId : CallSiteFrames) 323a2e266b3SKazu Hirata MR.CallSiteIds.push_back(CSId); 324a2e266b3SKazu Hirata return MR; 325a2e266b3SKazu Hirata } 326a2e266b3SKazu Hirata 327a2e266b3SKazu Hirata static const auto Err = [](Error E) { 328a2e266b3SKazu Hirata FAIL() << E; 329a2e266b3SKazu Hirata consumeError(std::move(E)); 330a2e266b3SKazu Hirata }; 331a2e266b3SKazu Hirata 332a2e266b3SKazu Hirata // Make sure that we can undrift direct calls. 333a2e266b3SKazu Hirata TEST(MemProf, ComputeUndriftingMap) { 334a2e266b3SKazu Hirata // Suppose that the source code has changed from: 335a2e266b3SKazu Hirata // 336a2e266b3SKazu Hirata // void bar(); 337a2e266b3SKazu Hirata // void baz(); 338a2e266b3SKazu Hirata // void zzz(); 339a2e266b3SKazu Hirata // 340a2e266b3SKazu Hirata // void foo() { 341a2e266b3SKazu Hirata // /**/ bar(); // LineLocation(1, 8) 342a2e266b3SKazu Hirata // zzz(); // LineLocation(2, 3) 343a2e266b3SKazu Hirata // baz(); // LineLocation(3, 3) 344a2e266b3SKazu Hirata // } 345a2e266b3SKazu Hirata // 346a2e266b3SKazu Hirata // to: 347a2e266b3SKazu Hirata // 348a2e266b3SKazu Hirata // void bar(); 349a2e266b3SKazu Hirata // void baz(); 350a2e266b3SKazu Hirata // 351a2e266b3SKazu Hirata // void foo() { 352a2e266b3SKazu Hirata // bar(); // LineLocation(1, 3) 353a2e266b3SKazu Hirata // /**/ baz(); // LineLocation(2, 8) 354a2e266b3SKazu Hirata // } 355a2e266b3SKazu Hirata // 356a2e266b3SKazu Hirata // Notice that the calls to bar and baz have drifted while zzz has been 357a2e266b3SKazu Hirata // removed. 358a2e266b3SKazu Hirata StringRef IR = R"IR( 359a2e266b3SKazu Hirata define dso_local void @_Z3foov() #0 !dbg !10 { 360a2e266b3SKazu Hirata entry: 361a2e266b3SKazu Hirata call void @_Z3barv(), !dbg !13 362a2e266b3SKazu Hirata call void @_Z3bazv(), !dbg !14 363a2e266b3SKazu Hirata ret void, !dbg !15 364a2e266b3SKazu Hirata } 365a2e266b3SKazu Hirata 366a2e266b3SKazu Hirata declare !dbg !16 void @_Z3barv() #1 367a2e266b3SKazu Hirata 368a2e266b3SKazu Hirata declare !dbg !17 void @_Z3bazv() #1 369a2e266b3SKazu Hirata 370a2e266b3SKazu Hirata 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" } 371a2e266b3SKazu Hirata 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" } 372a2e266b3SKazu Hirata 373a2e266b3SKazu Hirata !llvm.dbg.cu = !{!0} 374a2e266b3SKazu Hirata !llvm.module.flags = !{!2, !3, !4, !5, !6, !7, !8} 375a2e266b3SKazu Hirata !llvm.ident = !{!9} 376a2e266b3SKazu Hirata 377a2e266b3SKazu Hirata !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) 378a2e266b3SKazu Hirata !1 = !DIFile(filename: "foobar.cc", directory: "/") 379a2e266b3SKazu Hirata !2 = !{i32 7, !"Dwarf Version", i32 5} 380a2e266b3SKazu Hirata !3 = !{i32 2, !"Debug Info Version", i32 3} 381a2e266b3SKazu Hirata !4 = !{i32 1, !"wchar_size", i32 4} 382a2e266b3SKazu Hirata !5 = !{i32 1, !"MemProfProfileFilename", !"memprof.profraw"} 383a2e266b3SKazu Hirata !6 = !{i32 8, !"PIC Level", i32 2} 384a2e266b3SKazu Hirata !7 = !{i32 7, !"PIE Level", i32 2} 385a2e266b3SKazu Hirata !8 = !{i32 7, !"uwtable", i32 2} 386a2e266b3SKazu Hirata !9 = !{!"clang"} 387a2e266b3SKazu Hirata !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) 388a2e266b3SKazu Hirata !11 = !DISubroutineType(types: !12) 389a2e266b3SKazu Hirata !12 = !{} 390a2e266b3SKazu Hirata !13 = !DILocation(line: 5, column: 3, scope: !10) 391a2e266b3SKazu Hirata !14 = !DILocation(line: 6, column: 8, scope: !10) 392a2e266b3SKazu Hirata !15 = !DILocation(line: 7, column: 1, scope: !10) 393a2e266b3SKazu Hirata !16 = !DISubprogram(name: "bar", linkageName: "_Z3barv", scope: !1, file: !1, line: 1, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) 394a2e266b3SKazu Hirata !17 = !DISubprogram(name: "baz", linkageName: "_Z3bazv", scope: !1, file: !1, line: 2, type: !11, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized) 395a2e266b3SKazu Hirata )IR"; 396a2e266b3SKazu Hirata 397a2e266b3SKazu Hirata LLVMContext Ctx; 398a2e266b3SKazu Hirata SMDiagnostic SMErr; 399a2e266b3SKazu Hirata std::unique_ptr<Module> M = parseAssemblyString(IR, SMErr, Ctx); 400a2e266b3SKazu Hirata ASSERT_TRUE(M); 401a2e266b3SKazu Hirata 402a2e266b3SKazu Hirata auto *F = M->getFunction("_Z3foov"); 403a2e266b3SKazu Hirata ASSERT_NE(F, nullptr); 404a2e266b3SKazu Hirata 405a2e266b3SKazu Hirata TargetLibraryInfoWrapperPass WrapperPass; 406a2e266b3SKazu Hirata auto &TLI = WrapperPass.getTLI(*F); 407a2e266b3SKazu Hirata auto Calls = extractCallsFromIR(*M, TLI); 408a2e266b3SKazu Hirata 409a2e266b3SKazu Hirata uint64_t GUIDFoo = IndexedMemProfRecord::getGUID("_Z3foov"); 410a2e266b3SKazu Hirata uint64_t GUIDBar = IndexedMemProfRecord::getGUID("_Z3barv"); 411a2e266b3SKazu Hirata uint64_t GUIDBaz = IndexedMemProfRecord::getGUID("_Z3bazv"); 412a2e266b3SKazu Hirata uint64_t GUIDZzz = IndexedMemProfRecord::getGUID("_Z3zzzv"); 413a2e266b3SKazu Hirata 414a2e266b3SKazu Hirata // Verify that extractCallsFromIR extracts caller-callee pairs as expected. 415a2e266b3SKazu Hirata EXPECT_THAT(Calls, 416a2e266b3SKazu Hirata UnorderedElementsAre(Pair( 417a2e266b3SKazu Hirata GUIDFoo, ElementsAre(Pair(LineLocation(1, 3), GUIDBar), 418a2e266b3SKazu Hirata Pair(LineLocation(2, 8), GUIDBaz))))); 419a2e266b3SKazu Hirata 420a2e266b3SKazu Hirata llvm::InstrProfWriter Writer; 421a2e266b3SKazu Hirata std::unique_ptr<IndexedInstrProfReader> Reader; 422a2e266b3SKazu Hirata 423a2e266b3SKazu Hirata const MemInfoBlock MIB = makePartialMIB(); 424a2e266b3SKazu Hirata 425624e89bcSKazu Hirata Writer.setMemProfVersionRequested(Version3); 426a2e266b3SKazu Hirata Writer.setMemProfFullSchema(false); 427a2e266b3SKazu Hirata 428a2e266b3SKazu Hirata ASSERT_THAT_ERROR(Writer.mergeProfileKind(InstrProfKind::MemProf), 429a2e266b3SKazu Hirata Succeeded()); 430a2e266b3SKazu Hirata 431a2e266b3SKazu Hirata const IndexedMemProfRecord IndexedMR = makeRecordV2( 432a2e266b3SKazu Hirata /*AllocFrames=*/{0x111, 0x222, 0x333}, 433624e89bcSKazu Hirata /*CallSiteFrames=*/{}, MIB, getHotColdSchema()); 4344b3b74dfSKazu Hirata 435624e89bcSKazu Hirata IndexedMemProfData MemProfData; 4364b3b74dfSKazu Hirata // The call sites within foo. 4374b3b74dfSKazu Hirata MemProfData.Frames.try_emplace(0, GUIDFoo, 1, 8, false); 4384b3b74dfSKazu Hirata MemProfData.Frames.try_emplace(1, GUIDFoo, 2, 3, false); 4394b3b74dfSKazu Hirata MemProfData.Frames.try_emplace(2, GUIDFoo, 3, 3, false); 4404b3b74dfSKazu Hirata // Line/column numbers below don't matter. 4414b3b74dfSKazu Hirata MemProfData.Frames.try_emplace(3, GUIDBar, 9, 9, false); 4424b3b74dfSKazu Hirata MemProfData.Frames.try_emplace(4, GUIDZzz, 9, 9, false); 4434b3b74dfSKazu Hirata MemProfData.Frames.try_emplace(5, GUIDBaz, 9, 9, false); 4444b3b74dfSKazu Hirata MemProfData.CallStacks.try_emplace( 445624e89bcSKazu Hirata 0x111, std::initializer_list<FrameId>{3, 0}); // bar called by foo 4464b3b74dfSKazu Hirata MemProfData.CallStacks.try_emplace( 447624e89bcSKazu Hirata 0x222, std::initializer_list<FrameId>{4, 1}); // zzz called by foo 4484b3b74dfSKazu Hirata MemProfData.CallStacks.try_emplace( 449624e89bcSKazu Hirata 0x333, std::initializer_list<FrameId>{5, 2}); // baz called by foo 4504b3b74dfSKazu Hirata MemProfData.Records.try_emplace(0x9999, IndexedMR); 4514b3b74dfSKazu Hirata Writer.addMemProfData(MemProfData, Err); 452a2e266b3SKazu Hirata 453a2e266b3SKazu Hirata auto Profile = Writer.writeBuffer(); 454a2e266b3SKazu Hirata 455a2e266b3SKazu Hirata auto ReaderOrErr = 456a2e266b3SKazu Hirata IndexedInstrProfReader::create(std::move(Profile), nullptr); 457a2e266b3SKazu Hirata EXPECT_THAT_ERROR(ReaderOrErr.takeError(), Succeeded()); 458a2e266b3SKazu Hirata Reader = std::move(ReaderOrErr.get()); 459a2e266b3SKazu Hirata 460a2e266b3SKazu Hirata // Verify that getMemProfCallerCalleePairs extracts caller-callee pairs as 461a2e266b3SKazu Hirata // expected. 462a2e266b3SKazu Hirata auto Pairs = Reader->getMemProfCallerCalleePairs(); 463a2e266b3SKazu Hirata ASSERT_THAT(Pairs, SizeIs(4)); 464a2e266b3SKazu Hirata ASSERT_THAT( 465a2e266b3SKazu Hirata Pairs, 466a2e266b3SKazu Hirata Contains(Pair(GUIDFoo, ElementsAre(Pair(LineLocation(1, 8), GUIDBar), 467a2e266b3SKazu Hirata Pair(LineLocation(2, 3), GUIDZzz), 468a2e266b3SKazu Hirata Pair(LineLocation(3, 3), GUIDBaz))))); 469a2e266b3SKazu Hirata 470a2e266b3SKazu Hirata // Verify that computeUndriftMap identifies undrifting opportunities: 471a2e266b3SKazu Hirata // 472a2e266b3SKazu Hirata // Profile IR 473a2e266b3SKazu Hirata // (Line: 1, Column: 8) -> (Line: 1, Column: 3) 474a2e266b3SKazu Hirata // (Line: 3, Column: 3) -> (Line: 2, Column: 8) 475a2e266b3SKazu Hirata auto UndriftMap = computeUndriftMap(*M, Reader.get(), TLI); 476a2e266b3SKazu Hirata ASSERT_THAT(UndriftMap, 477a2e266b3SKazu Hirata UnorderedElementsAre(Pair( 478a2e266b3SKazu Hirata GUIDFoo, UnorderedElementsAre( 479a2e266b3SKazu Hirata Pair(LineLocation(1, 8), LineLocation(1, 3)), 480a2e266b3SKazu Hirata Pair(LineLocation(3, 3), LineLocation(2, 8)))))); 481a2e266b3SKazu Hirata } 482e189d619SKazu Hirata } // namespace 483624e89bcSKazu Hirata } // namespace memprof 484624e89bcSKazu Hirata } // namespace llvm 485