@@ -82,9 +82,9 @@ struct PortableMemInfoBlock {
8282
8383 // Print out the contents of the MemInfoBlock in YAML format.
8484 void printYAML (raw_ostream &OS) const {
85- OS << " MemInfoBlock:\n " ;
85+ OS << " MemInfoBlock:\n " ;
8686#define MIBEntryDef (NameTag, Name, Type ) \
87- OS << " " << #Name << " : " << Name << " \n " ;
87+ OS << " " << #Name << " : " << Name << " \n " ;
8888#include " llvm/ProfileData/MIBEntryDef.inc"
8989#undef MIBEntryDef
9090 }
@@ -133,6 +133,7 @@ struct PortableMemInfoBlock {
133133#undef MIBEntryDef
134134};
135135
136+ // Holds the memprof profile information for a function.
136137struct MemProfRecord {
137138 // Describes a call frame for a dynamic allocation context. The contents of
138139 // the frame are populated by symbolizing the stack depot call frame from the
@@ -193,64 +194,152 @@ struct MemProfRecord {
193194 return sizeof (Frame::Function) + sizeof (Frame::LineOffset) +
194195 sizeof (Frame::Column) + sizeof (Frame::IsInlineFrame);
195196 }
197+
198+ // Print the frame information in YAML format.
199+ void printYAML (raw_ostream &OS) const {
200+ OS << " -\n "
201+ << " Function: " << Function << " \n "
202+ << " LineOffset: " << LineOffset << " \n "
203+ << " Column: " << Column << " \n "
204+ << " Inline: " << IsInlineFrame << " \n " ;
205+ }
196206 };
197207
198- // The dynamic calling context for the allocation.
199- llvm::SmallVector<Frame> CallStack;
200- // The statistics obtained from the runtime for the allocation.
201- PortableMemInfoBlock Info;
208+ struct AllocationInfo {
209+ // The dynamic calling context for the allocation.
210+ llvm::SmallVector<Frame> CallStack;
211+ // The statistics obtained from the runtime for the allocation.
212+ PortableMemInfoBlock Info;
213+
214+ AllocationInfo () = default ;
215+ AllocationInfo (ArrayRef<Frame> CS, const MemInfoBlock &MB)
216+ : CallStack(CS.begin(), CS.end()), Info(MB) {}
217+
218+ void printYAML (raw_ostream &OS) const {
219+ OS << " -\n " ;
220+ OS << " Callstack:\n " ;
221+ // TODO: Print out the frame on one line with to make it easier for deep
222+ // callstacks once we have a test to check valid YAML is generated.
223+ for (const auto &Frame : CallStack)
224+ Frame.printYAML (OS);
225+ Info.printYAML (OS);
226+ }
227+
228+ size_t serializedSize () const {
229+ return sizeof (uint64_t ) + // The number of frames to serialize.
230+ Frame::serializedSize () *
231+ CallStack.size () + // The contents of the frames.
232+ PortableMemInfoBlock::serializedSize (); // The size of the payload.
233+ }
234+
235+ bool operator ==(const AllocationInfo &Other) const {
236+ if (Other.Info != Info)
237+ return false ;
238+
239+ if (Other.CallStack .size () != CallStack.size ())
240+ return false ;
241+
242+ for (size_t J = 0 ; J < Other.CallStack .size (); J++) {
243+ if (Other.CallStack [J] != CallStack[J])
244+ return false ;
245+ }
246+ return true ;
247+ }
248+
249+ bool operator !=(const AllocationInfo &Other) const {
250+ return !operator ==(Other);
251+ }
252+ };
253+
254+ // Memory allocation sites in this function for which we have memory profiling
255+ // data.
256+ llvm::SmallVector<AllocationInfo> AllocSites;
257+ // Holds call sites in this function which are part of some memory allocation
258+ // context. We store this as a list of locations, each with its list of
259+ // inline locations in bottom-up order i.e. from leaf to root. The inline
260+ // location list may include additional entries, users should pick the last
261+ // entry in the list with the same function GUID.
262+ llvm::SmallVector<llvm::SmallVector<Frame>> CallSites;
202263
203264 void clear () {
204- CallStack.clear ();
205- Info.clear ();
265+ AllocSites.clear ();
266+ CallSites.clear ();
267+ }
268+
269+ void merge (const MemProfRecord &Other) {
270+ // TODO: Filter out duplicates which may occur if multiple memprof profiles
271+ // are merged together using llvm-profdata.
272+ AllocSites.append (Other.AllocSites );
273+ CallSites.append (Other.CallSites );
206274 }
207275
208276 size_t serializedSize () const {
209- return sizeof (uint64_t ) + // The number of frames to serialize.
210- Frame::serializedSize () *
211- CallStack.size () + // The contents of the frames.
212- PortableMemInfoBlock::serializedSize (); // The size of the payload.
277+ size_t Result = sizeof (GlobalValue::GUID);
278+ for (const AllocationInfo &N : AllocSites)
279+ Result += N.serializedSize ();
280+
281+ // The number of callsites we have information for.
282+ Result += sizeof (uint64_t );
283+ for (const auto &Frames : CallSites) {
284+ // The number of frames to serialize.
285+ Result += sizeof (uint64_t );
286+ for (const Frame &F : Frames)
287+ Result += F.serializedSize ();
288+ }
289+ return Result;
213290 }
214291
215292 // Prints out the contents of the memprof record in YAML.
216293 void print (llvm::raw_ostream &OS) const {
217- OS << " Callstack:\n " ;
218- // TODO: Print out the frame on one line with to make it easier for deep
219- // callstacks once we have a test to check valid YAML is generated.
220- for (const auto &Frame : CallStack) {
221- OS << " -\n "
222- << " Function: " << Frame.Function << " \n "
223- << " LineOffset: " << Frame.LineOffset << " \n "
224- << " Column: " << Frame.Column << " \n "
225- << " Inline: " << Frame.IsInlineFrame << " \n " ;
294+ if (!AllocSites.empty ()) {
295+ OS << " AllocSites:\n " ;
296+ for (const AllocationInfo &N : AllocSites)
297+ N.printYAML (OS);
226298 }
227299
228- Info.printYAML (OS);
300+ if (!CallSites.empty ()) {
301+ OS << " CallSites:\n " ;
302+ for (const auto &Frames : CallSites) {
303+ for (const auto &F : Frames) {
304+ OS << " -\n " ;
305+ F.printYAML (OS);
306+ }
307+ }
308+ }
229309 }
230310
231311 bool operator ==(const MemProfRecord &Other) const {
232- if (Other.Info != Info )
312+ if (Other.AllocSites . size () != AllocSites. size () )
233313 return false ;
234314
235- if (Other.CallStack .size () != CallStack .size ())
315+ if (Other.CallSites .size () != CallSites .size ())
236316 return false ;
237317
238- for (size_t I = 0 ; I < Other.CallStack .size (); I++) {
239- if (Other.CallStack [I] != CallStack[I])
318+ for (size_t I = 0 ; I < AllocSites.size (); I++) {
319+ if (AllocSites[I] != Other.AllocSites [I])
320+ return false ;
321+ }
322+
323+ for (size_t I = 0 ; I < CallSites.size (); I++) {
324+ if (CallSites[I] != Other.CallSites [I])
240325 return false ;
241326 }
242327 return true ;
243328 }
244- };
245329
246- // Serializes the memprof records in \p Records to the ostream \p OS based on
247- // the schema provided in \p Schema.
248- void serializeRecords (const ArrayRef<MemProfRecord> Records,
249- const MemProfSchema &Schema, raw_ostream &OS);
330+ // Serializes the memprof records in \p Records to the ostream \p OS based on
331+ // the schema provided in \p Schema.
332+ void serialize (const MemProfSchema &Schema, raw_ostream &OS);
250333
251- // Deserializes memprof records from the Buffer
252- SmallVector<MemProfRecord, 4 > deserializeRecords (const MemProfSchema &Schema,
253- const unsigned char *Buffer);
334+ // Deserializes memprof records from the Buffer.
335+ static MemProfRecord deserialize (const MemProfSchema &Schema,
336+ const unsigned char *Buffer);
337+
338+ // Returns the GUID for the function name after canonicalization. For memprof,
339+ // we remove any .llvm suffix added by LTO. MemProfRecords are mapped to
340+ // functions using this GUID.
341+ static GlobalValue::GUID getGUID (const StringRef FunctionName);
342+ };
254343
255344// Reads a memprof schema from a buffer. All entries in the buffer are
256345// interpreted as uint64_t. The first entry in the buffer denotes the number of
@@ -259,14 +348,11 @@ SmallVector<MemProfRecord, 4> deserializeRecords(const MemProfSchema &Schema,
259348// byte past the schema contents.
260349Expected<MemProfSchema> readMemProfSchema (const unsigned char *&Buffer);
261350
262- using FunctionMemProfMap =
263- DenseMap<uint64_t , SmallVector<memprof::MemProfRecord, 4 >>;
264-
265351// / Trait for lookups into the on-disk hash table for memprof format in the
266352// / indexed profile.
267353class MemProfRecordLookupTrait {
268354public:
269- using data_type = ArrayRef< MemProfRecord> ;
355+ using data_type = const MemProfRecord & ;
270356 using internal_key_type = uint64_t ;
271357 using external_key_type = uint64_t ;
272358 using hash_value_type = uint64_t ;
@@ -297,24 +383,24 @@ class MemProfRecordLookupTrait {
297383
298384 data_type ReadData (uint64_t K, const unsigned char *D,
299385 offset_type /* Unused*/ ) {
300- Records = deserializeRecords (Schema, D);
301- return Records ;
386+ Record = MemProfRecord::deserialize (Schema, D);
387+ return Record ;
302388 }
303389
304390private:
305391 // Holds the memprof schema used to deserialize records.
306392 MemProfSchema Schema;
307393 // Holds the records from one function deserialized from the indexed format.
308- llvm::SmallVector< MemProfRecord, 4 > Records ;
394+ MemProfRecord Record ;
309395};
310396
311397class MemProfRecordWriterTrait {
312398public:
313399 using key_type = uint64_t ;
314400 using key_type_ref = uint64_t ;
315401
316- using data_type = ArrayRef< MemProfRecord> ;
317- using data_type_ref = ArrayRef< MemProfRecord> ;
402+ using data_type = MemProfRecord;
403+ using data_type_ref = MemProfRecord & ;
318404
319405 using hash_value_type = uint64_t ;
320406 using offset_type = uint64_t ;
@@ -333,17 +419,9 @@ class MemProfRecordWriterTrait {
333419 using namespace support ;
334420
335421 endian::Writer LE (Out, little);
336-
337422 offset_type N = sizeof (K);
338423 LE.write <offset_type>(N);
339-
340- offset_type M = 0 ;
341-
342- M += sizeof (uint64_t );
343- for (const auto &Record : V) {
344- M += Record.serializedSize ();
345- }
346-
424+ offset_type M = V.serializedSize ();
347425 LE.write <offset_type>(M);
348426 return std::make_pair (N, M);
349427 }
@@ -357,7 +435,7 @@ class MemProfRecordWriterTrait {
357435 void EmitData (raw_ostream &Out, key_type_ref /* Unused*/ , data_type_ref V,
358436 offset_type /* Unused*/ ) {
359437 assert (Schema != nullptr && " MemProf schema is not initialized!" );
360- serializeRecords (V, *Schema, Out);
438+ V. serialize ( *Schema, Out);
361439 }
362440};
363441
0 commit comments