xref: /openbsd-src/gnu/llvm/compiler-rt/lib/profile/InstrProfilingBuffer.c (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick /*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\
23cab2bb3Spatrick |*
33cab2bb3Spatrick |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick |* See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick |*
73cab2bb3Spatrick \*===----------------------------------------------------------------------===*/
83cab2bb3Spatrick 
9d89ec533Spatrick // Note: This is linked into the Darwin kernel, and must remain compatible
10d89ec533Spatrick // with freestanding compilation. See `darwin_add_builtin_libraries`.
11d89ec533Spatrick 
123cab2bb3Spatrick #include "InstrProfiling.h"
133cab2bb3Spatrick #include "InstrProfilingInternal.h"
143cab2bb3Spatrick #include "InstrProfilingPort.h"
153cab2bb3Spatrick 
163cab2bb3Spatrick /* When continuous mode is enabled (%c), this parameter is set to 1.
173cab2bb3Spatrick  *
183cab2bb3Spatrick  * This parameter is defined here in InstrProfilingBuffer.o, instead of in
193cab2bb3Spatrick  * InstrProfilingFile.o, to sequester all libc-dependent code in
203cab2bb3Spatrick  * InstrProfilingFile.o. The test `instrprof-without-libc` will break if this
213cab2bb3Spatrick  * layering is violated. */
223cab2bb3Spatrick static int ContinuouslySyncProfile = 0;
233cab2bb3Spatrick 
24d89ec533Spatrick /* The system page size. Only valid when non-zero. If 0, the page size is
25d89ec533Spatrick  * unavailable. */
26d89ec533Spatrick static unsigned PageSize = 0;
27d89ec533Spatrick 
__llvm_profile_is_continuous_mode_enabled(void)283cab2bb3Spatrick COMPILER_RT_VISIBILITY int __llvm_profile_is_continuous_mode_enabled(void) {
29d89ec533Spatrick   return ContinuouslySyncProfile && PageSize;
303cab2bb3Spatrick }
313cab2bb3Spatrick 
__llvm_profile_enable_continuous_mode(void)323cab2bb3Spatrick COMPILER_RT_VISIBILITY void __llvm_profile_enable_continuous_mode(void) {
333cab2bb3Spatrick   ContinuouslySyncProfile = 1;
343cab2bb3Spatrick }
353cab2bb3Spatrick 
__llvm_profile_set_page_size(unsigned PS)36d89ec533Spatrick COMPILER_RT_VISIBILITY void __llvm_profile_set_page_size(unsigned PS) {
37d89ec533Spatrick   PageSize = PS;
38d89ec533Spatrick }
39d89ec533Spatrick 
403cab2bb3Spatrick COMPILER_RT_VISIBILITY
__llvm_profile_get_size_for_buffer(void)413cab2bb3Spatrick uint64_t __llvm_profile_get_size_for_buffer(void) {
423cab2bb3Spatrick   const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
433cab2bb3Spatrick   const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
44*810390e3Srobert   const char *CountersBegin = __llvm_profile_begin_counters();
45*810390e3Srobert   const char *CountersEnd = __llvm_profile_end_counters();
463cab2bb3Spatrick   const char *NamesBegin = __llvm_profile_begin_names();
473cab2bb3Spatrick   const char *NamesEnd = __llvm_profile_end_names();
483cab2bb3Spatrick 
493cab2bb3Spatrick   return __llvm_profile_get_size_for_buffer_internal(
503cab2bb3Spatrick       DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
513cab2bb3Spatrick }
523cab2bb3Spatrick 
533cab2bb3Spatrick COMPILER_RT_VISIBILITY
__llvm_profile_get_num_data(const __llvm_profile_data * Begin,const __llvm_profile_data * End)54*810390e3Srobert uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin,
553cab2bb3Spatrick                                      const __llvm_profile_data *End) {
563cab2bb3Spatrick   intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End;
573cab2bb3Spatrick   return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) /
583cab2bb3Spatrick          sizeof(__llvm_profile_data);
593cab2bb3Spatrick }
603cab2bb3Spatrick 
61*810390e3Srobert COMPILER_RT_VISIBILITY
__llvm_profile_get_data_size(const __llvm_profile_data * Begin,const __llvm_profile_data * End)62*810390e3Srobert uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
63*810390e3Srobert                                       const __llvm_profile_data *End) {
64*810390e3Srobert   return __llvm_profile_get_num_data(Begin, End) * sizeof(__llvm_profile_data);
65*810390e3Srobert }
66*810390e3Srobert 
__llvm_profile_counter_entry_size(void)67*810390e3Srobert COMPILER_RT_VISIBILITY size_t __llvm_profile_counter_entry_size(void) {
68*810390e3Srobert   if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE)
69*810390e3Srobert     return sizeof(uint8_t);
70*810390e3Srobert   return sizeof(uint64_t);
71*810390e3Srobert }
72*810390e3Srobert 
73*810390e3Srobert COMPILER_RT_VISIBILITY
__llvm_profile_get_num_counters(const char * Begin,const char * End)74*810390e3Srobert uint64_t __llvm_profile_get_num_counters(const char *Begin, const char *End) {
75*810390e3Srobert   intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End;
76*810390e3Srobert   return ((EndI + __llvm_profile_counter_entry_size() - 1) - BeginI) /
77*810390e3Srobert          __llvm_profile_counter_entry_size();
78*810390e3Srobert }
79*810390e3Srobert 
80*810390e3Srobert COMPILER_RT_VISIBILITY
__llvm_profile_get_counters_size(const char * Begin,const char * End)81*810390e3Srobert uint64_t __llvm_profile_get_counters_size(const char *Begin, const char *End) {
82*810390e3Srobert   return __llvm_profile_get_num_counters(Begin, End) *
83*810390e3Srobert          __llvm_profile_counter_entry_size();
84*810390e3Srobert }
85*810390e3Srobert 
863cab2bb3Spatrick /// Calculate the number of padding bytes needed to add to \p Offset in order
873cab2bb3Spatrick /// for (\p Offset + Padding) to be page-aligned.
calculateBytesNeededToPageAlign(uint64_t Offset)88d89ec533Spatrick static uint64_t calculateBytesNeededToPageAlign(uint64_t Offset) {
893cab2bb3Spatrick   uint64_t OffsetModPage = Offset % PageSize;
903cab2bb3Spatrick   if (OffsetModPage > 0)
913cab2bb3Spatrick     return PageSize - OffsetModPage;
923cab2bb3Spatrick   return 0;
933cab2bb3Spatrick }
943cab2bb3Spatrick 
needsCounterPadding(void)95d89ec533Spatrick static int needsCounterPadding(void) {
96d89ec533Spatrick #if defined(__APPLE__)
97d89ec533Spatrick   return __llvm_profile_is_continuous_mode_enabled();
98d89ec533Spatrick #else
99d89ec533Spatrick   return 0;
100d89ec533Spatrick #endif
101d89ec533Spatrick }
102d89ec533Spatrick 
1033cab2bb3Spatrick COMPILER_RT_VISIBILITY
__llvm_profile_get_padding_sizes_for_counters(uint64_t DataSize,uint64_t CountersSize,uint64_t NamesSize,uint64_t * PaddingBytesBeforeCounters,uint64_t * PaddingBytesAfterCounters,uint64_t * PaddingBytesAfterNames)1043cab2bb3Spatrick void __llvm_profile_get_padding_sizes_for_counters(
1053cab2bb3Spatrick     uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
1063cab2bb3Spatrick     uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
1073cab2bb3Spatrick     uint64_t *PaddingBytesAfterNames) {
108d89ec533Spatrick   if (!needsCounterPadding()) {
1093cab2bb3Spatrick     *PaddingBytesBeforeCounters = 0;
1103cab2bb3Spatrick     *PaddingBytesAfterCounters = 0;
1113cab2bb3Spatrick     *PaddingBytesAfterNames = __llvm_profile_get_num_padding_bytes(NamesSize);
1123cab2bb3Spatrick     return;
1133cab2bb3Spatrick   }
1143cab2bb3Spatrick 
1153cab2bb3Spatrick   // In continuous mode, the file offsets for headers and for the start of
1163cab2bb3Spatrick   // counter sections need to be page-aligned.
117*810390e3Srobert   *PaddingBytesBeforeCounters =
118*810390e3Srobert       calculateBytesNeededToPageAlign(sizeof(__llvm_profile_header) + DataSize);
119*810390e3Srobert   *PaddingBytesAfterCounters = calculateBytesNeededToPageAlign(CountersSize);
120d89ec533Spatrick   *PaddingBytesAfterNames = calculateBytesNeededToPageAlign(NamesSize);
1213cab2bb3Spatrick }
1223cab2bb3Spatrick 
1233cab2bb3Spatrick COMPILER_RT_VISIBILITY
__llvm_profile_get_size_for_buffer_internal(const __llvm_profile_data * DataBegin,const __llvm_profile_data * DataEnd,const char * CountersBegin,const char * CountersEnd,const char * NamesBegin,const char * NamesEnd)1243cab2bb3Spatrick uint64_t __llvm_profile_get_size_for_buffer_internal(
1253cab2bb3Spatrick     const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
126*810390e3Srobert     const char *CountersBegin, const char *CountersEnd, const char *NamesBegin,
127*810390e3Srobert     const char *NamesEnd) {
1283cab2bb3Spatrick   /* Match logic in __llvm_profile_write_buffer(). */
1293cab2bb3Spatrick   const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
1303cab2bb3Spatrick   uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
131*810390e3Srobert   uint64_t CountersSize =
132*810390e3Srobert       __llvm_profile_get_counters_size(CountersBegin, CountersEnd);
1333cab2bb3Spatrick 
1343cab2bb3Spatrick   /* Determine how much padding is needed before/after the counters and after
1353cab2bb3Spatrick    * the names. */
1363cab2bb3Spatrick   uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
1373cab2bb3Spatrick       PaddingBytesAfterNames;
1383cab2bb3Spatrick   __llvm_profile_get_padding_sizes_for_counters(
1393cab2bb3Spatrick       DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
1403cab2bb3Spatrick       &PaddingBytesAfterCounters, &PaddingBytesAfterNames);
1413cab2bb3Spatrick 
142d89ec533Spatrick   return sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
143*810390e3Srobert          DataSize + PaddingBytesBeforeCounters + CountersSize +
144*810390e3Srobert          PaddingBytesAfterCounters + NamesSize + PaddingBytesAfterNames;
1453cab2bb3Spatrick }
1463cab2bb3Spatrick 
1473cab2bb3Spatrick COMPILER_RT_VISIBILITY
initBufferWriter(ProfDataWriter * BufferWriter,char * Buffer)1483cab2bb3Spatrick void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer) {
1493cab2bb3Spatrick   BufferWriter->Write = lprofBufferWriter;
1503cab2bb3Spatrick   BufferWriter->WriterCtx = Buffer;
1513cab2bb3Spatrick }
1523cab2bb3Spatrick 
__llvm_profile_write_buffer(char * Buffer)1533cab2bb3Spatrick COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) {
1543cab2bb3Spatrick   ProfDataWriter BufferWriter;
1553cab2bb3Spatrick   initBufferWriter(&BufferWriter, Buffer);
1563cab2bb3Spatrick   return lprofWriteData(&BufferWriter, 0, 0);
1573cab2bb3Spatrick }
1583cab2bb3Spatrick 
__llvm_profile_write_buffer_internal(char * Buffer,const __llvm_profile_data * DataBegin,const __llvm_profile_data * DataEnd,const char * CountersBegin,const char * CountersEnd,const char * NamesBegin,const char * NamesEnd)1593cab2bb3Spatrick COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
1603cab2bb3Spatrick     char *Buffer, const __llvm_profile_data *DataBegin,
161*810390e3Srobert     const __llvm_profile_data *DataEnd, const char *CountersBegin,
162*810390e3Srobert     const char *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
1633cab2bb3Spatrick   ProfDataWriter BufferWriter;
1643cab2bb3Spatrick   initBufferWriter(&BufferWriter, Buffer);
1653cab2bb3Spatrick   return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin,
1663cab2bb3Spatrick                             CountersEnd, 0, NamesBegin, NamesEnd, 0);
1673cab2bb3Spatrick }
168