InstrProfilingMerge.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. /*===- InstrProfilingMerge.c - Profile in-process Merging ---------------===*\
  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. |* This file defines the API needed for in-process merging of profile data
  9. |* stored in memory buffer.
  10. \*===---------------------------------------------------------------------===*/
  11. #include "InstrProfiling.h"
  12. #include "InstrProfilingInternal.h"
  13. #include "InstrProfilingUtil.h"
  14. #define INSTR_PROF_VALUE_PROF_DATA
  15. #include "profile/InstrProfData.inc"
  16. COMPILER_RT_VISIBILITY
  17. void (*VPMergeHook)(ValueProfData *, __llvm_profile_data *);
  18. COMPILER_RT_VISIBILITY
  19. uint64_t lprofGetLoadModuleSignature(void) {
  20. /* A very fast way to compute a module signature. */
  21. uint64_t Version = __llvm_profile_get_version();
  22. uint64_t NumCounters = __llvm_profile_get_num_counters(
  23. __llvm_profile_begin_counters(), __llvm_profile_end_counters());
  24. uint64_t NumData = __llvm_profile_get_num_data(__llvm_profile_begin_data(),
  25. __llvm_profile_end_data());
  26. uint64_t NamesSize =
  27. (uint64_t)(__llvm_profile_end_names() - __llvm_profile_begin_names());
  28. uint64_t NumVnodes =
  29. (uint64_t)(__llvm_profile_end_vnodes() - __llvm_profile_begin_vnodes());
  30. const __llvm_profile_data *FirstD = __llvm_profile_begin_data();
  31. return (NamesSize << 40) + (NumCounters << 30) + (NumData << 20) +
  32. (NumVnodes << 10) + (NumData > 0 ? FirstD->NameRef : 0) + Version +
  33. __llvm_profile_get_magic();
  34. }
  35. #ifdef __GNUC__
  36. #pragma GCC diagnostic push
  37. #pragma GCC diagnostic ignored "-Wcast-qual"
  38. #elif defined(__clang__)
  39. #pragma clang diagnostic push
  40. #pragma clang diagnostic ignored "-Wcast-qual"
  41. #endif
  42. /* Returns 1 if profile is not structurally compatible. */
  43. COMPILER_RT_VISIBILITY
  44. int __llvm_profile_check_compatibility(const char *ProfileData,
  45. uint64_t ProfileSize) {
  46. __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
  47. __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
  48. SrcDataStart =
  49. (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) +
  50. Header->BinaryIdsSize);
  51. SrcDataEnd = SrcDataStart + Header->NumData;
  52. if (ProfileSize < sizeof(__llvm_profile_header))
  53. return 1;
  54. /* Check the header first. */
  55. if (Header->Magic != __llvm_profile_get_magic() ||
  56. Header->Version != __llvm_profile_get_version() ||
  57. Header->NumData !=
  58. __llvm_profile_get_num_data(__llvm_profile_begin_data(),
  59. __llvm_profile_end_data()) ||
  60. Header->NumCounters !=
  61. __llvm_profile_get_num_counters(__llvm_profile_begin_counters(),
  62. __llvm_profile_end_counters()) ||
  63. Header->NumBitmapBytes !=
  64. __llvm_profile_get_num_bitmap_bytes(__llvm_profile_begin_bitmap(),
  65. __llvm_profile_end_bitmap()) ||
  66. Header->NamesSize !=
  67. __llvm_profile_get_name_size(__llvm_profile_begin_names(),
  68. __llvm_profile_end_names()) ||
  69. Header->ValueKindLast != IPVK_Last)
  70. return 1;
  71. if (ProfileSize <
  72. sizeof(__llvm_profile_header) + Header->BinaryIdsSize +
  73. Header->NumData * sizeof(__llvm_profile_data) + Header->NamesSize +
  74. Header->NumCounters * __llvm_profile_counter_entry_size() +
  75. Header->NumBitmapBytes)
  76. return 1;
  77. for (SrcData = SrcDataStart,
  78. DstData = (__llvm_profile_data *)__llvm_profile_begin_data();
  79. SrcData < SrcDataEnd; ++SrcData, ++DstData) {
  80. if (SrcData->NameRef != DstData->NameRef ||
  81. SrcData->FuncHash != DstData->FuncHash ||
  82. SrcData->NumCounters != DstData->NumCounters ||
  83. SrcData->NumBitmapBytes != DstData->NumBitmapBytes)
  84. return 1;
  85. }
  86. /* Matched! */
  87. return 0;
  88. }
  89. static uintptr_t signextIfWin64(void *V) {
  90. #ifdef _WIN64
  91. return (uintptr_t)(int32_t)(uintptr_t)V;
  92. #else
  93. return (uintptr_t)V;
  94. #endif
  95. }
  96. COMPILER_RT_VISIBILITY
  97. int __llvm_profile_merge_from_buffer(const char *ProfileData,
  98. uint64_t ProfileSize) {
  99. if (__llvm_profile_get_version() & VARIANT_MASK_TEMPORAL_PROF) {
  100. PROF_ERR("%s\n",
  101. "Temporal profiles do not support profile merging at runtime. "
  102. "Instead, merge raw profiles using the llvm-profdata tool.");
  103. return 1;
  104. }
  105. __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
  106. __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
  107. char *SrcCountersStart, *DstCounter;
  108. const char *SrcCountersEnd, *SrcCounter;
  109. const char *SrcBitmapStart;
  110. const char *SrcNameStart;
  111. const char *SrcValueProfDataStart, *SrcValueProfData;
  112. uintptr_t CountersDelta = Header->CountersDelta;
  113. uintptr_t BitmapDelta = Header->BitmapDelta;
  114. SrcDataStart =
  115. (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) +
  116. Header->BinaryIdsSize);
  117. SrcDataEnd = SrcDataStart + Header->NumData;
  118. SrcCountersStart = (char *)SrcDataEnd;
  119. SrcCountersEnd = SrcCountersStart +
  120. Header->NumCounters * __llvm_profile_counter_entry_size();
  121. SrcBitmapStart = SrcCountersEnd;
  122. SrcNameStart = SrcBitmapStart + Header->NumBitmapBytes;
  123. SrcValueProfDataStart =
  124. SrcNameStart + Header->NamesSize +
  125. __llvm_profile_get_num_padding_bytes(Header->NamesSize);
  126. if (SrcNameStart < SrcCountersStart || SrcNameStart < SrcBitmapStart)
  127. return 1;
  128. // Merge counters by iterating the entire counter section when data section is
  129. // empty due to correlation.
  130. if (Header->NumData == 0) {
  131. for (SrcCounter = SrcCountersStart,
  132. DstCounter = __llvm_profile_begin_counters();
  133. SrcCounter < SrcCountersEnd;) {
  134. if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) {
  135. *DstCounter &= *SrcCounter;
  136. } else {
  137. *(uint64_t *)DstCounter += *(uint64_t *)SrcCounter;
  138. }
  139. SrcCounter += __llvm_profile_counter_entry_size();
  140. DstCounter += __llvm_profile_counter_entry_size();
  141. }
  142. return 0;
  143. }
  144. for (SrcData = SrcDataStart,
  145. DstData = (__llvm_profile_data *)__llvm_profile_begin_data(),
  146. SrcValueProfData = SrcValueProfDataStart;
  147. SrcData < SrcDataEnd; ++SrcData, ++DstData) {
  148. // For the in-memory destination, CounterPtr is the distance from the start
  149. // address of the data to the start address of the counter. On WIN64,
  150. // CounterPtr is a truncated 32-bit value due to COFF limitation. Sign
  151. // extend CounterPtr to get the original value.
  152. char *DstCounters =
  153. (char *)((uintptr_t)DstData + signextIfWin64(DstData->CounterPtr));
  154. char *DstBitmap =
  155. (char *)((uintptr_t)DstData + signextIfWin64(DstData->BitmapPtr));
  156. unsigned NVK = 0;
  157. // SrcData is a serialized representation of the memory image. We need to
  158. // compute the in-buffer counter offset from the in-memory address distance.
  159. // The initial CountersDelta is the in-memory address difference
  160. // start(__llvm_prf_cnts)-start(__llvm_prf_data), so SrcData->CounterPtr -
  161. // CountersDelta computes the offset into the in-buffer counter section.
  162. //
  163. // On WIN64, CountersDelta is truncated as well, so no need for signext.
  164. char *SrcCounters =
  165. SrcCountersStart + ((uintptr_t)SrcData->CounterPtr - CountersDelta);
  166. // CountersDelta needs to be decreased as we advance to the next data
  167. // record.
  168. CountersDelta -= sizeof(*SrcData);
  169. unsigned NC = SrcData->NumCounters;
  170. if (NC == 0)
  171. return 1;
  172. if (SrcCounters < SrcCountersStart || SrcCounters >= SrcNameStart ||
  173. (SrcCounters + __llvm_profile_counter_entry_size() * NC) > SrcNameStart)
  174. return 1;
  175. for (unsigned I = 0; I < NC; I++) {
  176. if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) {
  177. // A value of zero signifies the function is covered.
  178. DstCounters[I] &= SrcCounters[I];
  179. } else {
  180. ((uint64_t *)DstCounters)[I] += ((uint64_t *)SrcCounters)[I];
  181. }
  182. }
  183. const char *SrcBitmap =
  184. SrcBitmapStart + ((uintptr_t)SrcData->BitmapPtr - BitmapDelta);
  185. // BitmapDelta also needs to be decreased as we advance to the next data
  186. // record.
  187. BitmapDelta -= sizeof(*SrcData);
  188. unsigned NB = SrcData->NumBitmapBytes;
  189. // NumBitmapBytes may legitimately be 0. Just keep going.
  190. if (NB != 0) {
  191. if (SrcBitmap < SrcBitmapStart || (SrcBitmap + NB) > SrcNameStart)
  192. return 1;
  193. // Merge Src and Dst Bitmap bytes by simply ORing them together.
  194. for (unsigned I = 0; I < NB; I++)
  195. DstBitmap[I] |= SrcBitmap[I];
  196. }
  197. /* Now merge value profile data. */
  198. if (!VPMergeHook)
  199. continue;
  200. for (unsigned I = 0; I <= IPVK_Last; I++)
  201. NVK += (SrcData->NumValueSites[I] != 0);
  202. if (!NVK)
  203. continue;
  204. if (SrcValueProfData >= ProfileData + ProfileSize)
  205. return 1;
  206. VPMergeHook((ValueProfData *)SrcValueProfData, DstData);
  207. SrcValueProfData =
  208. SrcValueProfData + ((ValueProfData *)SrcValueProfData)->TotalSize;
  209. }
  210. return 0;
  211. }
  212. #ifdef __GNUC__
  213. #pragma GCC diagnostic pop
  214. #elif defined(__clang__)
  215. #pragma clang diagnostic pop
  216. #endif