LLVM 22.0.0git
MemProf.cpp
Go to the documentation of this file.
3#include "llvm/IR/Function.h"
8
9namespace llvm {
10namespace memprof {
13#define MIBEntryDef(NameTag, Name, Type) List.push_back(Meta::Name);
15#undef MIBEntryDef
16 return List;
17}
18
20 return {Meta::AllocCount, Meta::TotalSize, Meta::TotalLifetime,
21 Meta::TotalLifetimeAccessDensity};
22}
23
24static size_t serializedSizeV2(const IndexedAllocationInfo &IAI,
25 const MemProfSchema &Schema) {
26 size_t Size = 0;
27 // The CallStackId
28 Size += sizeof(CallStackId);
29 // The size of the payload.
31 return Size;
32}
33
34static size_t serializedSizeV3(const IndexedAllocationInfo &IAI,
35 const MemProfSchema &Schema) {
36 size_t Size = 0;
37 // The linear call stack ID.
38 Size += sizeof(LinearCallStackId);
39 // The size of the payload.
41 return Size;
42}
43
45 IndexedVersion Version) const {
46 switch (Version) {
47 case Version2:
48 return serializedSizeV2(*this, Schema);
49 // Combine V3 and V4 as the size calculation is the same
50 case Version3:
51 case Version4:
52 return serializedSizeV3(*this, Schema);
53 }
54 llvm_unreachable("unsupported MemProf version");
55}
56
58 const MemProfSchema &Schema) {
59 // The number of alloc sites to serialize.
60 size_t Result = sizeof(uint64_t);
61 for (const IndexedAllocationInfo &N : Record.AllocSites)
62 Result += N.serializedSize(Schema, Version2);
63
64 // The number of callsites we have information for.
65 Result += sizeof(uint64_t);
66 // The CallStackId
67 Result += Record.CallSites.size() * sizeof(CallStackId);
68 return Result;
69}
70
72 const MemProfSchema &Schema) {
73 // The number of alloc sites to serialize.
74 size_t Result = sizeof(uint64_t);
75 for (const IndexedAllocationInfo &N : Record.AllocSites)
76 Result += N.serializedSize(Schema, Version3);
77
78 // The number of callsites we have information for.
79 Result += sizeof(uint64_t);
80 // The linear call stack ID.
81 // Note: V3 only stored the LinearCallStackId per call site.
82 Result += Record.CallSites.size() * sizeof(LinearCallStackId);
83 return Result;
84}
85
87 const MemProfSchema &Schema) {
88 // The number of alloc sites to serialize.
89 size_t Result = sizeof(uint64_t);
90 for (const IndexedAllocationInfo &N : Record.AllocSites)
91 Result += N.serializedSize(Schema, Version4);
92
93 // The number of callsites we have information for.
94 Result += sizeof(uint64_t);
95 for (const auto &CS : Record.CallSites)
96 Result += sizeof(LinearCallStackId) + sizeof(uint64_t) +
97 CS.CalleeGuids.size() * sizeof(GlobalValue::GUID);
98 return Result;
99}
100
102 IndexedVersion Version) const {
103 switch (Version) {
104 case Version2:
105 return serializedSizeV2(*this, Schema);
106 case Version3:
107 return serializedSizeV3(*this, Schema);
108 case Version4:
109 return serializedSizeV4(*this, Schema);
110 }
111 llvm_unreachable("unsupported MemProf version");
112}
113
115 const MemProfSchema &Schema, raw_ostream &OS) {
116 using namespace support;
117
119
120 LE.write<uint64_t>(Record.AllocSites.size());
121 for (const IndexedAllocationInfo &N : Record.AllocSites) {
122 LE.write<CallStackId>(N.CSId);
123 N.Info.serialize(Schema, OS);
124 }
125
126 // Related contexts.
127 LE.write<uint64_t>(Record.CallSites.size());
128 for (const auto &CS : Record.CallSites)
129 LE.write<CallStackId>(CS.CSId);
130}
131
132static void serializeV3(
133 const IndexedMemProfRecord &Record, const MemProfSchema &Schema,
135 llvm::DenseMap<CallStackId, LinearCallStackId> &MemProfCallStackIndexes) {
136 using namespace support;
137
139
140 LE.write<uint64_t>(Record.AllocSites.size());
141 for (const IndexedAllocationInfo &N : Record.AllocSites) {
142 assert(MemProfCallStackIndexes.contains(N.CSId));
143 LE.write<LinearCallStackId>(MemProfCallStackIndexes[N.CSId]);
144 N.Info.serialize(Schema, OS);
145 }
146
147 // Related contexts.
148 LE.write<uint64_t>(Record.CallSites.size());
149 for (const auto &CS : Record.CallSites) {
150 assert(MemProfCallStackIndexes.contains(CS.CSId));
151 LE.write<LinearCallStackId>(MemProfCallStackIndexes[CS.CSId]);
152 }
153}
154
155static void serializeV4(
156 const IndexedMemProfRecord &Record, const MemProfSchema &Schema,
158 llvm::DenseMap<CallStackId, LinearCallStackId> &MemProfCallStackIndexes) {
159 using namespace support;
160
162
163 LE.write<uint64_t>(Record.AllocSites.size());
164 for (const IndexedAllocationInfo &N : Record.AllocSites) {
165 assert(MemProfCallStackIndexes.contains(N.CSId));
166 LE.write<LinearCallStackId>(MemProfCallStackIndexes[N.CSId]);
167 N.Info.serialize(Schema, OS);
168 }
169
170 // Related contexts.
171 LE.write<uint64_t>(Record.CallSites.size());
172 for (const auto &CS : Record.CallSites) {
173 assert(MemProfCallStackIndexes.contains(CS.CSId));
174 LE.write<LinearCallStackId>(MemProfCallStackIndexes[CS.CSId]);
175 LE.write<uint64_t>(CS.CalleeGuids.size());
176 for (const auto &Guid : CS.CalleeGuids)
177 LE.write<GlobalValue::GUID>(Guid);
178 }
179}
180
183 llvm::DenseMap<CallStackId, LinearCallStackId> *MemProfCallStackIndexes)
184 const {
185 switch (Version) {
186 case Version2:
187 serializeV2(*this, Schema, OS);
188 return;
189 case Version3:
190 serializeV3(*this, Schema, OS, *MemProfCallStackIndexes);
191 return;
192 case Version4:
193 serializeV4(*this, Schema, OS, *MemProfCallStackIndexes);
194 return;
195 }
196 llvm_unreachable("unsupported MemProf version");
197}
198
200 const unsigned char *Ptr) {
201 using namespace support;
202
204
205 // Read the meminfo nodes.
206 const uint64_t NumNodes =
207 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
208 Record.AllocSites.reserve(NumNodes);
209 for (uint64_t I = 0; I < NumNodes; I++) {
211 Node.CSId = endian::readNext<CallStackId, llvm::endianness::little>(Ptr);
212 Node.Info.deserialize(Schema, Ptr);
214 Record.AllocSites.push_back(Node);
215 }
216
217 // Read the callsite information.
218 const uint64_t NumCtxs =
219 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
220 Record.CallSites.reserve(NumCtxs);
221 for (uint64_t J = 0; J < NumCtxs; J++) {
222 CallStackId CSId =
223 endian::readNext<CallStackId, llvm::endianness::little>(Ptr);
224 Record.CallSites.emplace_back(CSId);
225 }
226
227 return Record;
228}
229
231 const unsigned char *Ptr) {
232 using namespace support;
233
235
236 // Read the meminfo nodes.
237 const uint64_t NumNodes =
238 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
239 Record.AllocSites.reserve(NumNodes);
240 const size_t SerializedSize = PortableMemInfoBlock::serializedSize(Schema);
241 for (uint64_t I = 0; I < NumNodes; I++) {
243 Node.CSId =
244 endian::readNext<LinearCallStackId, llvm::endianness::little>(Ptr);
245 Node.Info.deserialize(Schema, Ptr);
246 Ptr += SerializedSize;
247 Record.AllocSites.push_back(Node);
248 }
249
250 // Read the callsite information.
251 const uint64_t NumCtxs =
252 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
253 Record.CallSites.reserve(NumCtxs);
254 for (uint64_t J = 0; J < NumCtxs; J++) {
255 // We are storing LinearCallStackId in CallSiteIds, which is a vector of
256 // CallStackId. Assert that CallStackId is no smaller than
257 // LinearCallStackId.
258 static_assert(sizeof(LinearCallStackId) <= sizeof(CallStackId));
259 LinearCallStackId CSId =
260 endian::readNext<LinearCallStackId, llvm::endianness::little>(Ptr);
261 Record.CallSites.emplace_back(CSId);
262 }
263
264 return Record;
265}
266
268 const unsigned char *Ptr) {
269 using namespace support;
270
272
273 // Read the meminfo nodes.
274 const uint64_t NumNodes =
275 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
276 Record.AllocSites.reserve(NumNodes);
277 const size_t SerializedSize = PortableMemInfoBlock::serializedSize(Schema);
278 for (uint64_t I = 0; I < NumNodes; I++) {
280 Node.CSId =
281 endian::readNext<LinearCallStackId, llvm::endianness::little>(Ptr);
282 Node.Info.deserialize(Schema, Ptr);
283 Ptr += SerializedSize;
284 Record.AllocSites.push_back(Node);
285 }
286
287 // Read the callsite information.
288 const uint64_t NumCtxs =
289 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
290 Record.CallSites.reserve(NumCtxs);
291 for (uint64_t J = 0; J < NumCtxs; J++) {
292 static_assert(sizeof(LinearCallStackId) <= sizeof(CallStackId));
293 LinearCallStackId CSId =
294 endian::readNext<LinearCallStackId, llvm::endianness::little>(Ptr);
295 const uint64_t NumGuids =
296 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
298 Guids.reserve(NumGuids);
299 for (uint64_t K = 0; K < NumGuids; ++K)
300 Guids.push_back(
301 endian::readNext<GlobalValue::GUID, llvm::endianness::little>(Ptr));
302 Record.CallSites.emplace_back(CSId, std::move(Guids));
303 }
304
305 return Record;
306}
307
308IndexedMemProfRecord
310 const unsigned char *Ptr,
312 switch (Version) {
313 case Version2:
314 return deserializeV2(Schema, Ptr);
315 case Version3:
316 return deserializeV3(Schema, Ptr);
317 case Version4:
318 return deserializeV4(Schema, Ptr);
319 }
320 llvm_unreachable("unsupported MemProf version");
321}
322
324 llvm::function_ref<std::vector<Frame>(const CallStackId)> Callback) const {
326
327 Record.AllocSites.reserve(AllocSites.size());
328 for (const IndexedAllocationInfo &IndexedAI : AllocSites) {
330 AI.Info = IndexedAI.Info;
331 AI.CallStack = Callback(IndexedAI.CSId);
332 Record.AllocSites.push_back(std::move(AI));
333 }
334
335 Record.CallSites.reserve(CallSites.size());
336 for (const IndexedCallSiteInfo &CS : CallSites) {
337 std::vector<Frame> Frames = Callback(CS.CSId);
338 Record.CallSites.emplace_back(std::move(Frames), CS.CalleeGuids);
339 }
340
341 return Record;
342}
343
345 // Canonicalize the function name to drop suffixes such as ".llvm.". Note
346 // we do not drop any ".__uniq." suffixes, as getCanonicalFnName does not drop
347 // those by default. This is by design to differentiate internal linkage
348 // functions during matching. By dropping the other suffixes we can then match
349 // functions in the profile use phase prior to their addition. Note that this
350 // applies to both instrumented and sampled function names.
351 StringRef CanonicalName =
353
354 // We use the function guid which we expect to be a uint64_t. At
355 // this time, it is the lower 64 bits of the md5 of the canonical
356 // function name.
357 return Function::getGUIDAssumingExternalLinkage(CanonicalName);
358}
359
360Expected<MemProfSchema> readMemProfSchema(const unsigned char *&Buffer) {
361 using namespace support;
362
363 const unsigned char *Ptr = Buffer;
364 const uint64_t NumSchemaIds =
365 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
366 if (NumSchemaIds > static_cast<uint64_t>(Meta::Size)) {
367 return make_error<InstrProfError>(instrprof_error::malformed,
368 "memprof schema invalid");
369 }
370
371 MemProfSchema Result;
372 for (size_t I = 0; I < NumSchemaIds; I++) {
373 const uint64_t Tag =
374 endian::readNext<uint64_t, llvm::endianness::little>(Ptr);
375 if (Tag >= static_cast<uint64_t>(Meta::Size)) {
376 return make_error<InstrProfError>(instrprof_error::malformed,
377 "memprof schema invalid");
378 }
379 Result.push_back(static_cast<Meta>(Tag));
380 }
381 // Advance the buffer to one past the schema if we succeeded.
382 Buffer = Ptr;
383 return Result;
384}
385} // namespace memprof
386} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define I(x, y, z)
Definition: MD5.cpp:58
raw_pwrite_stream & OS
This file defines the SmallVector class.
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition: DenseMap.h:168
Tagged union holding either a T or a Error.
Definition: Error.h:485
static LLVM_ABI GUID getGUIDAssumingExternalLinkage(StringRef GlobalName)
Return a 64-bit global unique ID constructed from the name of a global symbol.
Definition: Globals.cpp:77
uint64_t GUID
Declare a type to represent a global unique identifier for a global value.
Definition: GlobalValue.h:577
void reserve(size_type N)
Definition: SmallVector.h:664
void push_back(const T &Elt)
Definition: SmallVector.h:414
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
static StringRef getCanonicalFnName(const Function &F)
Return the canonical name for a function, taking into account suffix elision policy attributes.
Definition: SampleProf.h:1102
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static IndexedMemProfRecord deserializeV4(const MemProfSchema &Schema, const unsigned char *Ptr)
Definition: MemProf.cpp:267
static IndexedMemProfRecord deserializeV3(const MemProfSchema &Schema, const unsigned char *Ptr)
Definition: MemProf.cpp:230
static void serializeV3(const IndexedMemProfRecord &Record, const MemProfSchema &Schema, raw_ostream &OS, llvm::DenseMap< CallStackId, LinearCallStackId > &MemProfCallStackIndexes)
Definition: MemProf.cpp:132
LLVM_ABI MemProfSchema getHotColdSchema()
Definition: MemProf.cpp:19
uint32_t LinearCallStackId
Definition: MemProf.h:355
static size_t serializedSizeV2(const IndexedAllocationInfo &IAI, const MemProfSchema &Schema)
Definition: MemProf.cpp:24
static size_t serializedSizeV3(const IndexedAllocationInfo &IAI, const MemProfSchema &Schema)
Definition: MemProf.cpp:34
uint64_t CallStackId
Definition: MemProf.h:352
LLVM_ABI MemProfSchema getFullSchema()
Definition: MemProf.cpp:11
LLVM_ABI GlobalValue::GUID getGUID(const StringRef FunctionName)
Definition: MemProf.cpp:344
static void serializeV4(const IndexedMemProfRecord &Record, const MemProfSchema &Schema, raw_ostream &OS, llvm::DenseMap< CallStackId, LinearCallStackId > &MemProfCallStackIndexes)
Definition: MemProf.cpp:155
LLVM_ABI Expected< MemProfSchema > readMemProfSchema(const unsigned char *&Buffer)
Definition: MemProf.cpp:360
static void serializeV2(const IndexedMemProfRecord &Record, const MemProfSchema &Schema, raw_ostream &OS)
Definition: MemProf.cpp:114
static IndexedMemProfRecord deserializeV2(const MemProfSchema &Schema, const unsigned char *Ptr)
Definition: MemProf.cpp:199
static size_t serializedSizeV4(const IndexedMemProfRecord &Record, const MemProfSchema &Schema)
Definition: MemProf.cpp:86
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
#define N
std::vector< Frame > CallStack
Definition: MemProf.h:417
PortableMemInfoBlock Info
Definition: MemProf.h:419
LLVM_ABI size_t serializedSize(const MemProfSchema &Schema, IndexedVersion Version) const
Definition: MemProf.cpp:44
llvm::SmallVector< IndexedAllocationInfo > AllocSites
Definition: MemProf.h:441
LLVM_ABI size_t serializedSize(const MemProfSchema &Schema, IndexedVersion Version) const
Definition: MemProf.cpp:101
LLVM_ABI void serialize(const MemProfSchema &Schema, raw_ostream &OS, IndexedVersion Version, llvm::DenseMap< CallStackId, LinearCallStackId > *MemProfCallStackIndexes=nullptr) const
Definition: MemProf.cpp:181
static LLVM_ABI IndexedMemProfRecord deserialize(const MemProfSchema &Schema, const unsigned char *Buffer, IndexedVersion Version)
Definition: MemProf.cpp:309
llvm::SmallVector< IndexedCallSiteInfo > CallSites
Definition: MemProf.h:447
LLVM_ABI MemProfRecord toMemProfRecord(llvm::function_ref< std::vector< Frame >(const CallStackId)> Callback) const
Definition: MemProf.cpp:323
static size_t serializedSize(const MemProfSchema &Schema)
Definition: MemProf.h:204
Adapter to write values to a stream in a particular byte order.
Definition: EndianStream.h:67