InstrProfilingWriter.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*===- InstrProfilingWriter.c - Write instrumentation to a file or 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. #ifdef _MSC_VER
  11. /* For _alloca */
  12. #include <malloc.h>
  13. #endif
  14. #include <string.h>
  15. #include "InstrProfiling.h"
  16. #include "InstrProfilingInternal.h"
  17. #include "InstrProfilingPort.h"
  18. #define INSTR_PROF_VALUE_PROF_DATA
  19. #include "profile/InstrProfData.inc"
  20. COMPILER_RT_VISIBILITY void (*FreeHook)(void *) = NULL;
  21. static ProfBufferIO TheBufferIO;
  22. #define VP_BUFFER_SIZE 8 * 1024
  23. static uint8_t BufferIOBuffer[VP_BUFFER_SIZE];
  24. static InstrProfValueData VPDataArray[16];
  25. static uint32_t VPDataArraySize = sizeof(VPDataArray) / sizeof(*VPDataArray);
  26. COMPILER_RT_VISIBILITY uint8_t *DynamicBufferIOBuffer = 0;
  27. COMPILER_RT_VISIBILITY uint32_t VPBufferSize = 0;
  28. /* The buffer writer is responsible in keeping writer state
  29. * across the call.
  30. */
  31. COMPILER_RT_VISIBILITY uint32_t lprofBufferWriter(ProfDataWriter *This,
  32. ProfDataIOVec *IOVecs,
  33. uint32_t NumIOVecs) {
  34. uint32_t I;
  35. char **Buffer = (char **)&This->WriterCtx;
  36. for (I = 0; I < NumIOVecs; I++) {
  37. size_t Length = IOVecs[I].ElmSize * IOVecs[I].NumElm;
  38. if (IOVecs[I].Data)
  39. memcpy(*Buffer, IOVecs[I].Data, Length);
  40. else if (IOVecs[I].UseZeroPadding) {
  41. /* Allocating the buffer should zero fill. */
  42. }
  43. *Buffer += Length;
  44. }
  45. return 0;
  46. }
  47. static void llvmInitBufferIO(ProfBufferIO *BufferIO, ProfDataWriter *FileWriter,
  48. uint8_t *Buffer, uint32_t BufferSz) {
  49. BufferIO->FileWriter = FileWriter;
  50. BufferIO->OwnFileWriter = 0;
  51. BufferIO->BufferStart = Buffer;
  52. BufferIO->BufferSz = BufferSz;
  53. BufferIO->CurOffset = 0;
  54. }
  55. COMPILER_RT_VISIBILITY ProfBufferIO *
  56. lprofCreateBufferIO(ProfDataWriter *FileWriter) {
  57. uint8_t *Buffer = DynamicBufferIOBuffer;
  58. uint32_t BufferSize = VPBufferSize;
  59. if (!Buffer) {
  60. Buffer = &BufferIOBuffer[0];
  61. BufferSize = sizeof(BufferIOBuffer);
  62. }
  63. llvmInitBufferIO(&TheBufferIO, FileWriter, Buffer, BufferSize);
  64. return &TheBufferIO;
  65. }
  66. COMPILER_RT_VISIBILITY void lprofDeleteBufferIO(ProfBufferIO *BufferIO) {
  67. if (BufferIO->OwnFileWriter)
  68. FreeHook(BufferIO->FileWriter);
  69. if (DynamicBufferIOBuffer) {
  70. FreeHook(DynamicBufferIOBuffer);
  71. DynamicBufferIOBuffer = 0;
  72. VPBufferSize = 0;
  73. }
  74. }
  75. COMPILER_RT_VISIBILITY int
  76. lprofBufferIOWrite(ProfBufferIO *BufferIO, const uint8_t *Data, uint32_t Size) {
  77. /* Buffer is not large enough, it is time to flush. */
  78. if (Size + BufferIO->CurOffset > BufferIO->BufferSz) {
  79. if (lprofBufferIOFlush(BufferIO) != 0)
  80. return -1;
  81. }
  82. /* Special case, bypass the buffer completely. */
  83. ProfDataIOVec IO[] = {{Data, sizeof(uint8_t), Size, 0}};
  84. if (Size > BufferIO->BufferSz) {
  85. if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))
  86. return -1;
  87. } else {
  88. /* Write the data to buffer */
  89. uint8_t *Buffer = BufferIO->BufferStart + BufferIO->CurOffset;
  90. ProfDataWriter BufferWriter;
  91. initBufferWriter(&BufferWriter, (char *)Buffer);
  92. lprofBufferWriter(&BufferWriter, IO, 1);
  93. BufferIO->CurOffset =
  94. (uint8_t *)BufferWriter.WriterCtx - BufferIO->BufferStart;
  95. }
  96. return 0;
  97. }
  98. COMPILER_RT_VISIBILITY int lprofBufferIOFlush(ProfBufferIO *BufferIO) {
  99. if (BufferIO->CurOffset) {
  100. ProfDataIOVec IO[] = {
  101. {BufferIO->BufferStart, sizeof(uint8_t), BufferIO->CurOffset, 0}};
  102. if (BufferIO->FileWriter->Write(BufferIO->FileWriter, IO, 1))
  103. return -1;
  104. BufferIO->CurOffset = 0;
  105. }
  106. return 0;
  107. }
  108. /* Write out value profile data for function specified with \c Data.
  109. * The implementation does not use the method \c serializeValueProfData
  110. * which depends on dynamic memory allocation. In this implementation,
  111. * value profile data is written out to \c BufferIO piecemeal.
  112. */
  113. static int writeOneValueProfData(ProfBufferIO *BufferIO,
  114. VPDataReaderType *VPDataReader,
  115. const __llvm_profile_data *Data) {
  116. unsigned I, NumValueKinds = 0;
  117. ValueProfData VPHeader;
  118. uint8_t *SiteCountArray[IPVK_Last + 1];
  119. for (I = 0; I <= IPVK_Last; I++) {
  120. if (!Data->NumValueSites[I])
  121. SiteCountArray[I] = 0;
  122. else {
  123. uint32_t Sz =
  124. VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) -
  125. offsetof(ValueProfRecord, SiteCountArray);
  126. /* Only use alloca for this small byte array to avoid excessive
  127. * stack growth. */
  128. SiteCountArray[I] = (uint8_t *)COMPILER_RT_ALLOCA(Sz);
  129. memset(SiteCountArray[I], 0, Sz);
  130. }
  131. }
  132. /* If NumValueKinds returned is 0, there is nothing to write, report
  133. success and return. This should match the raw profile reader's behavior. */
  134. if (!(NumValueKinds = VPDataReader->InitRTRecord(Data, SiteCountArray)))
  135. return 0;
  136. /* First write the header structure. */
  137. VPHeader.TotalSize = VPDataReader->GetValueProfDataSize();
  138. VPHeader.NumValueKinds = NumValueKinds;
  139. if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPHeader,
  140. sizeof(ValueProfData)))
  141. return -1;
  142. /* Make sure nothing else needs to be written before value profile
  143. * records. */
  144. if ((void *)VPDataReader->GetFirstValueProfRecord(&VPHeader) !=
  145. (void *)(&VPHeader + 1))
  146. return -1;
  147. /* Write out the value profile record for each value kind
  148. * one by one. */
  149. for (I = 0; I <= IPVK_Last; I++) {
  150. uint32_t J;
  151. ValueProfRecord RecordHeader;
  152. /* The size of the value prof record header without counting the
  153. * site count array .*/
  154. uint32_t RecordHeaderSize = offsetof(ValueProfRecord, SiteCountArray);
  155. uint32_t SiteCountArraySize;
  156. if (!Data->NumValueSites[I])
  157. continue;
  158. /* Write out the record header. */
  159. RecordHeader.Kind = I;
  160. RecordHeader.NumValueSites = Data->NumValueSites[I];
  161. if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&RecordHeader,
  162. RecordHeaderSize))
  163. return -1;
  164. /* Write out the site value count array including padding space. */
  165. SiteCountArraySize =
  166. VPDataReader->GetValueProfRecordHeaderSize(Data->NumValueSites[I]) -
  167. RecordHeaderSize;
  168. if (lprofBufferIOWrite(BufferIO, SiteCountArray[I], SiteCountArraySize))
  169. return -1;
  170. /* Write out the value profile data for each value site. */
  171. for (J = 0; J < Data->NumValueSites[I]; J++) {
  172. uint32_t NRead, NRemain;
  173. ValueProfNode *NextStartNode = 0;
  174. NRemain = VPDataReader->GetNumValueDataForSite(I, J);
  175. if (!NRemain)
  176. continue;
  177. /* Read and write out value data in small chunks till it is done. */
  178. do {
  179. NRead = (NRemain > VPDataArraySize ? VPDataArraySize : NRemain);
  180. NextStartNode =
  181. VPDataReader->GetValueData(I, /* ValueKind */
  182. J, /* Site */
  183. &VPDataArray[0], NextStartNode, NRead);
  184. if (lprofBufferIOWrite(BufferIO, (const uint8_t *)&VPDataArray[0],
  185. NRead * sizeof(InstrProfValueData)))
  186. return -1;
  187. NRemain -= NRead;
  188. } while (NRemain != 0);
  189. }
  190. }
  191. /* All done report success. */
  192. return 0;
  193. }
  194. static int writeValueProfData(ProfDataWriter *Writer,
  195. VPDataReaderType *VPDataReader,
  196. const __llvm_profile_data *DataBegin,
  197. const __llvm_profile_data *DataEnd) {
  198. ProfBufferIO *BufferIO;
  199. const __llvm_profile_data *DI = 0;
  200. if (!VPDataReader)
  201. return 0;
  202. BufferIO = lprofCreateBufferIO(Writer);
  203. for (DI = DataBegin; DI < DataEnd; DI++) {
  204. if (writeOneValueProfData(BufferIO, VPDataReader, DI))
  205. return -1;
  206. }
  207. if (lprofBufferIOFlush(BufferIO) != 0)
  208. return -1;
  209. lprofDeleteBufferIO(BufferIO);
  210. return 0;
  211. }
  212. COMPILER_RT_VISIBILITY int lprofWriteData(ProfDataWriter *Writer,
  213. VPDataReaderType *VPDataReader,
  214. int SkipNameDataWrite) {
  215. /* Match logic in __llvm_profile_write_buffer(). */
  216. const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
  217. const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
  218. const char *CountersBegin = __llvm_profile_begin_counters();
  219. const char *CountersEnd = __llvm_profile_end_counters();
  220. const char *NamesBegin = __llvm_profile_begin_names();
  221. const char *NamesEnd = __llvm_profile_end_names();
  222. return lprofWriteDataImpl(Writer, DataBegin, DataEnd, CountersBegin,
  223. CountersEnd, VPDataReader, NamesBegin, NamesEnd,
  224. SkipNameDataWrite);
  225. }
  226. COMPILER_RT_VISIBILITY int
  227. lprofWriteDataImpl(ProfDataWriter *Writer, const __llvm_profile_data *DataBegin,
  228. const __llvm_profile_data *DataEnd,
  229. const char *CountersBegin, const char *CountersEnd,
  230. VPDataReaderType *VPDataReader, const char *NamesBegin,
  231. const char *NamesEnd, int SkipNameDataWrite) {
  232. int DebugInfoCorrelate =
  233. (__llvm_profile_get_version() & VARIANT_MASK_DBG_CORRELATE) != 0ULL;
  234. /* Calculate size of sections. */
  235. const uint64_t DataSectionSize =
  236. DebugInfoCorrelate ? 0 : __llvm_profile_get_data_size(DataBegin, DataEnd);
  237. const uint64_t NumData =
  238. DebugInfoCorrelate ? 0 : __llvm_profile_get_num_data(DataBegin, DataEnd);
  239. const uint64_t CountersSectionSize =
  240. __llvm_profile_get_counters_size(CountersBegin, CountersEnd);
  241. const uint64_t NumCounters =
  242. __llvm_profile_get_num_counters(CountersBegin, CountersEnd);
  243. const uint64_t NamesSize = DebugInfoCorrelate ? 0 : NamesEnd - NamesBegin;
  244. /* Create the header. */
  245. __llvm_profile_header Header;
  246. /* Determine how much padding is needed before/after the counters and after
  247. * the names. */
  248. uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
  249. PaddingBytesAfterNames;
  250. __llvm_profile_get_padding_sizes_for_counters(
  251. DataSectionSize, CountersSectionSize, NamesSize,
  252. &PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
  253. &PaddingBytesAfterNames);
  254. {
  255. // TODO: Unfortunately the header's fields are named DataSize and
  256. // CountersSize when they should be named NumData and NumCounters,
  257. // respectively.
  258. const uint64_t CountersSize = NumCounters;
  259. const uint64_t DataSize = NumData;
  260. /* Initialize header structure. */
  261. #define INSTR_PROF_RAW_HEADER(Type, Name, Init) Header.Name = Init;
  262. #include "profile/InstrProfData.inc"
  263. }
  264. /* On WIN64, label differences are truncated 32-bit values. Truncate
  265. * CountersDelta to match. */
  266. #ifdef _WIN64
  267. Header.CountersDelta = (uint32_t)Header.CountersDelta;
  268. #endif
  269. /* The data and names sections are omitted in lightweight mode. */
  270. if (DebugInfoCorrelate) {
  271. Header.CountersDelta = 0;
  272. Header.NamesDelta = 0;
  273. }
  274. /* Write the profile header. */
  275. ProfDataIOVec IOVec[] = {{&Header, sizeof(__llvm_profile_header), 1, 0}};
  276. if (Writer->Write(Writer, IOVec, sizeof(IOVec) / sizeof(*IOVec)))
  277. return -1;
  278. /* Write the binary id lengths and data. */
  279. if (__llvm_write_binary_ids(Writer) == -1)
  280. return -1;
  281. /* Write the profile data. */
  282. ProfDataIOVec IOVecData[] = {
  283. {DebugInfoCorrelate ? NULL : DataBegin, sizeof(uint8_t), DataSectionSize,
  284. 0},
  285. {NULL, sizeof(uint8_t), PaddingBytesBeforeCounters, 1},
  286. {CountersBegin, sizeof(uint8_t), CountersSectionSize, 0},
  287. {NULL, sizeof(uint8_t), PaddingBytesAfterCounters, 1},
  288. {(SkipNameDataWrite || DebugInfoCorrelate) ? NULL : NamesBegin,
  289. sizeof(uint8_t), NamesSize, 0},
  290. {NULL, sizeof(uint8_t), PaddingBytesAfterNames, 1}};
  291. if (Writer->Write(Writer, IOVecData, sizeof(IOVecData) / sizeof(*IOVecData)))
  292. return -1;
  293. /* Value profiling is not yet supported in continuous mode. */
  294. if (__llvm_profile_is_continuous_mode_enabled())
  295. return 0;
  296. return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd);
  297. }