1 | #include "llvm/ProfileData/MemProf.h" |
2 | #include "llvm/ADT/SmallVector.h" |
3 | #include "llvm/IR/Function.h" |
4 | #include "llvm/ProfileData/InstrProf.h" |
5 | #include "llvm/ProfileData/SampleProf.h" |
6 | #include "llvm/Support/Endian.h" |
7 | #include "llvm/Support/EndianStream.h" |
8 | |
9 | namespace llvm { |
10 | namespace memprof { |
11 | |
12 | void IndexedMemProfRecord::serialize(const MemProfSchema &Schema, |
13 | raw_ostream &OS) { |
14 | using namespace support; |
15 | |
16 | endian::Writer LE(OS, llvm::endianness::little); |
17 | |
18 | LE.write<uint64_t>(Val: AllocSites.size()); |
19 | for (const IndexedAllocationInfo &N : AllocSites) { |
20 | LE.write<uint64_t>(Val: N.CallStack.size()); |
21 | for (const FrameId &Id : N.CallStack) |
22 | LE.write<FrameId>(Val: Id); |
23 | N.Info.serialize(Schema, OS); |
24 | } |
25 | |
26 | // Related contexts. |
27 | LE.write<uint64_t>(Val: CallSites.size()); |
28 | for (const auto &Frames : CallSites) { |
29 | LE.write<uint64_t>(Val: Frames.size()); |
30 | for (const FrameId &Id : Frames) |
31 | LE.write<FrameId>(Val: Id); |
32 | } |
33 | } |
34 | |
35 | IndexedMemProfRecord |
36 | IndexedMemProfRecord::deserialize(const MemProfSchema &Schema, |
37 | const unsigned char *Ptr) { |
38 | using namespace support; |
39 | |
40 | IndexedMemProfRecord Record; |
41 | |
42 | // Read the meminfo nodes. |
43 | const uint64_t NumNodes = |
44 | endian::readNext<uint64_t, llvm::endianness::little, unaligned>(memory&: Ptr); |
45 | for (uint64_t I = 0; I < NumNodes; I++) { |
46 | IndexedAllocationInfo Node; |
47 | const uint64_t NumFrames = |
48 | endian::readNext<uint64_t, llvm::endianness::little, unaligned>(memory&: Ptr); |
49 | for (uint64_t J = 0; J < NumFrames; J++) { |
50 | const FrameId Id = |
51 | endian::readNext<FrameId, llvm::endianness::little, unaligned>(memory&: Ptr); |
52 | Node.CallStack.push_back(Elt: Id); |
53 | } |
54 | Node.Info.deserialize(Schema, Ptr); |
55 | Ptr += PortableMemInfoBlock::serializedSize(); |
56 | Record.AllocSites.push_back(Elt: Node); |
57 | } |
58 | |
59 | // Read the callsite information. |
60 | const uint64_t NumCtxs = |
61 | endian::readNext<uint64_t, llvm::endianness::little, unaligned>(memory&: Ptr); |
62 | for (uint64_t J = 0; J < NumCtxs; J++) { |
63 | const uint64_t NumFrames = |
64 | endian::readNext<uint64_t, llvm::endianness::little, unaligned>(memory&: Ptr); |
65 | llvm::SmallVector<FrameId> Frames; |
66 | Frames.reserve(N: NumFrames); |
67 | for (uint64_t K = 0; K < NumFrames; K++) { |
68 | const FrameId Id = |
69 | endian::readNext<FrameId, llvm::endianness::little, unaligned>(memory&: Ptr); |
70 | Frames.push_back(Elt: Id); |
71 | } |
72 | Record.CallSites.push_back(Elt: Frames); |
73 | } |
74 | |
75 | return Record; |
76 | } |
77 | |
78 | GlobalValue::GUID IndexedMemProfRecord::getGUID(const StringRef FunctionName) { |
79 | // Canonicalize the function name to drop suffixes such as ".llvm.". Note |
80 | // we do not drop any ".__uniq." suffixes, as getCanonicalFnName does not drop |
81 | // those by default. This is by design to differentiate internal linkage |
82 | // functions during matching. By dropping the other suffixes we can then match |
83 | // functions in the profile use phase prior to their addition. Note that this |
84 | // applies to both instrumented and sampled function names. |
85 | StringRef CanonicalName = |
86 | sampleprof::FunctionSamples::getCanonicalFnName(FnName: FunctionName); |
87 | |
88 | // We use the function guid which we expect to be a uint64_t. At |
89 | // this time, it is the lower 64 bits of the md5 of the canonical |
90 | // function name. |
91 | return Function::getGUID(GlobalName: CanonicalName); |
92 | } |
93 | |
94 | Expected<MemProfSchema> readMemProfSchema(const unsigned char *&Buffer) { |
95 | using namespace support; |
96 | |
97 | const unsigned char *Ptr = Buffer; |
98 | const uint64_t NumSchemaIds = |
99 | endian::readNext<uint64_t, llvm::endianness::little, unaligned>(memory&: Ptr); |
100 | if (NumSchemaIds > static_cast<uint64_t>(Meta::Size)) { |
101 | return make_error<InstrProfError>(Args: instrprof_error::malformed, |
102 | Args: "memprof schema invalid" ); |
103 | } |
104 | |
105 | MemProfSchema Result; |
106 | for (size_t I = 0; I < NumSchemaIds; I++) { |
107 | const uint64_t Tag = |
108 | endian::readNext<uint64_t, llvm::endianness::little, unaligned>(memory&: Ptr); |
109 | if (Tag >= static_cast<uint64_t>(Meta::Size)) { |
110 | return make_error<InstrProfError>(Args: instrprof_error::malformed, |
111 | Args: "memprof schema invalid" ); |
112 | } |
113 | Result.push_back(Elt: static_cast<Meta>(Tag)); |
114 | } |
115 | // Advace the buffer to one past the schema if we succeeded. |
116 | Buffer = Ptr; |
117 | return Result; |
118 | } |
119 | |
120 | } // namespace memprof |
121 | } // namespace llvm |
122 | |