| #include "llvm/ProfileData/MemProf.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/ProfileData/InstrProf.h" |
| #include "llvm/Support/Endian.h" |
| #include "llvm/Support/EndianStream.h" |
| |
| namespace llvm { |
| namespace memprof { |
| |
| void IndexedMemProfRecord::serialize(const MemProfSchema &Schema, |
| raw_ostream &OS) { |
| using namespace support; |
| |
| endian::Writer LE(OS, little); |
| |
| LE.write<uint64_t>(AllocSites.size()); |
| for (const IndexedAllocationInfo &N : AllocSites) { |
| LE.write<uint64_t>(N.CallStack.size()); |
| for (const FrameId &Id : N.CallStack) |
| LE.write<FrameId>(Id); |
| N.Info.serialize(Schema, OS); |
| } |
| |
| // Related contexts. |
| LE.write<uint64_t>(CallSites.size()); |
| for (const auto &Frames : CallSites) { |
| LE.write<uint64_t>(Frames.size()); |
| for (const FrameId &Id : Frames) |
| LE.write<FrameId>(Id); |
| } |
| } |
| |
| IndexedMemProfRecord |
| IndexedMemProfRecord::deserialize(const MemProfSchema &Schema, |
| const unsigned char *Ptr) { |
| using namespace support; |
| |
| IndexedMemProfRecord Record; |
| |
| // Read the meminfo nodes. |
| const uint64_t NumNodes = endian::readNext<uint64_t, little, unaligned>(Ptr); |
| for (uint64_t I = 0; I < NumNodes; I++) { |
| IndexedAllocationInfo Node; |
| const uint64_t NumFrames = |
| endian::readNext<uint64_t, little, unaligned>(Ptr); |
| for (uint64_t J = 0; J < NumFrames; J++) { |
| const FrameId Id = endian::readNext<FrameId, little, unaligned>(Ptr); |
| Node.CallStack.push_back(Id); |
| } |
| Node.Info.deserialize(Schema, Ptr); |
| Ptr += PortableMemInfoBlock::serializedSize(); |
| Record.AllocSites.push_back(Node); |
| } |
| |
| // Read the callsite information. |
| const uint64_t NumCtxs = endian::readNext<uint64_t, little, unaligned>(Ptr); |
| for (uint64_t J = 0; J < NumCtxs; J++) { |
| const uint64_t NumFrames = |
| endian::readNext<uint64_t, little, unaligned>(Ptr); |
| llvm::SmallVector<FrameId> Frames; |
| Frames.reserve(NumFrames); |
| for (uint64_t K = 0; K < NumFrames; K++) { |
| const FrameId Id = endian::readNext<FrameId, little, unaligned>(Ptr); |
| Frames.push_back(Id); |
| } |
| Record.CallSites.push_back(Frames); |
| } |
| |
| return Record; |
| } |
| |
| GlobalValue::GUID IndexedMemProfRecord::getGUID(const StringRef FunctionName) { |
| const auto Pos = FunctionName.find(".llvm."); |
| |
| // We use the function guid which we expect to be a uint64_t. At |
| // this time, it is the lower 64 bits of the md5 of the function |
| // name. Any suffix with .llvm. is trimmed since these are added by |
| // thinLTO global promotion. At the time the profile is consumed, |
| // these suffixes will not be present. |
| return Function::getGUID(FunctionName.take_front(Pos)); |
| } |
| |
| Expected<MemProfSchema> readMemProfSchema(const unsigned char *&Buffer) { |
| using namespace support; |
| |
| const unsigned char *Ptr = Buffer; |
| const uint64_t NumSchemaIds = |
| endian::readNext<uint64_t, little, unaligned>(Ptr); |
| if (NumSchemaIds > static_cast<uint64_t>(Meta::Size)) { |
| return make_error<InstrProfError>(instrprof_error::malformed, |
| "memprof schema invalid"); |
| } |
| |
| MemProfSchema Result; |
| for (size_t I = 0; I < NumSchemaIds; I++) { |
| const uint64_t Tag = endian::readNext<uint64_t, little, unaligned>(Ptr); |
| if (Tag >= static_cast<uint64_t>(Meta::Size)) { |
| return make_error<InstrProfError>(instrprof_error::malformed, |
| "memprof schema invalid"); |
| } |
| Result.push_back(static_cast<Meta>(Tag)); |
| } |
| // Advace the buffer to one past the schema if we succeeded. |
| Buffer = Ptr; |
| return Result; |
| } |
| |
| } // namespace memprof |
| } // namespace llvm |