1 /*===- InstrProfilingWriter.c - Write instrumentation to a file or buffer -===*\
3 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 |* See https://llvm.org/LICENSE.txt for license information.
5 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 \*===----------------------------------------------------------------------===*/
9 // Note: This is linked into the Darwin kernel, and must remain compatible
10 // with freestanding compilation. See `darwin_add_builtin_libraries`.
18 #include "InstrProfiling.h"
19 #include "InstrProfilingInternal.h"
20 #include "InstrProfilingPort.h"
22 #define INSTR_PROF_VALUE_PROF_DATA
23 #include "profile/InstrProfData.inc"
25 COMPILER_RT_VISIBILITY
void (*FreeHook
)(void *) = NULL
;
26 static ProfBufferIO TheBufferIO
;
27 #define VP_BUFFER_SIZE 8 * 1024
28 static uint8_t BufferIOBuffer
[VP_BUFFER_SIZE
];
29 static InstrProfValueData VPDataArray
[16];
30 static uint32_t VPDataArraySize
= sizeof(VPDataArray
) / sizeof(*VPDataArray
);
32 COMPILER_RT_VISIBILITY
uint8_t *DynamicBufferIOBuffer
= 0;
33 COMPILER_RT_VISIBILITY
uint32_t VPBufferSize
= 0;
35 /* The buffer writer is responsible in keeping writer state
38 COMPILER_RT_VISIBILITY
uint32_t lprofBufferWriter(ProfDataWriter
*This
,
39 ProfDataIOVec
*IOVecs
,
42 char **Buffer
= (char **)&This
->WriterCtx
;
43 for (I
= 0; I
< NumIOVecs
; I
++) {
44 size_t Length
= IOVecs
[I
].ElmSize
* IOVecs
[I
].NumElm
;
46 memcpy(*Buffer
, IOVecs
[I
].Data
, Length
);
47 else if (IOVecs
[I
].UseZeroPadding
) {
48 /* Allocating the buffer should zero fill. */
55 static void llvmInitBufferIO(ProfBufferIO
*BufferIO
, ProfDataWriter
*FileWriter
,
56 uint8_t *Buffer
, uint32_t BufferSz
) {
57 BufferIO
->FileWriter
= FileWriter
;
58 BufferIO
->OwnFileWriter
= 0;
59 BufferIO
->BufferStart
= Buffer
;
60 BufferIO
->BufferSz
= BufferSz
;
61 BufferIO
->CurOffset
= 0;
64 COMPILER_RT_VISIBILITY ProfBufferIO
*
65 lprofCreateBufferIO(ProfDataWriter
*FileWriter
) {
66 uint8_t *Buffer
= DynamicBufferIOBuffer
;
67 uint32_t BufferSize
= VPBufferSize
;
69 Buffer
= &BufferIOBuffer
[0];
70 BufferSize
= sizeof(BufferIOBuffer
);
72 llvmInitBufferIO(&TheBufferIO
, FileWriter
, Buffer
, BufferSize
);
76 COMPILER_RT_VISIBILITY
void lprofDeleteBufferIO(ProfBufferIO
*BufferIO
) {
77 if (BufferIO
->OwnFileWriter
)
78 FreeHook(BufferIO
->FileWriter
);
79 if (DynamicBufferIOBuffer
) {
80 FreeHook(DynamicBufferIOBuffer
);
81 DynamicBufferIOBuffer
= 0;
86 COMPILER_RT_VISIBILITY
int
87 lprofBufferIOWrite(ProfBufferIO
*BufferIO
, const uint8_t *Data
, uint32_t Size
) {
88 /* Buffer is not large enough, it is time to flush. */
89 if (Size
+ BufferIO
->CurOffset
> BufferIO
->BufferSz
) {
90 if (lprofBufferIOFlush(BufferIO
) != 0)
93 /* Special case, bypass the buffer completely. */
94 ProfDataIOVec IO
[] = {{Data
, sizeof(uint8_t), Size
, 0}};
95 if (Size
> BufferIO
->BufferSz
) {
96 if (BufferIO
->FileWriter
->Write(BufferIO
->FileWriter
, IO
, 1))
99 /* Write the data to buffer */
100 uint8_t *Buffer
= BufferIO
->BufferStart
+ BufferIO
->CurOffset
;
101 ProfDataWriter BufferWriter
;
102 initBufferWriter(&BufferWriter
, (char *)Buffer
);
103 lprofBufferWriter(&BufferWriter
, IO
, 1);
104 BufferIO
->CurOffset
=
105 (uint8_t *)BufferWriter
.WriterCtx
- BufferIO
->BufferStart
;
110 COMPILER_RT_VISIBILITY
int lprofBufferIOFlush(ProfBufferIO
*BufferIO
) {
111 if (BufferIO
->CurOffset
) {
112 ProfDataIOVec IO
[] = {
113 {BufferIO
->BufferStart
, sizeof(uint8_t), BufferIO
->CurOffset
, 0}};
114 if (BufferIO
->FileWriter
->Write(BufferIO
->FileWriter
, IO
, 1))
116 BufferIO
->CurOffset
= 0;
121 /* Write out value profile data for function specified with \c Data.
122 * The implementation does not use the method \c serializeValueProfData
123 * which depends on dynamic memory allocation. In this implementation,
124 * value profile data is written out to \c BufferIO piecemeal.
126 static int writeOneValueProfData(ProfBufferIO
*BufferIO
,
127 VPDataReaderType
*VPDataReader
,
128 const __llvm_profile_data
*Data
) {
129 unsigned I
, NumValueKinds
= 0;
130 ValueProfData VPHeader
;
131 uint8_t *SiteCountArray
[IPVK_Last
+ 1];
133 for (I
= 0; I
<= IPVK_Last
; I
++) {
134 if (!Data
->NumValueSites
[I
])
135 SiteCountArray
[I
] = 0;
138 VPDataReader
->GetValueProfRecordHeaderSize(Data
->NumValueSites
[I
]) -
139 offsetof(ValueProfRecord
, SiteCountArray
);
140 /* Only use alloca for this small byte array to avoid excessive
142 SiteCountArray
[I
] = (uint8_t *)COMPILER_RT_ALLOCA(Sz
);
143 memset(SiteCountArray
[I
], 0, Sz
);
147 /* If NumValueKinds returned is 0, there is nothing to write, report
148 success and return. This should match the raw profile reader's behavior. */
149 if (!(NumValueKinds
= VPDataReader
->InitRTRecord(Data
, SiteCountArray
)))
152 /* First write the header structure. */
153 VPHeader
.TotalSize
= VPDataReader
->GetValueProfDataSize();
154 VPHeader
.NumValueKinds
= NumValueKinds
;
155 if (lprofBufferIOWrite(BufferIO
, (const uint8_t *)&VPHeader
,
156 sizeof(ValueProfData
)))
159 /* Make sure nothing else needs to be written before value profile
161 if ((void *)VPDataReader
->GetFirstValueProfRecord(&VPHeader
) !=
162 (void *)(&VPHeader
+ 1))
165 /* Write out the value profile record for each value kind
167 for (I
= 0; I
<= IPVK_Last
; I
++) {
169 ValueProfRecord RecordHeader
;
170 /* The size of the value prof record header without counting the
171 * site count array .*/
172 uint32_t RecordHeaderSize
= offsetof(ValueProfRecord
, SiteCountArray
);
173 uint32_t SiteCountArraySize
;
175 if (!Data
->NumValueSites
[I
])
178 /* Write out the record header. */
179 RecordHeader
.Kind
= I
;
180 RecordHeader
.NumValueSites
= Data
->NumValueSites
[I
];
181 if (lprofBufferIOWrite(BufferIO
, (const uint8_t *)&RecordHeader
,
185 /* Write out the site value count array including padding space. */
187 VPDataReader
->GetValueProfRecordHeaderSize(Data
->NumValueSites
[I
]) -
189 if (lprofBufferIOWrite(BufferIO
, SiteCountArray
[I
], SiteCountArraySize
))
192 /* Write out the value profile data for each value site. */
193 for (J
= 0; J
< Data
->NumValueSites
[I
]; J
++) {
194 uint32_t NRead
, NRemain
;
195 ValueProfNode
*NextStartNode
= 0;
196 NRemain
= VPDataReader
->GetNumValueDataForSite(I
, J
);
199 /* Read and write out value data in small chunks till it is done. */
201 NRead
= (NRemain
> VPDataArraySize
? VPDataArraySize
: NRemain
);
203 VPDataReader
->GetValueData(I
, /* ValueKind */
205 &VPDataArray
[0], NextStartNode
, NRead
);
206 if (lprofBufferIOWrite(BufferIO
, (const uint8_t *)&VPDataArray
[0],
207 NRead
* sizeof(InstrProfValueData
)))
210 } while (NRemain
!= 0);
213 /* All done report success. */
217 static int writeValueProfData(ProfDataWriter
*Writer
,
218 VPDataReaderType
*VPDataReader
,
219 const __llvm_profile_data
*DataBegin
,
220 const __llvm_profile_data
*DataEnd
) {
221 ProfBufferIO
*BufferIO
;
222 const __llvm_profile_data
*DI
= 0;
227 BufferIO
= lprofCreateBufferIO(Writer
);
229 for (DI
= DataBegin
; DI
< DataEnd
; DI
++) {
230 if (writeOneValueProfData(BufferIO
, VPDataReader
, DI
))
234 if (lprofBufferIOFlush(BufferIO
) != 0)
236 lprofDeleteBufferIO(BufferIO
);
241 COMPILER_RT_VISIBILITY
int lprofWriteData(ProfDataWriter
*Writer
,
242 VPDataReaderType
*VPDataReader
,
243 int SkipNameDataWrite
) {
244 /* Match logic in __llvm_profile_write_buffer(). */
245 const __llvm_profile_data
*DataBegin
= __llvm_profile_begin_data();
246 const __llvm_profile_data
*DataEnd
= __llvm_profile_end_data();
247 const char *CountersBegin
= __llvm_profile_begin_counters();
248 const char *CountersEnd
= __llvm_profile_end_counters();
249 const char *BitmapBegin
= __llvm_profile_begin_bitmap();
250 const char *BitmapEnd
= __llvm_profile_end_bitmap();
251 const char *NamesBegin
= __llvm_profile_begin_names();
252 const char *NamesEnd
= __llvm_profile_end_names();
253 const VTableProfData
*VTableBegin
= __llvm_profile_begin_vtables();
254 const VTableProfData
*VTableEnd
= __llvm_profile_end_vtables();
255 const char *VNamesBegin
= __llvm_profile_begin_vtabnames();
256 const char *VNamesEnd
= __llvm_profile_end_vtabnames();
257 return lprofWriteDataImpl(Writer
, DataBegin
, DataEnd
, CountersBegin
,
258 CountersEnd
, BitmapBegin
, BitmapEnd
, VPDataReader
,
259 NamesBegin
, NamesEnd
, VTableBegin
, VTableEnd
,
260 VNamesBegin
, VNamesEnd
, SkipNameDataWrite
);
263 COMPILER_RT_VISIBILITY
int
264 lprofWriteDataImpl(ProfDataWriter
*Writer
, const __llvm_profile_data
*DataBegin
,
265 const __llvm_profile_data
*DataEnd
,
266 const char *CountersBegin
, const char *CountersEnd
,
267 const char *BitmapBegin
, const char *BitmapEnd
,
268 VPDataReaderType
*VPDataReader
, const char *NamesBegin
,
269 const char *NamesEnd
, const VTableProfData
*VTableBegin
,
270 const VTableProfData
*VTableEnd
, const char *VNamesBegin
,
271 const char *VNamesEnd
, int SkipNameDataWrite
) {
272 /* Calculate size of sections. */
273 const uint64_t DataSectionSize
=
274 __llvm_profile_get_data_size(DataBegin
, DataEnd
);
275 const uint64_t NumData
= __llvm_profile_get_num_data(DataBegin
, DataEnd
);
276 const uint64_t CountersSectionSize
=
277 __llvm_profile_get_counters_size(CountersBegin
, CountersEnd
);
278 const uint64_t NumCounters
=
279 __llvm_profile_get_num_counters(CountersBegin
, CountersEnd
);
280 const uint64_t NumBitmapBytes
=
281 __llvm_profile_get_num_bitmap_bytes(BitmapBegin
, BitmapEnd
);
282 const uint64_t NamesSize
= __llvm_profile_get_name_size(NamesBegin
, NamesEnd
);
283 const uint64_t NumVTables
=
284 __llvm_profile_get_num_vtable(VTableBegin
, VTableEnd
);
285 const uint64_t VTableSectionSize
=
286 __llvm_profile_get_vtable_section_size(VTableBegin
, VTableEnd
);
287 const uint64_t VNamesSize
=
288 __llvm_profile_get_name_size(VNamesBegin
, VNamesEnd
);
290 /* Create the header. */
291 __llvm_profile_header Header
;
293 /* Determine how much padding is needed before/after the counters and after
295 uint64_t PaddingBytesBeforeCounters
, PaddingBytesAfterCounters
,
296 PaddingBytesAfterBitmapBytes
, PaddingBytesAfterNames
,
297 PaddingBytesAfterVTable
, PaddingBytesAfterVNames
;
298 if (__llvm_profile_get_padding_sizes_for_counters(
299 DataSectionSize
, CountersSectionSize
, NumBitmapBytes
, NamesSize
,
300 VTableSectionSize
, VNamesSize
, &PaddingBytesBeforeCounters
,
301 &PaddingBytesAfterCounters
, &PaddingBytesAfterBitmapBytes
,
302 &PaddingBytesAfterNames
, &PaddingBytesAfterVTable
,
303 &PaddingBytesAfterVNames
) == -1)
307 /* Initialize header structure. */
308 #define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init;
309 #include "profile/InstrProfData.inc"
312 /* On WIN64, label differences are truncated 32-bit values. Truncate
313 * CountersDelta to match. */
315 Header
.CountersDelta
= (uint32_t)Header
.CountersDelta
;
316 Header
.BitmapDelta
= (uint32_t)Header
.BitmapDelta
;
319 /* The data and names sections are omitted in lightweight mode. */
320 if (NumData
== 0 && NamesSize
== 0) {
321 Header
.CountersDelta
= 0;
322 Header
.NamesDelta
= 0;
325 /* Write the profile header. */
326 ProfDataIOVec IOVec
[] = {{&Header
, sizeof(__llvm_profile_header
), 1, 0}};
327 if (Writer
->Write(Writer
, IOVec
, sizeof(IOVec
) / sizeof(*IOVec
)))
330 /* Write the binary id lengths and data. */
331 if (__llvm_write_binary_ids(Writer
) == -1)
334 /* Write the profile data. */
335 ProfDataIOVec IOVecData
[] = {
336 {DataBegin
, sizeof(uint8_t), DataSectionSize
, 0},
337 {NULL
, sizeof(uint8_t), PaddingBytesBeforeCounters
, 1},
338 {CountersBegin
, sizeof(uint8_t), CountersSectionSize
, 0},
339 {NULL
, sizeof(uint8_t), PaddingBytesAfterCounters
, 1},
340 {BitmapBegin
, sizeof(uint8_t), NumBitmapBytes
, 0},
341 {NULL
, sizeof(uint8_t), PaddingBytesAfterBitmapBytes
, 1},
342 {SkipNameDataWrite
? NULL
: NamesBegin
, sizeof(uint8_t), NamesSize
, 0},
343 {NULL
, sizeof(uint8_t), PaddingBytesAfterNames
, 1},
344 {VTableBegin
, sizeof(uint8_t), VTableSectionSize
, 0},
345 {NULL
, sizeof(uint8_t), PaddingBytesAfterVTable
, 1},
346 {SkipNameDataWrite
? NULL
: VNamesBegin
, sizeof(uint8_t), VNamesSize
, 0},
347 {NULL
, sizeof(uint8_t), PaddingBytesAfterVNames
, 1}};
348 if (Writer
->Write(Writer
, IOVecData
, sizeof(IOVecData
) / sizeof(*IOVecData
)))
351 /* Value profiling is not yet supported in continuous mode and profile
352 * correlation mode. */
353 if (__llvm_profile_is_continuous_mode_enabled() ||
354 (NumData
== 0 && NamesSize
== 0))
357 return writeValueProfData(Writer
, VPDataReader
, DataBegin
, DataEnd
);
361 * Write binary id length and then its data, because binary id does not
362 * have a fixed length.
364 COMPILER_RT_VISIBILITY
365 int lprofWriteOneBinaryId(ProfDataWriter
*Writer
, uint64_t BinaryIdLen
,
366 const uint8_t *BinaryIdData
,
367 uint64_t BinaryIdPadding
) {
368 ProfDataIOVec BinaryIdIOVec
[] = {
369 {&BinaryIdLen
, sizeof(uint64_t), 1, 0},
370 {BinaryIdData
, sizeof(uint8_t), BinaryIdLen
, 0},
371 {NULL
, sizeof(uint8_t), BinaryIdPadding
, 1},
373 if (Writer
->Write(Writer
, BinaryIdIOVec
,
374 sizeof(BinaryIdIOVec
) / sizeof(*BinaryIdIOVec
)))
377 /* Successfully wrote binary id, report success. */