1 #include "llvm/ProfileData/MemProf.h" 2 #include "llvm/ADT/DenseMap.h" 3 #include "llvm/ADT/MapVector.h" 4 #include "llvm/DebugInfo/DIContext.h" 5 #include "llvm/DebugInfo/Symbolize/SymbolizableModule.h" 6 #include "llvm/Object/ObjectFile.h" 7 #include "llvm/ProfileData/InstrProf.h" 8 #include "llvm/ProfileData/MemProfData.inc" 9 #include "llvm/ProfileData/RawMemProfReader.h" 10 #include "llvm/Support/Error.h" 11 #include "llvm/Support/MD5.h" 12 #include "gmock/gmock.h" 13 #include "gtest/gtest.h" 14 15 #include <initializer_list> 16 17 namespace { 18 19 using ::llvm::DIGlobal; 20 using ::llvm::DIInliningInfo; 21 using ::llvm::DILineInfo; 22 using ::llvm::DILineInfoSpecifier; 23 using ::llvm::DILocal; 24 using ::llvm::memprof::CallStackMap; 25 using ::llvm::memprof::MemInfoBlock; 26 using ::llvm::memprof::MemProfRecord; 27 using ::llvm::memprof::RawMemProfReader; 28 using ::llvm::memprof::SegmentEntry; 29 using ::llvm::object::SectionedAddress; 30 using ::llvm::symbolize::SymbolizableModule; 31 using ::testing::Return; 32 33 class MockSymbolizer : public SymbolizableModule { 34 public: 35 MOCK_CONST_METHOD3(symbolizeInlinedCode, 36 DIInliningInfo(SectionedAddress, DILineInfoSpecifier, 37 bool)); 38 // Most of the methods in the interface are unused. We only mock the 39 // method that we expect to be called from the memprof reader. 40 virtual DILineInfo symbolizeCode(SectionedAddress, DILineInfoSpecifier, 41 bool) const { 42 llvm_unreachable("unused"); 43 } 44 virtual DIGlobal symbolizeData(SectionedAddress) const { 45 llvm_unreachable("unused"); 46 } 47 virtual std::vector<DILocal> symbolizeFrame(SectionedAddress) const { 48 llvm_unreachable("unused"); 49 } 50 virtual bool isWin32Module() const { llvm_unreachable("unused"); } 51 virtual uint64_t getModulePreferredBase() const { 52 llvm_unreachable("unused"); 53 } 54 }; 55 56 struct MockInfo { 57 std::string FunctionName; 58 uint32_t Line; 59 uint32_t StartLine; 60 uint32_t Column; 61 }; 62 DIInliningInfo makeInliningInfo(std::initializer_list<MockInfo> MockFrames) { 63 DIInliningInfo Result; 64 for (const auto &Item : MockFrames) { 65 DILineInfo Frame; 66 Frame.FunctionName = Item.FunctionName; 67 Frame.Line = Item.Line; 68 Frame.StartLine = Item.StartLine; 69 Frame.Column = Item.Column; 70 Result.addFrame(Frame); 71 } 72 return Result; 73 } 74 75 llvm::SmallVector<SegmentEntry, 4> makeSegments() { 76 llvm::SmallVector<SegmentEntry, 4> Result; 77 // Mimic an entry for a non position independent executable. 78 Result.emplace_back(0x0, 0x40000, 0x0); 79 return Result; 80 } 81 82 const DILineInfoSpecifier specifier() { 83 return DILineInfoSpecifier( 84 DILineInfoSpecifier::FileLineInfoKind::RawValue, 85 DILineInfoSpecifier::FunctionNameKind::LinkageName); 86 } 87 88 MATCHER_P4(FrameContains, Function, LineOffset, Column, Inline, "") { 89 const std::string ExpectedHash = std::to_string(llvm::MD5Hash(Function)); 90 if (arg.Function != ExpectedHash) { 91 *result_listener << "Hash mismatch"; 92 return false; 93 } 94 if (arg.LineOffset == LineOffset && arg.Column == Column && 95 arg.IsInlineFrame == Inline) { 96 return true; 97 } 98 *result_listener << "LineOffset, Column or Inline mismatch"; 99 return false; 100 } 101 102 TEST(MemProf, FillsValue) { 103 std::unique_ptr<MockSymbolizer> Symbolizer(new MockSymbolizer()); 104 105 EXPECT_CALL(*Symbolizer, symbolizeInlinedCode(SectionedAddress{0x2000}, 106 specifier(), false)) 107 .Times(2) 108 .WillRepeatedly(Return(makeInliningInfo({ 109 {"foo", 10, 5, 30}, 110 {"bar", 201, 150, 20}, 111 }))); 112 113 EXPECT_CALL(*Symbolizer, symbolizeInlinedCode(SectionedAddress{0x6000}, 114 specifier(), false)) 115 .Times(1) 116 .WillRepeatedly(Return(makeInliningInfo({ 117 {"baz", 10, 5, 30}, 118 {"qux.llvm.12345", 75, 70, 10}, 119 }))); 120 121 CallStackMap CSM; 122 CSM[0x1] = {0x2000}; 123 CSM[0x2] = {0x6000, 0x2000}; 124 125 llvm::MapVector<uint64_t, MemInfoBlock> Prof; 126 Prof[0x1].alloc_count = 1; 127 Prof[0x2].alloc_count = 2; 128 129 auto Seg = makeSegments(); 130 131 RawMemProfReader Reader(std::move(Symbolizer), Seg, Prof, CSM); 132 133 std::vector<MemProfRecord> Records; 134 for (const MemProfRecord &R : Reader) { 135 Records.push_back(R); 136 } 137 EXPECT_EQ(Records.size(), 2U); 138 139 EXPECT_EQ(Records[0].Info.alloc_count, 1U); 140 EXPECT_EQ(Records[1].Info.alloc_count, 2U); 141 EXPECT_THAT(Records[0].CallStack[0], FrameContains("foo", 5U, 30U, false)); 142 EXPECT_THAT(Records[0].CallStack[1], FrameContains("bar", 51U, 20U, true)); 143 144 EXPECT_THAT(Records[1].CallStack[0], FrameContains("baz", 5U, 30U, false)); 145 EXPECT_THAT(Records[1].CallStack[1], FrameContains("qux", 5U, 10U, true)); 146 EXPECT_THAT(Records[1].CallStack[2], FrameContains("foo", 5U, 30U, false)); 147 EXPECT_THAT(Records[1].CallStack[3], FrameContains("bar", 51U, 20U, true)); 148 } 149 150 } // namespace 151