5 #include "memprof_rawprofile.h"
6 #include "profile/MemProfData.inc"
7 #include "sanitizer_common/sanitizer_allocator_internal.h"
8 #include "sanitizer_common/sanitizer_array_ref.h"
9 #include "sanitizer_common/sanitizer_common.h"
10 #include "sanitizer_common/sanitizer_linux.h"
11 #include "sanitizer_common/sanitizer_procmaps.h"
12 #include "sanitizer_common/sanitizer_stackdepot.h"
13 #include "sanitizer_common/sanitizer_stackdepotbase.h"
14 #include "sanitizer_common/sanitizer_stacktrace.h"
15 #include "sanitizer_common/sanitizer_vector.h"
18 using ::__sanitizer::Vector
;
19 using ::llvm::memprof::MemInfoBlock
;
20 using SegmentEntry
= ::llvm::memprof::SegmentEntry
;
21 using Header
= ::llvm::memprof::Header
;
24 template <class T
> char *WriteBytes(const T
&Pod
, char *Buffer
) {
26 return Buffer
+ sizeof(T
);
29 void RecordStackId(const uptr Key
, UNUSED LockedMemInfoBlock
*const &MIB
,
31 // No need to touch the MIB value here since we are only recording the key.
32 auto *StackIds
= reinterpret_cast<Vector
<u64
> *>(Arg
);
33 StackIds
->PushBack(Key
);
37 u64
SegmentSizeBytes(ArrayRef
<LoadedModule
> Modules
) {
38 u64 NumSegmentsToRecord
= 0;
39 for (const auto &Module
: Modules
) {
40 for (const auto &Segment
: Module
.ranges()) {
41 if (Segment
.executable
)
42 NumSegmentsToRecord
++;
46 return sizeof(u64
) // A header which stores the number of records.
47 + sizeof(SegmentEntry
) * NumSegmentsToRecord
;
50 // The segment section uses the following format:
51 // ---------- Segment Info
53 // ---------- Segment Entry
61 void SerializeSegmentsToBuffer(ArrayRef
<LoadedModule
> Modules
,
62 const u64 ExpectedNumBytes
, char *&Buffer
) {
64 // Reserve space for the final count.
67 u64 NumSegmentsRecorded
= 0;
69 for (const auto &Module
: Modules
) {
70 for (const auto &Segment
: Module
.ranges()) {
71 if (Segment
.executable
) {
72 SegmentEntry
Entry(Segment
.beg
, Segment
.end
, Module
.base_address());
73 CHECK(Module
.uuid_size() <= MEMPROF_BUILDID_MAX_SIZE
);
74 Entry
.BuildIdSize
= Module
.uuid_size();
75 memcpy(Entry
.BuildId
, Module
.uuid(), Module
.uuid_size());
76 memcpy(Ptr
, &Entry
, sizeof(SegmentEntry
));
77 Ptr
+= sizeof(SegmentEntry
);
78 NumSegmentsRecorded
++;
82 // Store the number of segments we recorded in the space we reserved.
83 *((u64
*)Buffer
) = NumSegmentsRecorded
;
84 CHECK(ExpectedNumBytes
>= static_cast<u64
>(Ptr
- Buffer
) &&
85 "Expected num bytes != actual bytes written");
88 u64
StackSizeBytes(const Vector
<u64
> &StackIds
) {
89 u64 NumBytesToWrite
= sizeof(u64
);
91 const u64 NumIds
= StackIds
.Size();
92 for (unsigned k
= 0; k
< NumIds
; ++k
) {
93 const u64 Id
= StackIds
[k
];
94 // One entry for the id and then one more for the number of stack pcs.
95 NumBytesToWrite
+= 2 * sizeof(u64
);
96 const StackTrace St
= StackDepotGet(Id
);
98 CHECK(St
.trace
!= nullptr && St
.size
> 0 && "Empty stack trace");
99 for (uptr i
= 0; i
< St
.size
&& St
.trace
[i
] != 0; i
++) {
100 NumBytesToWrite
+= sizeof(u64
);
103 return NumBytesToWrite
;
106 // The stack info section uses the following format:
108 // ---------- Stack Info
110 // ---------- Stack Entry
116 void SerializeStackToBuffer(const Vector
<u64
> &StackIds
,
117 const u64 ExpectedNumBytes
, char *&Buffer
) {
118 const u64 NumIds
= StackIds
.Size();
120 Ptr
= WriteBytes(static_cast<u64
>(NumIds
), Ptr
);
122 for (unsigned k
= 0; k
< NumIds
; ++k
) {
123 const u64 Id
= StackIds
[k
];
124 Ptr
= WriteBytes(Id
, Ptr
);
125 Ptr
+= sizeof(u64
); // Bump it by u64, we will fill this in later.
127 const StackTrace St
= StackDepotGet(Id
);
128 for (uptr i
= 0; i
< St
.size
&& St
.trace
[i
] != 0; i
++) {
129 // PCs in stack traces are actually the return addresses, that is,
130 // addresses of the next instructions after the call.
131 uptr pc
= StackTrace::GetPreviousInstructionPc(St
.trace
[i
]);
132 Ptr
= WriteBytes(static_cast<u64
>(pc
), Ptr
);
135 // Store the count in the space we reserved earlier.
136 *(u64
*)(Ptr
- (Count
+ 1) * sizeof(u64
)) = Count
;
139 CHECK(ExpectedNumBytes
>= static_cast<u64
>(Ptr
- Buffer
) &&
140 "Expected num bytes != actual bytes written");
143 // The MIB section has the following format:
144 // ---------- MIB Info
146 // ---------- MIB Entry 0
149 // ---- AccessHistogram Entry 0
151 // ---- AccessHistogram Entry AccessHistogramSize - 1
152 // ---------- MIB Entry 1
155 // ---- AccessHistogram Entry 0
157 // ---- AccessHistogram Entry AccessHistogramSize - 1
159 void SerializeMIBInfoToBuffer(MIBMapTy
&MIBMap
, const Vector
<u64
> &StackIds
,
160 const u64 ExpectedNumBytes
, char *&Buffer
) {
162 const u64 NumEntries
= StackIds
.Size();
163 Ptr
= WriteBytes(NumEntries
, Ptr
);
164 for (u64 i
= 0; i
< NumEntries
; i
++) {
165 const u64 Key
= StackIds
[i
];
166 MIBMapTy::Handle
h(&MIBMap
, Key
, /*remove=*/true, /*create=*/false);
168 Ptr
= WriteBytes(Key
, Ptr
);
169 // FIXME: We unnecessarily serialize the AccessHistogram pointer. Adding a
170 // serialization schema will fix this issue. See also FIXME in
172 Ptr
= WriteBytes((*h
)->mib
, Ptr
);
173 for (u64 j
= 0; j
< (*h
)->mib
.AccessHistogramSize
; ++j
) {
174 u64 HistogramEntry
= ((u64
*)((*h
)->mib
.AccessHistogram
))[j
];
175 Ptr
= WriteBytes(HistogramEntry
, Ptr
);
177 if ((*h
)->mib
.AccessHistogramSize
> 0) {
178 InternalFree((void *)((*h
)->mib
.AccessHistogram
));
181 CHECK(ExpectedNumBytes
>= static_cast<u64
>(Ptr
- Buffer
) &&
182 "Expected num bytes != actual bytes written");
193 // ---------- Segment Info
195 // ---------- Segment Entry
203 // Optional Padding Bytes
204 // ---------- MIB Info
206 // ---------- MIB Entry
209 // ---- AccessHistogram Entry 0
211 // ---- AccessHistogram Entry AccessHistogramSize - 1
212 // ---------- MIB Entry 1
215 // ---- AccessHistogram Entry 0
217 // ---- AccessHistogram Entry AccessHistogramSize - 1
218 // Optional Padding Bytes
219 // ---------- Stack Info
221 // ---------- Stack Entry
227 // Optional Padding Bytes
229 u64
SerializeToRawProfile(MIBMapTy
&MIBMap
, ArrayRef
<LoadedModule
> Modules
,
231 // Each section size is rounded up to 8b since the first entry in each section
232 // is a u64 which holds the number of entries in the section by convention.
233 const u64 NumSegmentBytes
= RoundUpTo(SegmentSizeBytes(Modules
), 8);
235 Vector
<u64
> StackIds
;
236 MIBMap
.ForEach(RecordStackId
, reinterpret_cast<void *>(&StackIds
));
237 // The first 8b are for the total number of MIB records. Each MIB record is
238 // preceded by a 8b stack id which is associated with stack frames in the next
240 const u64 NumMIBInfoBytes
= RoundUpTo(
241 sizeof(u64
) + StackIds
.Size() * (sizeof(u64
) + sizeof(MemInfoBlock
)), 8);
243 // Get Number of AccessHistogram entries in total
244 u64 TotalAccessHistogramEntries
= 0;
246 [](const uptr Key
, UNUSED LockedMemInfoBlock
*const &MIB
, void *Arg
) {
247 u64
*TotalAccessHistogramEntries
= (u64
*)Arg
;
248 *TotalAccessHistogramEntries
+= MIB
->mib
.AccessHistogramSize
;
250 reinterpret_cast<void *>(&TotalAccessHistogramEntries
));
251 const u64 NumHistogramBytes
=
252 RoundUpTo(TotalAccessHistogramEntries
* sizeof(uint64_t), 8);
254 const u64 NumStackBytes
= RoundUpTo(StackSizeBytes(StackIds
), 8);
256 // Ensure that the profile is 8b aligned. We allow for some optional padding
257 // at the end so that any subsequent profile serialized to the same file does
258 // not incur unaligned accesses.
259 const u64 TotalSizeBytes
=
260 RoundUpTo(sizeof(Header
) + NumSegmentBytes
+ NumStackBytes
+
261 NumMIBInfoBytes
+ NumHistogramBytes
,
264 // Allocate the memory for the entire buffer incl. info blocks.
265 Buffer
= (char *)InternalAlloc(TotalSizeBytes
);
268 Header header
{MEMPROF_RAW_MAGIC_64
,
270 static_cast<u64
>(TotalSizeBytes
),
272 sizeof(Header
) + NumSegmentBytes
,
273 sizeof(Header
) + NumSegmentBytes
+ NumMIBInfoBytes
+
275 Ptr
= WriteBytes(header
, Ptr
);
277 SerializeSegmentsToBuffer(Modules
, NumSegmentBytes
, Ptr
);
278 Ptr
+= NumSegmentBytes
;
280 SerializeMIBInfoToBuffer(MIBMap
, StackIds
,
281 NumMIBInfoBytes
+ NumHistogramBytes
, Ptr
);
282 Ptr
+= NumMIBInfoBytes
+ NumHistogramBytes
;
284 SerializeStackToBuffer(StackIds
, NumStackBytes
, Ptr
);
286 return TotalSizeBytes
;
289 } // namespace __memprof