InstrProfilingBuffer.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*===- InstrProfilingBuffer.c - Write instrumentation to a memory buffer --===*\
  2. |*
  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
  6. |*
  7. \*===----------------------------------------------------------------------===*/
  8. // Note: This is linked into the Darwin kernel, and must remain compatible
  9. // with freestanding compilation. See `darwin_add_builtin_libraries`.
  10. #include "InstrProfiling.h"
  11. #include "InstrProfilingInternal.h"
  12. #include "InstrProfilingPort.h"
  13. /* When continuous mode is enabled (%c), this parameter is set to 1.
  14. *
  15. * This parameter is defined here in InstrProfilingBuffer.o, instead of in
  16. * InstrProfilingFile.o, to sequester all libc-dependent code in
  17. * InstrProfilingFile.o. The test `instrprof-without-libc` will break if this
  18. * layering is violated. */
  19. static int ContinuouslySyncProfile = 0;
  20. /* The system page size. Only valid when non-zero. If 0, the page size is
  21. * unavailable. */
  22. static unsigned PageSize = 0;
  23. COMPILER_RT_VISIBILITY int __llvm_profile_is_continuous_mode_enabled(void) {
  24. return ContinuouslySyncProfile && PageSize;
  25. }
  26. COMPILER_RT_VISIBILITY void __llvm_profile_enable_continuous_mode(void) {
  27. ContinuouslySyncProfile = 1;
  28. }
  29. COMPILER_RT_VISIBILITY void __llvm_profile_set_page_size(unsigned PS) {
  30. PageSize = PS;
  31. }
  32. COMPILER_RT_VISIBILITY
  33. uint64_t __llvm_profile_get_size_for_buffer(void) {
  34. const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
  35. const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
  36. const char *CountersBegin = __llvm_profile_begin_counters();
  37. const char *CountersEnd = __llvm_profile_end_counters();
  38. const char *NamesBegin = __llvm_profile_begin_names();
  39. const char *NamesEnd = __llvm_profile_end_names();
  40. return __llvm_profile_get_size_for_buffer_internal(
  41. DataBegin, DataEnd, CountersBegin, CountersEnd, NamesBegin, NamesEnd);
  42. }
  43. COMPILER_RT_VISIBILITY
  44. uint64_t __llvm_profile_get_num_data(const __llvm_profile_data *Begin,
  45. const __llvm_profile_data *End) {
  46. intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End;
  47. return ((EndI + sizeof(__llvm_profile_data) - 1) - BeginI) /
  48. sizeof(__llvm_profile_data);
  49. }
  50. COMPILER_RT_VISIBILITY
  51. uint64_t __llvm_profile_get_data_size(const __llvm_profile_data *Begin,
  52. const __llvm_profile_data *End) {
  53. return __llvm_profile_get_num_data(Begin, End) * sizeof(__llvm_profile_data);
  54. }
  55. COMPILER_RT_VISIBILITY size_t __llvm_profile_counter_entry_size(void) {
  56. if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE)
  57. return sizeof(uint8_t);
  58. return sizeof(uint64_t);
  59. }
  60. COMPILER_RT_VISIBILITY
  61. uint64_t __llvm_profile_get_num_counters(const char *Begin, const char *End) {
  62. intptr_t BeginI = (intptr_t)Begin, EndI = (intptr_t)End;
  63. return ((EndI + __llvm_profile_counter_entry_size() - 1) - BeginI) /
  64. __llvm_profile_counter_entry_size();
  65. }
  66. COMPILER_RT_VISIBILITY
  67. uint64_t __llvm_profile_get_counters_size(const char *Begin, const char *End) {
  68. return __llvm_profile_get_num_counters(Begin, End) *
  69. __llvm_profile_counter_entry_size();
  70. }
  71. /// Calculate the number of padding bytes needed to add to \p Offset in order
  72. /// for (\p Offset + Padding) to be page-aligned.
  73. static uint64_t calculateBytesNeededToPageAlign(uint64_t Offset) {
  74. uint64_t OffsetModPage = Offset % PageSize;
  75. if (OffsetModPage > 0)
  76. return PageSize - OffsetModPage;
  77. return 0;
  78. }
  79. static int needsCounterPadding(void) {
  80. #if defined(__APPLE__)
  81. return __llvm_profile_is_continuous_mode_enabled();
  82. #else
  83. return 0;
  84. #endif
  85. }
  86. COMPILER_RT_VISIBILITY
  87. void __llvm_profile_get_padding_sizes_for_counters(
  88. uint64_t DataSize, uint64_t CountersSize, uint64_t NamesSize,
  89. uint64_t *PaddingBytesBeforeCounters, uint64_t *PaddingBytesAfterCounters,
  90. uint64_t *PaddingBytesAfterNames) {
  91. if (!needsCounterPadding()) {
  92. *PaddingBytesBeforeCounters = 0;
  93. *PaddingBytesAfterCounters = 0;
  94. *PaddingBytesAfterNames = __llvm_profile_get_num_padding_bytes(NamesSize);
  95. return;
  96. }
  97. // In continuous mode, the file offsets for headers and for the start of
  98. // counter sections need to be page-aligned.
  99. *PaddingBytesBeforeCounters =
  100. calculateBytesNeededToPageAlign(sizeof(__llvm_profile_header) + DataSize);
  101. *PaddingBytesAfterCounters = calculateBytesNeededToPageAlign(CountersSize);
  102. *PaddingBytesAfterNames = calculateBytesNeededToPageAlign(NamesSize);
  103. }
  104. COMPILER_RT_VISIBILITY
  105. uint64_t __llvm_profile_get_size_for_buffer_internal(
  106. const __llvm_profile_data *DataBegin, const __llvm_profile_data *DataEnd,
  107. const char *CountersBegin, const char *CountersEnd, const char *NamesBegin,
  108. const char *NamesEnd) {
  109. /* Match logic in __llvm_profile_write_buffer(). */
  110. const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
  111. uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
  112. uint64_t CountersSize =
  113. __llvm_profile_get_counters_size(CountersBegin, CountersEnd);
  114. /* Determine how much padding is needed before/after the counters and after
  115. * the names. */
  116. uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
  117. PaddingBytesAfterNames;
  118. __llvm_profile_get_padding_sizes_for_counters(
  119. DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters,
  120. &PaddingBytesAfterCounters, &PaddingBytesAfterNames);
  121. return sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) +
  122. DataSize + PaddingBytesBeforeCounters + CountersSize +
  123. PaddingBytesAfterCounters + NamesSize + PaddingBytesAfterNames;
  124. }
  125. COMPILER_RT_VISIBILITY
  126. void initBufferWriter(ProfDataWriter *BufferWriter, char *Buffer) {
  127. BufferWriter->Write = lprofBufferWriter;
  128. BufferWriter->WriterCtx = Buffer;
  129. }
  130. COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer(char *Buffer) {
  131. ProfDataWriter BufferWriter;
  132. initBufferWriter(&BufferWriter, Buffer);
  133. return lprofWriteData(&BufferWriter, 0, 0);
  134. }
  135. COMPILER_RT_VISIBILITY int __llvm_profile_write_buffer_internal(
  136. char *Buffer, const __llvm_profile_data *DataBegin,
  137. const __llvm_profile_data *DataEnd, const char *CountersBegin,
  138. const char *CountersEnd, const char *NamesBegin, const char *NamesEnd) {
  139. ProfDataWriter BufferWriter;
  140. initBufferWriter(&BufferWriter, Buffer);
  141. return lprofWriteDataImpl(&BufferWriter, DataBegin, DataEnd, CountersBegin,
  142. CountersEnd, 0, NamesBegin, NamesEnd, 0);
  143. }