MemProf.h 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. #ifndef LLVM_PROFILEDATA_MEMPROF_H_
  7. #define LLVM_PROFILEDATA_MEMPROF_H_
  8. #include "llvm/ADT/DenseMap.h"
  9. #include "llvm/ADT/STLFunctionalExtras.h"
  10. #include "llvm/ADT/SmallVector.h"
  11. #include "llvm/IR/GlobalValue.h"
  12. #include "llvm/ProfileData/MemProfData.inc"
  13. #include "llvm/Support/Endian.h"
  14. #include "llvm/Support/EndianStream.h"
  15. #include "llvm/Support/raw_ostream.h"
  16. #include <cstdint>
  17. #include <optional>
  18. namespace llvm {
  19. namespace memprof {
  20. enum class Meta : uint64_t {
  21. Start = 0,
  22. #define MIBEntryDef(NameTag, Name, Type) NameTag,
  23. #include "llvm/ProfileData/MIBEntryDef.inc"
  24. #undef MIBEntryDef
  25. Size
  26. };
  27. using MemProfSchema = llvm::SmallVector<Meta, static_cast<int>(Meta::Size)>;
  28. // Holds the actual MemInfoBlock data with all fields. Contents may be read or
  29. // written partially by providing an appropriate schema to the serialize and
  30. // deserialize methods.
  31. struct PortableMemInfoBlock {
  32. PortableMemInfoBlock() = default;
  33. explicit PortableMemInfoBlock(const MemInfoBlock &Block) {
  34. #define MIBEntryDef(NameTag, Name, Type) Name = Block.Name;
  35. #include "llvm/ProfileData/MIBEntryDef.inc"
  36. #undef MIBEntryDef
  37. }
  38. PortableMemInfoBlock(const MemProfSchema &Schema, const unsigned char *Ptr) {
  39. deserialize(Schema, Ptr);
  40. }
  41. // Read the contents of \p Ptr based on the \p Schema to populate the
  42. // MemInfoBlock member.
  43. void deserialize(const MemProfSchema &Schema, const unsigned char *Ptr) {
  44. using namespace support;
  45. for (const Meta Id : Schema) {
  46. switch (Id) {
  47. #define MIBEntryDef(NameTag, Name, Type) \
  48. case Meta::Name: { \
  49. Name = endian::readNext<Type, little, unaligned>(Ptr); \
  50. } break;
  51. #include "llvm/ProfileData/MIBEntryDef.inc"
  52. #undef MIBEntryDef
  53. default:
  54. llvm_unreachable("Unknown meta type id, is the profile collected from "
  55. "a newer version of the runtime?");
  56. }
  57. }
  58. }
  59. // Write the contents of the MemInfoBlock based on the \p Schema provided to
  60. // the raw_ostream \p OS.
  61. void serialize(const MemProfSchema &Schema, raw_ostream &OS) const {
  62. using namespace support;
  63. endian::Writer LE(OS, little);
  64. for (const Meta Id : Schema) {
  65. switch (Id) {
  66. #define MIBEntryDef(NameTag, Name, Type) \
  67. case Meta::Name: { \
  68. LE.write<Type>(Name); \
  69. } break;
  70. #include "llvm/ProfileData/MIBEntryDef.inc"
  71. #undef MIBEntryDef
  72. default:
  73. llvm_unreachable("Unknown meta type id, invalid input?");
  74. }
  75. }
  76. }
  77. // Print out the contents of the MemInfoBlock in YAML format.
  78. void printYAML(raw_ostream &OS) const {
  79. OS << " MemInfoBlock:\n";
  80. #define MIBEntryDef(NameTag, Name, Type) \
  81. OS << " " << #Name << ": " << Name << "\n";
  82. #include "llvm/ProfileData/MIBEntryDef.inc"
  83. #undef MIBEntryDef
  84. }
  85. // Define getters for each type which can be called by analyses.
  86. #define MIBEntryDef(NameTag, Name, Type) \
  87. Type get##Name() const { return Name; }
  88. #include "llvm/ProfileData/MIBEntryDef.inc"
  89. #undef MIBEntryDef
  90. void clear() { *this = PortableMemInfoBlock(); }
  91. // Returns the full schema currently in use.
  92. static MemProfSchema getSchema() {
  93. MemProfSchema List;
  94. #define MIBEntryDef(NameTag, Name, Type) List.push_back(Meta::Name);
  95. #include "llvm/ProfileData/MIBEntryDef.inc"
  96. #undef MIBEntryDef
  97. return List;
  98. }
  99. bool operator==(const PortableMemInfoBlock &Other) const {
  100. #define MIBEntryDef(NameTag, Name, Type) \
  101. if (Other.get##Name() != get##Name()) \
  102. return false;
  103. #include "llvm/ProfileData/MIBEntryDef.inc"
  104. #undef MIBEntryDef
  105. return true;
  106. }
  107. bool operator!=(const PortableMemInfoBlock &Other) const {
  108. return !operator==(Other);
  109. }
  110. static constexpr size_t serializedSize() {
  111. size_t Result = 0;
  112. #define MIBEntryDef(NameTag, Name, Type) Result += sizeof(Type);
  113. #include "llvm/ProfileData/MIBEntryDef.inc"
  114. #undef MIBEntryDef
  115. return Result;
  116. }
  117. private:
  118. #define MIBEntryDef(NameTag, Name, Type) Type Name = Type();
  119. #include "llvm/ProfileData/MIBEntryDef.inc"
  120. #undef MIBEntryDef
  121. };
  122. // A type representing the id generated by hashing the contents of the Frame.
  123. using FrameId = uint64_t;
  124. // Describes a call frame for a dynamic allocation context. The contents of
  125. // the frame are populated by symbolizing the stack depot call frame from the
  126. // compiler runtime.
  127. struct Frame {
  128. // A uuid (uint64_t) identifying the function. It is obtained by
  129. // llvm::md5(FunctionName) which returns the lower 64 bits.
  130. GlobalValue::GUID Function;
  131. // The symbol name for the function. Only populated in the Frame by the reader
  132. // if requested during initialization. This field should not be serialized.
  133. std::optional<std::string> SymbolName;
  134. // The source line offset of the call from the beginning of parent function.
  135. uint32_t LineOffset;
  136. // The source column number of the call to help distinguish multiple calls
  137. // on the same line.
  138. uint32_t Column;
  139. // Whether the current frame is inlined.
  140. bool IsInlineFrame;
  141. Frame(const Frame &Other) {
  142. Function = Other.Function;
  143. SymbolName = Other.SymbolName;
  144. LineOffset = Other.LineOffset;
  145. Column = Other.Column;
  146. IsInlineFrame = Other.IsInlineFrame;
  147. }
  148. Frame(uint64_t Hash, uint32_t Off, uint32_t Col, bool Inline)
  149. : Function(Hash), LineOffset(Off), Column(Col), IsInlineFrame(Inline) {}
  150. bool operator==(const Frame &Other) const {
  151. // Ignore the SymbolName field to avoid a string compare. Comparing the
  152. // function hash serves the same purpose.
  153. return Other.Function == Function && Other.LineOffset == LineOffset &&
  154. Other.Column == Column && Other.IsInlineFrame == IsInlineFrame;
  155. }
  156. Frame &operator=(const Frame &Other) {
  157. Function = Other.Function;
  158. SymbolName = Other.SymbolName;
  159. LineOffset = Other.LineOffset;
  160. Column = Other.Column;
  161. IsInlineFrame = Other.IsInlineFrame;
  162. return *this;
  163. }
  164. bool operator!=(const Frame &Other) const { return !operator==(Other); }
  165. // Write the contents of the frame to the ostream \p OS.
  166. void serialize(raw_ostream &OS) const {
  167. using namespace support;
  168. endian::Writer LE(OS, little);
  169. // If the type of the GlobalValue::GUID changes, then we need to update
  170. // the reader and the writer.
  171. static_assert(std::is_same<GlobalValue::GUID, uint64_t>::value,
  172. "Expect GUID to be uint64_t.");
  173. LE.write<uint64_t>(Function);
  174. LE.write<uint32_t>(LineOffset);
  175. LE.write<uint32_t>(Column);
  176. LE.write<bool>(IsInlineFrame);
  177. }
  178. // Read a frame from char data which has been serialized as little endian.
  179. static Frame deserialize(const unsigned char *Ptr) {
  180. using namespace support;
  181. const uint64_t F = endian::readNext<uint64_t, little, unaligned>(Ptr);
  182. const uint32_t L = endian::readNext<uint32_t, little, unaligned>(Ptr);
  183. const uint32_t C = endian::readNext<uint32_t, little, unaligned>(Ptr);
  184. const bool I = endian::readNext<bool, little, unaligned>(Ptr);
  185. return Frame(/*Function=*/F, /*LineOffset=*/L, /*Column=*/C,
  186. /*IsInlineFrame=*/I);
  187. }
  188. // Returns the size of the frame information.
  189. static constexpr size_t serializedSize() {
  190. return sizeof(Frame::Function) + sizeof(Frame::LineOffset) +
  191. sizeof(Frame::Column) + sizeof(Frame::IsInlineFrame);
  192. }
  193. // Print the frame information in YAML format.
  194. void printYAML(raw_ostream &OS) const {
  195. OS << " -\n"
  196. << " Function: " << Function << "\n"
  197. << " SymbolName: " << SymbolName.value_or("<None>") << "\n"
  198. << " LineOffset: " << LineOffset << "\n"
  199. << " Column: " << Column << "\n"
  200. << " Inline: " << IsInlineFrame << "\n";
  201. }
  202. // Return a hash value based on the contents of the frame. Here we don't use
  203. // hashing from llvm ADT since we are going to persist the hash id, the hash
  204. // combine algorithm in ADT uses a new randomized seed each time.
  205. inline FrameId hash() const {
  206. auto HashCombine = [](auto Value, size_t Seed) {
  207. std::hash<decltype(Value)> Hasher;
  208. // The constant used below is the 64 bit representation of the fractional
  209. // part of the golden ratio. Used here for the randomness in their bit
  210. // pattern.
  211. return Hasher(Value) + 0x9e3779b97f4a7c15 + (Seed << 6) + (Seed >> 2);
  212. };
  213. size_t Result = 0;
  214. Result ^= HashCombine(Function, Result);
  215. Result ^= HashCombine(LineOffset, Result);
  216. Result ^= HashCombine(Column, Result);
  217. Result ^= HashCombine(IsInlineFrame, Result);
  218. return static_cast<FrameId>(Result);
  219. }
  220. };
  221. // Holds allocation information in a space efficient format where frames are
  222. // represented using unique identifiers.
  223. struct IndexedAllocationInfo {
  224. // The dynamic calling context for the allocation in bottom-up (leaf-to-root)
  225. // order. Frame contents are stored out-of-line.
  226. llvm::SmallVector<FrameId> CallStack;
  227. // The statistics obtained from the runtime for the allocation.
  228. PortableMemInfoBlock Info;
  229. IndexedAllocationInfo() = default;
  230. IndexedAllocationInfo(ArrayRef<FrameId> CS, const MemInfoBlock &MB)
  231. : CallStack(CS.begin(), CS.end()), Info(MB) {}
  232. // Returns the size in bytes when this allocation info struct is serialized.
  233. size_t serializedSize() const {
  234. return sizeof(uint64_t) + // The number of frames to serialize.
  235. sizeof(FrameId) * CallStack.size() + // The callstack frame ids.
  236. PortableMemInfoBlock::serializedSize(); // The size of the payload.
  237. }
  238. bool operator==(const IndexedAllocationInfo &Other) const {
  239. if (Other.Info != Info)
  240. return false;
  241. if (Other.CallStack.size() != CallStack.size())
  242. return false;
  243. for (size_t J = 0; J < Other.CallStack.size(); J++) {
  244. if (Other.CallStack[J] != CallStack[J])
  245. return false;
  246. }
  247. return true;
  248. }
  249. bool operator!=(const IndexedAllocationInfo &Other) const {
  250. return !operator==(Other);
  251. }
  252. };
  253. // Holds allocation information with frame contents inline. The type should
  254. // be used for temporary in-memory instances.
  255. struct AllocationInfo {
  256. // Same as IndexedAllocationInfo::CallStack with the frame contents inline.
  257. llvm::SmallVector<Frame> CallStack;
  258. // Same as IndexedAllocationInfo::Info;
  259. PortableMemInfoBlock Info;
  260. AllocationInfo() = default;
  261. AllocationInfo(
  262. const IndexedAllocationInfo &IndexedAI,
  263. llvm::function_ref<const Frame(const FrameId)> IdToFrameCallback) {
  264. for (const FrameId &Id : IndexedAI.CallStack) {
  265. CallStack.push_back(IdToFrameCallback(Id));
  266. }
  267. Info = IndexedAI.Info;
  268. }
  269. void printYAML(raw_ostream &OS) const {
  270. OS << " -\n";
  271. OS << " Callstack:\n";
  272. // TODO: Print out the frame on one line with to make it easier for deep
  273. // callstacks once we have a test to check valid YAML is generated.
  274. for (const Frame &F : CallStack) {
  275. F.printYAML(OS);
  276. }
  277. Info.printYAML(OS);
  278. }
  279. };
  280. // Holds the memprof profile information for a function. The internal
  281. // representation stores frame ids for efficiency. This representation should
  282. // be used in the profile conversion and manipulation tools.
  283. struct IndexedMemProfRecord {
  284. // Memory allocation sites in this function for which we have memory
  285. // profiling data.
  286. llvm::SmallVector<IndexedAllocationInfo> AllocSites;
  287. // Holds call sites in this function which are part of some memory
  288. // allocation context. We store this as a list of locations, each with its
  289. // list of inline locations in bottom-up order i.e. from leaf to root. The
  290. // inline location list may include additional entries, users should pick
  291. // the last entry in the list with the same function GUID.
  292. llvm::SmallVector<llvm::SmallVector<FrameId>> CallSites;
  293. void clear() {
  294. AllocSites.clear();
  295. CallSites.clear();
  296. }
  297. void merge(const IndexedMemProfRecord &Other) {
  298. // TODO: Filter out duplicates which may occur if multiple memprof
  299. // profiles are merged together using llvm-profdata.
  300. AllocSites.append(Other.AllocSites);
  301. CallSites.append(Other.CallSites);
  302. }
  303. size_t serializedSize() const {
  304. size_t Result = sizeof(GlobalValue::GUID);
  305. for (const IndexedAllocationInfo &N : AllocSites)
  306. Result += N.serializedSize();
  307. // The number of callsites we have information for.
  308. Result += sizeof(uint64_t);
  309. for (const auto &Frames : CallSites) {
  310. // The number of frame ids to serialize.
  311. Result += sizeof(uint64_t);
  312. Result += Frames.size() * sizeof(FrameId);
  313. }
  314. return Result;
  315. }
  316. bool operator==(const IndexedMemProfRecord &Other) const {
  317. if (Other.AllocSites.size() != AllocSites.size())
  318. return false;
  319. if (Other.CallSites.size() != CallSites.size())
  320. return false;
  321. for (size_t I = 0; I < AllocSites.size(); I++) {
  322. if (AllocSites[I] != Other.AllocSites[I])
  323. return false;
  324. }
  325. for (size_t I = 0; I < CallSites.size(); I++) {
  326. if (CallSites[I] != Other.CallSites[I])
  327. return false;
  328. }
  329. return true;
  330. }
  331. // Serializes the memprof records in \p Records to the ostream \p OS based
  332. // on the schema provided in \p Schema.
  333. void serialize(const MemProfSchema &Schema, raw_ostream &OS);
  334. // Deserializes memprof records from the Buffer.
  335. static IndexedMemProfRecord deserialize(const MemProfSchema &Schema,
  336. const unsigned char *Buffer);
  337. // Returns the GUID for the function name after canonicalization. For
  338. // memprof, we remove any .llvm suffix added by LTO. MemProfRecords are
  339. // mapped to functions using this GUID.
  340. static GlobalValue::GUID getGUID(const StringRef FunctionName);
  341. };
  342. // Holds the memprof profile information for a function. The internal
  343. // representation stores frame contents inline. This representation should
  344. // be used for small amount of temporary, in memory instances.
  345. struct MemProfRecord {
  346. // Same as IndexedMemProfRecord::AllocSites with frame contents inline.
  347. llvm::SmallVector<AllocationInfo> AllocSites;
  348. // Same as IndexedMemProfRecord::CallSites with frame contents inline.
  349. llvm::SmallVector<llvm::SmallVector<Frame>> CallSites;
  350. MemProfRecord() = default;
  351. MemProfRecord(
  352. const IndexedMemProfRecord &Record,
  353. llvm::function_ref<const Frame(const FrameId Id)> IdToFrameCallback) {
  354. for (const IndexedAllocationInfo &IndexedAI : Record.AllocSites) {
  355. AllocSites.emplace_back(IndexedAI, IdToFrameCallback);
  356. }
  357. for (const ArrayRef<FrameId> Site : Record.CallSites) {
  358. llvm::SmallVector<Frame> Frames;
  359. for (const FrameId Id : Site) {
  360. Frames.push_back(IdToFrameCallback(Id));
  361. }
  362. CallSites.push_back(Frames);
  363. }
  364. }
  365. // Prints out the contents of the memprof record in YAML.
  366. void print(llvm::raw_ostream &OS) const {
  367. if (!AllocSites.empty()) {
  368. OS << " AllocSites:\n";
  369. for (const AllocationInfo &N : AllocSites)
  370. N.printYAML(OS);
  371. }
  372. if (!CallSites.empty()) {
  373. OS << " CallSites:\n";
  374. for (const llvm::SmallVector<Frame> &Frames : CallSites) {
  375. for (const Frame &F : Frames) {
  376. OS << " -\n";
  377. F.printYAML(OS);
  378. }
  379. }
  380. }
  381. }
  382. };
  383. // Reads a memprof schema from a buffer. All entries in the buffer are
  384. // interpreted as uint64_t. The first entry in the buffer denotes the number of
  385. // ids in the schema. Subsequent entries are integers which map to memprof::Meta
  386. // enum class entries. After successfully reading the schema, the pointer is one
  387. // byte past the schema contents.
  388. Expected<MemProfSchema> readMemProfSchema(const unsigned char *&Buffer);
  389. // Trait for reading IndexedMemProfRecord data from the on-disk hash table.
  390. class RecordLookupTrait {
  391. public:
  392. using data_type = const IndexedMemProfRecord &;
  393. using internal_key_type = uint64_t;
  394. using external_key_type = uint64_t;
  395. using hash_value_type = uint64_t;
  396. using offset_type = uint64_t;
  397. RecordLookupTrait() = delete;
  398. RecordLookupTrait(const MemProfSchema &S) : Schema(S) {}
  399. static bool EqualKey(uint64_t A, uint64_t B) { return A == B; }
  400. static uint64_t GetInternalKey(uint64_t K) { return K; }
  401. static uint64_t GetExternalKey(uint64_t K) { return K; }
  402. hash_value_type ComputeHash(uint64_t K) { return K; }
  403. static std::pair<offset_type, offset_type>
  404. ReadKeyDataLength(const unsigned char *&D) {
  405. using namespace support;
  406. offset_type KeyLen = endian::readNext<offset_type, little, unaligned>(D);
  407. offset_type DataLen = endian::readNext<offset_type, little, unaligned>(D);
  408. return std::make_pair(KeyLen, DataLen);
  409. }
  410. uint64_t ReadKey(const unsigned char *D, offset_type /*Unused*/) {
  411. using namespace support;
  412. return endian::readNext<external_key_type, little, unaligned>(D);
  413. }
  414. data_type ReadData(uint64_t K, const unsigned char *D,
  415. offset_type /*Unused*/) {
  416. Record = IndexedMemProfRecord::deserialize(Schema, D);
  417. return Record;
  418. }
  419. private:
  420. // Holds the memprof schema used to deserialize records.
  421. MemProfSchema Schema;
  422. // Holds the records from one function deserialized from the indexed format.
  423. IndexedMemProfRecord Record;
  424. };
  425. // Trait for writing IndexedMemProfRecord data to the on-disk hash table.
  426. class RecordWriterTrait {
  427. public:
  428. using key_type = uint64_t;
  429. using key_type_ref = uint64_t;
  430. using data_type = IndexedMemProfRecord;
  431. using data_type_ref = IndexedMemProfRecord &;
  432. using hash_value_type = uint64_t;
  433. using offset_type = uint64_t;
  434. // Pointer to the memprof schema to use for the generator. Unlike the reader
  435. // we must use a default constructor with no params for the writer trait so we
  436. // have a public member which must be initialized by the user.
  437. MemProfSchema *Schema = nullptr;
  438. RecordWriterTrait() = default;
  439. static hash_value_type ComputeHash(key_type_ref K) { return K; }
  440. static std::pair<offset_type, offset_type>
  441. EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) {
  442. using namespace support;
  443. endian::Writer LE(Out, little);
  444. offset_type N = sizeof(K);
  445. LE.write<offset_type>(N);
  446. offset_type M = V.serializedSize();
  447. LE.write<offset_type>(M);
  448. return std::make_pair(N, M);
  449. }
  450. void EmitKey(raw_ostream &Out, key_type_ref K, offset_type /*Unused*/) {
  451. using namespace support;
  452. endian::Writer LE(Out, little);
  453. LE.write<uint64_t>(K);
  454. }
  455. void EmitData(raw_ostream &Out, key_type_ref /*Unused*/, data_type_ref V,
  456. offset_type /*Unused*/) {
  457. assert(Schema != nullptr && "MemProf schema is not initialized!");
  458. V.serialize(*Schema, Out);
  459. }
  460. };
  461. // Trait for writing frame mappings to the on-disk hash table.
  462. class FrameWriterTrait {
  463. public:
  464. using key_type = FrameId;
  465. using key_type_ref = FrameId;
  466. using data_type = Frame;
  467. using data_type_ref = Frame &;
  468. using hash_value_type = FrameId;
  469. using offset_type = uint64_t;
  470. static hash_value_type ComputeHash(key_type_ref K) { return K; }
  471. static std::pair<offset_type, offset_type>
  472. EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) {
  473. using namespace support;
  474. endian::Writer LE(Out, little);
  475. offset_type N = sizeof(K);
  476. LE.write<offset_type>(N);
  477. offset_type M = V.serializedSize();
  478. LE.write<offset_type>(M);
  479. return std::make_pair(N, M);
  480. }
  481. void EmitKey(raw_ostream &Out, key_type_ref K, offset_type /*Unused*/) {
  482. using namespace support;
  483. endian::Writer LE(Out, little);
  484. LE.write<key_type>(K);
  485. }
  486. void EmitData(raw_ostream &Out, key_type_ref /*Unused*/, data_type_ref V,
  487. offset_type /*Unused*/) {
  488. V.serialize(Out);
  489. }
  490. };
  491. // Trait for reading frame mappings from the on-disk hash table.
  492. class FrameLookupTrait {
  493. public:
  494. using data_type = const Frame;
  495. using internal_key_type = FrameId;
  496. using external_key_type = FrameId;
  497. using hash_value_type = FrameId;
  498. using offset_type = uint64_t;
  499. static bool EqualKey(internal_key_type A, internal_key_type B) {
  500. return A == B;
  501. }
  502. static uint64_t GetInternalKey(internal_key_type K) { return K; }
  503. static uint64_t GetExternalKey(external_key_type K) { return K; }
  504. hash_value_type ComputeHash(internal_key_type K) { return K; }
  505. static std::pair<offset_type, offset_type>
  506. ReadKeyDataLength(const unsigned char *&D) {
  507. using namespace support;
  508. offset_type KeyLen = endian::readNext<offset_type, little, unaligned>(D);
  509. offset_type DataLen = endian::readNext<offset_type, little, unaligned>(D);
  510. return std::make_pair(KeyLen, DataLen);
  511. }
  512. uint64_t ReadKey(const unsigned char *D, offset_type /*Unused*/) {
  513. using namespace support;
  514. return endian::readNext<external_key_type, little, unaligned>(D);
  515. }
  516. data_type ReadData(uint64_t K, const unsigned char *D,
  517. offset_type /*Unused*/) {
  518. return Frame::deserialize(D);
  519. }
  520. };
  521. } // namespace memprof
  522. } // namespace llvm
  523. #endif // LLVM_PROFILEDATA_MEMPROF_H_
  524. #ifdef __GNUC__
  525. #pragma GCC diagnostic pop
  526. #endif