|
6 | 6 | // |
7 | 7 | //===----------------------------------------------------------------------===// |
8 | 8 | // |
9 | | -// MemProf data is serialized in writeMemProf provided in this header file. |
| 9 | +// This file implements IndexedMemProfData, a data structure to hold MemProf |
| 10 | +// in a space optimized format. It also provides utility methods for writing |
| 11 | +// MemProf data. |
10 | 12 | // |
11 | 13 | //===----------------------------------------------------------------------===// |
12 | 14 |
|
| 15 | +#ifndef LLVM_PROFILEDATA_INDEXEDMEMPROFDATA_H |
| 16 | +#define LLVM_PROFILEDATA_INDEXEDMEMPROFDATA_H |
| 17 | + |
13 | 18 | #include "llvm/ProfileData/InstrProf.h" |
14 | 19 | #include "llvm/ProfileData/MemProf.h" |
15 | 20 |
|
16 | 21 | namespace llvm { |
| 22 | +namespace memprof { |
| 23 | +struct IndexedMemProfData { |
| 24 | + // A map to hold memprof data per function. The lower 64 bits obtained from |
| 25 | + // the md5 hash of the function name is used to index into the map. |
| 26 | + llvm::MapVector<GlobalValue::GUID, IndexedMemProfRecord> Records; |
| 27 | + |
| 28 | + // A map to hold frame id to frame mappings. The mappings are used to |
| 29 | + // convert IndexedMemProfRecord to MemProfRecords with frame information |
| 30 | + // inline. |
| 31 | + llvm::MapVector<FrameId, Frame> Frames; |
| 32 | + |
| 33 | + // A map to hold call stack id to call stacks. |
| 34 | + llvm::MapVector<CallStackId, llvm::SmallVector<FrameId>> CallStacks; |
| 35 | + |
| 36 | + FrameId addFrame(const Frame &F) { |
| 37 | + const FrameId Id = hashFrame(F); |
| 38 | + Frames.try_emplace(Id, F); |
| 39 | + return Id; |
| 40 | + } |
| 41 | + |
| 42 | + CallStackId addCallStack(ArrayRef<FrameId> CS) { |
| 43 | + CallStackId CSId = hashCallStack(CS); |
| 44 | + CallStacks.try_emplace(CSId, CS); |
| 45 | + return CSId; |
| 46 | + } |
| 47 | + |
| 48 | + CallStackId addCallStack(SmallVector<FrameId> &&CS) { |
| 49 | + CallStackId CSId = hashCallStack(CS); |
| 50 | + CallStacks.try_emplace(CSId, std::move(CS)); |
| 51 | + return CSId; |
| 52 | + } |
| 53 | + |
| 54 | +private: |
| 55 | + // Return a hash value based on the contents of the frame. Here we use a |
| 56 | + // cryptographic hash function to minimize the chance of hash collisions. We |
| 57 | + // do persist FrameIds as part of memprof formats up to Version 2, inclusive. |
| 58 | + // However, the deserializer never calls this function; it uses FrameIds |
| 59 | + // merely as keys to look up Frames proper. |
| 60 | + FrameId hashFrame(const Frame &F) const { |
| 61 | + llvm::HashBuilder<llvm::TruncatedBLAKE3<8>, llvm::endianness::little> |
| 62 | + HashBuilder; |
| 63 | + HashBuilder.add(F.Function, F.LineOffset, F.Column, F.IsInlineFrame); |
| 64 | + llvm::BLAKE3Result<8> Hash = HashBuilder.final(); |
| 65 | + FrameId Id; |
| 66 | + std::memcpy(&Id, Hash.data(), sizeof(Hash)); |
| 67 | + return Id; |
| 68 | + } |
| 69 | + |
| 70 | + // Compute a CallStackId for a given call stack. |
| 71 | + CallStackId hashCallStack(ArrayRef<FrameId> CS) const { |
| 72 | + llvm::HashBuilder<llvm::TruncatedBLAKE3<8>, llvm::endianness::little> |
| 73 | + HashBuilder; |
| 74 | + for (FrameId F : CS) |
| 75 | + HashBuilder.add(F); |
| 76 | + llvm::BLAKE3Result<8> Hash = HashBuilder.final(); |
| 77 | + CallStackId CSId; |
| 78 | + std::memcpy(&CSId, Hash.data(), sizeof(Hash)); |
| 79 | + return CSId; |
| 80 | + } |
| 81 | +}; |
| 82 | +} // namespace memprof |
17 | 83 |
|
18 | 84 | // Write the MemProf data to OS. |
19 | 85 | Error writeMemProf(ProfOStream &OS, memprof::IndexedMemProfData &MemProfData, |
20 | 86 | memprof::IndexedVersion MemProfVersionRequested, |
21 | 87 | bool MemProfFullSchema); |
22 | | - |
23 | 88 | } // namespace llvm |
| 89 | +#endif |
0 commit comments