[clang] Handle __declspec() attributes in using
[llvm-project.git] / compiler-rt / lib / memprof / memprof_rawprofile.cpp
blobf065e8dbcabc0c12031979757ad1a18464ff8e87
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <string.h>
5 #include "memprof_rawprofile.h"
6 #include "profile/MemProfData.inc"
7 #include "sanitizer_common/sanitizer_allocator_internal.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"
16 namespace __memprof {
17 using ::__sanitizer::Vector;
18 using ::llvm::memprof::MemInfoBlock;
19 using SegmentEntry = ::llvm::memprof::SegmentEntry;
20 using Header = ::llvm::memprof::Header;
22 namespace {
23 template <class T> char *WriteBytes(T Pod, char *&Buffer) {
24 *(T *)Buffer = Pod;
25 return Buffer + sizeof(T);
28 void RecordStackId(const uptr Key, UNUSED LockedMemInfoBlock *const &MIB,
29 void *Arg) {
30 // No need to touch the MIB value here since we are only recording the key.
31 auto *StackIds = reinterpret_cast<Vector<u64> *>(Arg);
32 StackIds->PushBack(Key);
34 } // namespace
36 u64 SegmentSizeBytes(MemoryMappingLayoutBase &Layout) {
37 u64 NumSegmentsToRecord = 0;
38 MemoryMappedSegment segment;
39 for (Layout.Reset(); Layout.Next(&segment);)
40 if (segment.IsReadable() && segment.IsExecutable())
41 NumSegmentsToRecord++;
43 return sizeof(u64) // A header which stores the number of records.
44 + sizeof(SegmentEntry) * NumSegmentsToRecord;
47 // The segment section uses the following format:
48 // ---------- Segment Info
49 // Num Entries
50 // ---------- Segment Entry
51 // Start
52 // End
53 // Offset
54 // BuildID 32B
55 // ----------
56 // ...
57 void SerializeSegmentsToBuffer(MemoryMappingLayoutBase &Layout,
58 const u64 ExpectedNumBytes, char *&Buffer) {
59 char *Ptr = Buffer;
60 // Reserve space for the final count.
61 Ptr += sizeof(u64);
63 u64 NumSegmentsRecorded = 0;
64 MemoryMappedSegment segment;
66 for (Layout.Reset(); Layout.Next(&segment);) {
67 if (segment.IsReadable() && segment.IsExecutable()) {
68 // TODO: Record segment.uuid when it is implemented for Linux-Elf.
69 SegmentEntry Entry(segment.start, segment.end, segment.offset);
70 memcpy(Ptr, &Entry, sizeof(SegmentEntry));
71 Ptr += sizeof(SegmentEntry);
72 NumSegmentsRecorded++;
76 // Store the number of segments we recorded in the space we reserved.
77 *((u64 *)Buffer) = NumSegmentsRecorded;
78 CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
79 "Expected num bytes != actual bytes written");
82 u64 StackSizeBytes(const Vector<u64> &StackIds) {
83 u64 NumBytesToWrite = sizeof(u64);
85 const u64 NumIds = StackIds.Size();
86 for (unsigned k = 0; k < NumIds; ++k) {
87 const u64 Id = StackIds[k];
88 // One entry for the id and then one more for the number of stack pcs.
89 NumBytesToWrite += 2 * sizeof(u64);
90 const StackTrace St = StackDepotGet(Id);
92 CHECK(St.trace != nullptr && St.size > 0 && "Empty stack trace");
93 for (uptr i = 0; i < St.size && St.trace[i] != 0; i++) {
94 NumBytesToWrite += sizeof(u64);
97 return NumBytesToWrite;
100 // The stack info section uses the following format:
102 // ---------- Stack Info
103 // Num Entries
104 // ---------- Stack Entry
105 // Num Stacks
106 // PC1
107 // PC2
108 // ...
109 // ----------
110 void SerializeStackToBuffer(const Vector<u64> &StackIds,
111 const u64 ExpectedNumBytes, char *&Buffer) {
112 const u64 NumIds = StackIds.Size();
113 char *Ptr = Buffer;
114 Ptr = WriteBytes(static_cast<u64>(NumIds), Ptr);
116 for (unsigned k = 0; k < NumIds; ++k) {
117 const u64 Id = StackIds[k];
118 Ptr = WriteBytes(Id, Ptr);
119 Ptr += sizeof(u64); // Bump it by u64, we will fill this in later.
120 u64 Count = 0;
121 const StackTrace St = StackDepotGet(Id);
122 for (uptr i = 0; i < St.size && St.trace[i] != 0; i++) {
123 // PCs in stack traces are actually the return addresses, that is,
124 // addresses of the next instructions after the call.
125 uptr pc = StackTrace::GetPreviousInstructionPc(St.trace[i]);
126 Ptr = WriteBytes(static_cast<u64>(pc), Ptr);
127 ++Count;
129 // Store the count in the space we reserved earlier.
130 *(u64 *)(Ptr - (Count + 1) * sizeof(u64)) = Count;
133 CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
134 "Expected num bytes != actual bytes written");
137 // The MIB section has the following format:
138 // ---------- MIB Info
139 // Num Entries
140 // ---------- MIB Entry 0
141 // Alloc Count
142 // ...
143 // ---------- MIB Entry 1
144 // Alloc Count
145 // ...
146 // ----------
147 void SerializeMIBInfoToBuffer(MIBMapTy &MIBMap, const Vector<u64> &StackIds,
148 const u64 ExpectedNumBytes, char *&Buffer) {
149 char *Ptr = Buffer;
150 const u64 NumEntries = StackIds.Size();
151 Ptr = WriteBytes(NumEntries, Ptr);
153 for (u64 i = 0; i < NumEntries; i++) {
154 const u64 Key = StackIds[i];
155 MIBMapTy::Handle h(&MIBMap, Key, /*remove=*/true, /*create=*/false);
156 CHECK(h.exists());
157 Ptr = WriteBytes(Key, Ptr);
158 Ptr = WriteBytes((*h)->mib, Ptr);
161 CHECK(ExpectedNumBytes >= static_cast<u64>(Ptr - Buffer) &&
162 "Expected num bytes != actual bytes written");
165 // Format
166 // ---------- Header
167 // Magic
168 // Version
169 // Total Size
170 // Segment Offset
171 // MIB Info Offset
172 // Stack Offset
173 // ---------- Segment Info
174 // Num Entries
175 // ---------- Segment Entry
176 // Start
177 // End
178 // Offset
179 // BuildID 32B
180 // ----------
181 // ...
182 // ----------
183 // Optional Padding Bytes
184 // ---------- MIB Info
185 // Num Entries
186 // ---------- MIB Entry
187 // Alloc Count
188 // ...
189 // ----------
190 // Optional Padding Bytes
191 // ---------- Stack Info
192 // Num Entries
193 // ---------- Stack Entry
194 // Num Stacks
195 // PC1
196 // PC2
197 // ...
198 // ----------
199 // Optional Padding Bytes
200 // ...
201 u64 SerializeToRawProfile(MIBMapTy &MIBMap, MemoryMappingLayoutBase &Layout,
202 char *&Buffer) {
203 // Each section size is rounded up to 8b since the first entry in each section
204 // is a u64 which holds the number of entries in the section by convention.
205 const u64 NumSegmentBytes = RoundUpTo(SegmentSizeBytes(Layout), 8);
207 Vector<u64> StackIds;
208 MIBMap.ForEach(RecordStackId, reinterpret_cast<void *>(&StackIds));
209 // The first 8b are for the total number of MIB records. Each MIB record is
210 // preceded by a 8b stack id which is associated with stack frames in the next
211 // section.
212 const u64 NumMIBInfoBytes = RoundUpTo(
213 sizeof(u64) + StackIds.Size() * (sizeof(u64) + sizeof(MemInfoBlock)), 8);
215 const u64 NumStackBytes = RoundUpTo(StackSizeBytes(StackIds), 8);
217 // Ensure that the profile is 8b aligned. We allow for some optional padding
218 // at the end so that any subsequent profile serialized to the same file does
219 // not incur unaligned accesses.
220 const u64 TotalSizeBytes = RoundUpTo(
221 sizeof(Header) + NumSegmentBytes + NumStackBytes + NumMIBInfoBytes, 8);
223 // Allocate the memory for the entire buffer incl. info blocks.
224 Buffer = (char *)InternalAlloc(TotalSizeBytes);
225 char *Ptr = Buffer;
227 Header header{MEMPROF_RAW_MAGIC_64,
228 MEMPROF_RAW_VERSION,
229 static_cast<u64>(TotalSizeBytes),
230 sizeof(Header),
231 sizeof(Header) + NumSegmentBytes,
232 sizeof(Header) + NumSegmentBytes + NumMIBInfoBytes};
233 Ptr = WriteBytes(header, Ptr);
235 SerializeSegmentsToBuffer(Layout, NumSegmentBytes, Ptr);
236 Ptr += NumSegmentBytes;
238 SerializeMIBInfoToBuffer(MIBMap, StackIds, NumMIBInfoBytes, Ptr);
239 Ptr += NumMIBInfoBytes;
241 SerializeStackToBuffer(StackIds, NumStackBytes, Ptr);
243 return TotalSizeBytes;
246 } // namespace __memprof