memprof_rawprofile.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. #include <stdint.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include "memprof_rawprofile.h"
  5. #include "profile/MemProfData.inc"
  6. #include "sanitizer_common/sanitizer_allocator_internal.h"
  7. #include "sanitizer_common/sanitizer_array_ref.h"
  8. #include "sanitizer_common/sanitizer_common.h"
  9. #include "sanitizer_common/sanitizer_linux.h"
  10. #include "sanitizer_common/sanitizer_procmaps.h"
  11. #include "sanitizer_common/sanitizer_stackdepot.h"
  12. #include "sanitizer_common/sanitizer_stackdepotbase.h"
  13. #include "sanitizer_common/sanitizer_stacktrace.h"
  14. #include "sanitizer_common/sanitizer_vector.h"
  15. namespace __memprof {
  16. using ::__sanitizer::Vector;
  17. using ::llvm::memprof::MemInfoBlock;
  18. using SegmentEntry = ::llvm::memprof::SegmentEntry;
  19. using Header = ::llvm::memprof::Header;
  20. namespace {
  21. template <class T> char *WriteBytes(const T &Pod, char *Buffer) {
  22. *(T *)Buffer = Pod;
  23. return Buffer + sizeof(T);
  24. }
  25. void RecordStackId(const uptr Key, UNUSED LockedMemInfoBlock *const &MIB,
  26. void *Arg) {
  27. // No need to touch the MIB value here since we are only recording the key.
  28. auto *StackIds = reinterpret_cast<Vector<u64> *>(Arg);
  29. StackIds->PushBack(Key);
  30. }
  31. } // namespace
  32. u64 SegmentSizeBytes(ArrayRef<LoadedModule> Modules) {
  33. u64 NumSegmentsToRecord = 0;
  34. for (const auto &Module : Modules) {
  35. for (const auto &Segment : Module.ranges()) {
  36. if (Segment.executable)
  37. NumSegmentsToRecord++;
  38. }
  39. }
  40. return sizeof(u64) // A header which stores the number of records.
  41. + sizeof(SegmentEntry) * NumSegmentsToRecord;
  42. }
  43. // The segment section uses the following format:
  44. // ---------- Segment Info
  45. // Num Entries
  46. // ---------- Segment Entry
  47. // Start
  48. // End
  49. // Offset
  50. // UuidSize
  51. // Uuid 32B
  52. // ----------
  53. // ...
  54. void SerializeSegmentsToBuffer(ArrayRef<LoadedModule> Modules,
  55. const u64 ExpectedNumBytes, char *&Buffer) {
  56. char *Ptr = Buffer;
  57. // Reserve space for the final count.
  58. Ptr += sizeof(u64);
  59. u64 NumSegmentsRecorded = 0;
  60. for (const auto &Module : Modules) {
  61. for (const auto &Segment : Module.ranges()) {
  62. if (Segment.executable) {
  63. SegmentEntry Entry(Segment.beg, Segment.end, Module.base_address());
  64. CHECK(Module.uuid_size() <= MEMPROF_BUILDID_MAX_SIZE);
  65. Entry.BuildIdSize = Module.uuid_size();
  66. memcpy(Entry.BuildId, Module.uuid(), Module.uuid_size());
  67. memcpy(Ptr, &Entry, sizeof(SegmentEntry));
  68. Ptr += sizeof(SegmentEntry);
  69. NumSegmentsRecorded++;
  70. }
  71. }
  72. }
  73. // Store the number of segments we recorded in the space we reserved.
  74. *((u64 *)Buffer) = NumSegmentsRecorded;
  75. CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
  76. "Expected num bytes != actual bytes written");
  77. }
  78. u64 StackSizeBytes(const Vector<u64> &StackIds) {
  79. u64 NumBytesToWrite = sizeof(u64);
  80. const u64 NumIds = StackIds.Size();
  81. for (unsigned k = 0; k < NumIds; ++k) {
  82. const u64 Id = StackIds[k];
  83. // One entry for the id and then one more for the number of stack pcs.
  84. NumBytesToWrite += 2 * sizeof(u64);
  85. const StackTrace St = StackDepotGet(Id);
  86. CHECK(St.trace != nullptr && St.size > 0 && "Empty stack trace");
  87. for (uptr i = 0; i < St.size && St.trace[i] != 0; i++) {
  88. NumBytesToWrite += sizeof(u64);
  89. }
  90. }
  91. return NumBytesToWrite;
  92. }
  93. // The stack info section uses the following format:
  94. //
  95. // ---------- Stack Info
  96. // Num Entries
  97. // ---------- Stack Entry
  98. // Num Stacks
  99. // PC1
  100. // PC2
  101. // ...
  102. // ----------
  103. void SerializeStackToBuffer(const Vector<u64> &StackIds,
  104. const u64 ExpectedNumBytes, char *&Buffer) {
  105. const u64 NumIds = StackIds.Size();
  106. char *Ptr = Buffer;
  107. Ptr = WriteBytes(static_cast<u64>(NumIds), Ptr);
  108. for (unsigned k = 0; k < NumIds; ++k) {
  109. const u64 Id = StackIds[k];
  110. Ptr = WriteBytes(Id, Ptr);
  111. Ptr += sizeof(u64); // Bump it by u64, we will fill this in later.
  112. u64 Count = 0;
  113. const StackTrace St = StackDepotGet(Id);
  114. for (uptr i = 0; i < St.size && St.trace[i] != 0; i++) {
  115. // PCs in stack traces are actually the return addresses, that is,
  116. // addresses of the next instructions after the call.
  117. uptr pc = StackTrace::GetPreviousInstructionPc(St.trace[i]);
  118. Ptr = WriteBytes(static_cast<u64>(pc), Ptr);
  119. ++Count;
  120. }
  121. // Store the count in the space we reserved earlier.
  122. *(u64 *)(Ptr - (Count + 1) * sizeof(u64)) = Count;
  123. }
  124. CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
  125. "Expected num bytes != actual bytes written");
  126. }
  127. // The MIB section has the following format:
  128. // ---------- MIB Info
  129. // Num Entries
  130. // ---------- MIB Entry 0
  131. // Alloc Count
  132. // ...
  133. // ---------- MIB Entry 1
  134. // Alloc Count
  135. // ...
  136. // ----------
  137. void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector<u64> &StackIds,
  138. const u64 ExpectedNumBytes, char *&Buffer) {
  139. char *Ptr = Buffer;
  140. const u64 NumEntries = StackIds.Size();
  141. Ptr = WriteBytes(NumEntries, Ptr);
  142. for (u64 i = 0; i < NumEntries; i++) {
  143. const u64 Key = StackIds[i];
  144. MIBMapTy::Handle h(&MIBMap, Key, /*remove=*/true, /*create=*/false);
  145. CHECK(h.exists());
  146. Ptr = WriteBytes(Key, Ptr);
  147. Ptr = WriteBytes((*h)->mib, Ptr);
  148. }
  149. CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
  150. "Expected num bytes != actual bytes written");
  151. }
  152. // Format
  153. // ---------- Header
  154. // Magic
  155. // Version
  156. // Total Size
  157. // Segment Offset
  158. // MIB Info Offset
  159. // Stack Offset
  160. // ---------- Segment Info
  161. // Num Entries
  162. // ---------- Segment Entry
  163. // Start
  164. // End
  165. // Offset
  166. // BuildID 32B
  167. // ----------
  168. // ...
  169. // ----------
  170. // Optional Padding Bytes
  171. // ---------- MIB Info
  172. // Num Entries
  173. // ---------- MIB Entry
  174. // Alloc Count
  175. // ...
  176. // ----------
  177. // Optional Padding Bytes
  178. // ---------- Stack Info
  179. // Num Entries
  180. // ---------- Stack Entry
  181. // Num Stacks
  182. // PC1
  183. // PC2
  184. // ...
  185. // ----------
  186. // Optional Padding Bytes
  187. // ...
  188. u64 SerializeToRawProfile(MIBMapTy &MIBMap, ArrayRef<LoadedModule> Modules,
  189. char *&Buffer) {
  190. // Each section size is rounded up to 8b since the first entry in each section
  191. // is a u64 which holds the number of entries in the section by convention.
  192. const u64 NumSegmentBytes = RoundUpTo(SegmentSizeBytes(Modules), 8);
  193. Vector<u64> StackIds;
  194. MIBMap.ForEach(RecordStackId, reinterpret_cast<void *>(&StackIds));
  195. // The first 8b are for the total number of MIB records. Each MIB record is
  196. // preceded by a 8b stack id which is associated with stack frames in the next
  197. // section.
  198. const u64 NumMIBInfoBytes = RoundUpTo(
  199. sizeof(u64) + StackIds.Size() * (sizeof(u64) + sizeof(MemInfoBlock)), 8);
  200. const u64 NumStackBytes = RoundUpTo(StackSizeBytes(StackIds), 8);
  201. // Ensure that the profile is 8b aligned. We allow for some optional padding
  202. // at the end so that any subsequent profile serialized to the same file does
  203. // not incur unaligned accesses.
  204. const u64 TotalSizeBytes = RoundUpTo(
  205. sizeof(Header) + NumSegmentBytes + NumStackBytes + NumMIBInfoBytes, 8);
  206. // Allocate the memory for the entire buffer incl. info blocks.
  207. Buffer = (char *)InternalAlloc(TotalSizeBytes);
  208. char *Ptr = Buffer;
  209. Header header{MEMPROF_RAW_MAGIC_64,
  210. MEMPROF_RAW_VERSION,
  211. static_cast<u64>(TotalSizeBytes),
  212. sizeof(Header),
  213. sizeof(Header) + NumSegmentBytes,
  214. sizeof(Header) + NumSegmentBytes + NumMIBInfoBytes};
  215. Ptr = WriteBytes(header, Ptr);
  216. SerializeSegmentsToBuffer(Modules, NumSegmentBytes, Ptr);
  217. Ptr += NumSegmentBytes;
  218. SerializeMIBInfoToBuffer(MIBMap, StackIds, NumMIBInfoBytes, Ptr);
  219. Ptr += NumMIBInfoBytes;
  220. SerializeStackToBuffer(StackIds, NumStackBytes, Ptr);
  221. return TotalSizeBytes;
  222. }
  223. } // namespace __memprof