InstrProfilingMerge.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  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() {
  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. /* Returns 1 if profile is not structurally compatible. */
  36. COMPILER_RT_VISIBILITY
  37. int __llvm_profile_check_compatibility(const char *ProfileData,
  38. uint64_t ProfileSize) {
  39. /* Check profile header only for now */
  40. __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
  41. __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
  42. SrcDataStart =
  43. (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) +
  44. Header->BinaryIdsSize);
  45. SrcDataEnd = SrcDataStart + Header->DataSize;
  46. if (ProfileSize < sizeof(__llvm_profile_header))
  47. return 1;
  48. /* Check the header first. */
  49. if (Header->Magic != __llvm_profile_get_magic() ||
  50. Header->Version != __llvm_profile_get_version() ||
  51. Header->DataSize !=
  52. __llvm_profile_get_num_data(__llvm_profile_begin_data(),
  53. __llvm_profile_end_data()) ||
  54. Header->CountersSize !=
  55. __llvm_profile_get_num_counters(__llvm_profile_begin_counters(),
  56. __llvm_profile_end_counters()) ||
  57. Header->NamesSize != (uint64_t)(__llvm_profile_end_names() -
  58. __llvm_profile_begin_names()) ||
  59. Header->ValueKindLast != IPVK_Last)
  60. return 1;
  61. if (ProfileSize <
  62. sizeof(__llvm_profile_header) + Header->BinaryIdsSize +
  63. Header->DataSize * sizeof(__llvm_profile_data) + Header->NamesSize +
  64. Header->CountersSize * __llvm_profile_counter_entry_size())
  65. return 1;
  66. for (SrcData = SrcDataStart,
  67. DstData = (__llvm_profile_data *)__llvm_profile_begin_data();
  68. SrcData < SrcDataEnd; ++SrcData, ++DstData) {
  69. if (SrcData->NameRef != DstData->NameRef ||
  70. SrcData->FuncHash != DstData->FuncHash ||
  71. SrcData->NumCounters != DstData->NumCounters)
  72. return 1;
  73. }
  74. /* Matched! */
  75. return 0;
  76. }
  77. static uintptr_t signextIfWin64(void *V) {
  78. #ifdef _WIN64
  79. return (uintptr_t)(int32_t)(uintptr_t)V;
  80. #else
  81. return (uintptr_t)V;
  82. #endif
  83. }
  84. COMPILER_RT_VISIBILITY
  85. int __llvm_profile_merge_from_buffer(const char *ProfileData,
  86. uint64_t ProfileSize) {
  87. if (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) {
  88. PROF_ERR(
  89. "%s\n",
  90. "Debug info correlation does not support profile merging at runtime. "
  91. "Instead, merge raw profiles using the llvm-profdata tool.");
  92. return 1;
  93. }
  94. __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData;
  95. __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData;
  96. char *SrcCountersStart;
  97. const char *SrcNameStart;
  98. const char *SrcValueProfDataStart, *SrcValueProfData;
  99. uintptr_t CountersDelta = Header->CountersDelta;
  100. SrcDataStart =
  101. (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header) +
  102. Header->BinaryIdsSize);
  103. SrcDataEnd = SrcDataStart + Header->DataSize;
  104. SrcCountersStart = (char *)SrcDataEnd;
  105. SrcNameStart = SrcCountersStart +
  106. Header->CountersSize * __llvm_profile_counter_entry_size();
  107. SrcValueProfDataStart =
  108. SrcNameStart + Header->NamesSize +
  109. __llvm_profile_get_num_padding_bytes(Header->NamesSize);
  110. if (SrcNameStart < SrcCountersStart)
  111. return 1;
  112. for (SrcData = SrcDataStart,
  113. DstData = (__llvm_profile_data *)__llvm_profile_begin_data(),
  114. SrcValueProfData = SrcValueProfDataStart;
  115. SrcData < SrcDataEnd; ++SrcData, ++DstData) {
  116. // For the in-memory destination, CounterPtr is the distance from the start
  117. // address of the data to the start address of the counter. On WIN64,
  118. // CounterPtr is a truncated 32-bit value due to COFF limitation. Sign
  119. // extend CounterPtr to get the original value.
  120. char *DstCounters =
  121. (char *)((uintptr_t)DstData + signextIfWin64(DstData->CounterPtr));
  122. unsigned NVK = 0;
  123. // SrcData is a serialized representation of the memory image. We need to
  124. // compute the in-buffer counter offset from the in-memory address distance.
  125. // The initial CountersDelta is the in-memory address difference
  126. // start(__llvm_prf_cnts)-start(__llvm_prf_data), so SrcData->CounterPtr -
  127. // CountersDelta computes the offset into the in-buffer counter section.
  128. //
  129. // On WIN64, CountersDelta is truncated as well, so no need for signext.
  130. char *SrcCounters =
  131. SrcCountersStart + ((uintptr_t)SrcData->CounterPtr - CountersDelta);
  132. // CountersDelta needs to be decreased as we advance to the next data
  133. // record.
  134. CountersDelta -= sizeof(*SrcData);
  135. unsigned NC = SrcData->NumCounters;
  136. if (NC == 0)
  137. return 1;
  138. if (SrcCounters < SrcCountersStart || SrcCounters >= SrcNameStart ||
  139. (SrcCounters + __llvm_profile_counter_entry_size() * NC) > SrcNameStart)
  140. return 1;
  141. for (unsigned I = 0; I < NC; I++) {
  142. if (__llvm_profile_get_version() & VARIANT_MASK_BYTE_COVERAGE) {
  143. // A value of zero signifies the function is covered.
  144. DstCounters[I] &= SrcCounters[I];
  145. } else {
  146. ((uint64_t *)DstCounters)[I] += ((uint64_t *)SrcCounters)[I];
  147. }
  148. }
  149. /* Now merge value profile data. */
  150. if (!VPMergeHook)
  151. continue;
  152. for (unsigned I = 0; I <= IPVK_Last; I++)
  153. NVK += (SrcData->NumValueSites[I] != 0);
  154. if (!NVK)
  155. continue;
  156. if (SrcValueProfData >= ProfileData + ProfileSize)
  157. return 1;
  158. VPMergeHook((ValueProfData *)SrcValueProfData, DstData);
  159. SrcValueProfData =
  160. SrcValueProfData + ((ValueProfData *)SrcValueProfData)->TotalSize;
  161. }
  162. return 0;
  163. }