[flang][cuda] Adapt ExternalNameConversion to work in gpu module (#117039)
[llvm-project.git] / compiler-rt / lib / profile / InstrProfilingFile.c
blobbad4cc71801ec40bfd4b7568723b4bd98de10172
1 /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
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 \*===----------------------------------------------------------------------===*/
9 #if !defined(__Fuchsia__)
11 #include <assert.h>
12 #include <errno.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #ifdef _MSC_VER
17 /* For _alloca. */
18 #include <malloc.h>
19 #endif
20 #if defined(_WIN32)
21 #include "WindowsMMap.h"
22 /* For _chsize_s */
23 #include <io.h>
24 #include <process.h>
25 #else
26 #include <sys/file.h>
27 #include <sys/mman.h>
28 #include <unistd.h>
29 #if defined(__linux__)
30 #include <sys/types.h>
31 #endif
32 #endif
34 #include "InstrProfiling.h"
35 #include "InstrProfilingInternal.h"
36 #include "InstrProfilingPort.h"
37 #include "InstrProfilingUtil.h"
39 /* From where is profile name specified.
40 * The order the enumerators define their
41 * precedence. Re-order them may lead to
42 * runtime behavior change. */
43 typedef enum ProfileNameSpecifier {
44 PNS_unknown = 0,
45 PNS_default,
46 PNS_command_line,
47 PNS_environment,
48 PNS_runtime_api
49 } ProfileNameSpecifier;
51 static const char *getPNSStr(ProfileNameSpecifier PNS) {
52 switch (PNS) {
53 case PNS_default:
54 return "default setting";
55 case PNS_command_line:
56 return "command line";
57 case PNS_environment:
58 return "environment variable";
59 case PNS_runtime_api:
60 return "runtime API";
61 default:
62 return "Unknown";
66 #define MAX_PID_SIZE 16
67 /* Data structure holding the result of parsed filename pattern. */
68 typedef struct lprofFilename {
69 /* File name string possibly with %p or %h specifiers. */
70 const char *FilenamePat;
71 /* A flag indicating if FilenamePat's memory is allocated
72 * by runtime. */
73 unsigned OwnsFilenamePat;
74 const char *ProfilePathPrefix;
75 char PidChars[MAX_PID_SIZE];
76 char *TmpDir;
77 char Hostname[COMPILER_RT_MAX_HOSTLEN];
78 unsigned NumPids;
79 unsigned NumHosts;
80 /* When in-process merging is enabled, this parameter specifies
81 * the total number of profile data files shared by all the processes
82 * spawned from the same binary. By default the value is 1. If merging
83 * is not enabled, its value should be 0. This parameter is specified
84 * by the %[0-9]m specifier. For instance %2m enables merging using
85 * 2 profile data files. %1m is equivalent to %m. Also %m specifier
86 * can only appear once at the end of the name pattern. */
87 unsigned MergePoolSize;
88 ProfileNameSpecifier PNS;
89 } lprofFilename;
91 static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL,
92 {0}, 0, 0, 0, PNS_unknown};
94 static int ProfileMergeRequested = 0;
95 static int getProfileFileSizeForMerging(FILE *ProfileFile,
96 uint64_t *ProfileFileSize);
98 #if defined(__APPLE__)
99 static const int ContinuousModeSupported = 1;
100 static const int UseBiasVar = 0;
101 static const char *FileOpenMode = "a+b";
102 static void *BiasAddr = NULL;
103 static void *BiasDefaultAddr = NULL;
104 static void *BitmapBiasAddr = NULL;
105 static void *BitmapBiasDefaultAddr = NULL;
106 static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
107 /* Get the sizes of various profile data sections. Taken from
108 * __llvm_profile_get_size_for_buffer(). */
109 const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
110 const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
111 const char *CountersBegin = __llvm_profile_begin_counters();
112 const char *CountersEnd = __llvm_profile_end_counters();
113 const char *BitmapBegin = __llvm_profile_begin_bitmap();
114 const char *BitmapEnd = __llvm_profile_end_bitmap();
115 const char *NamesBegin = __llvm_profile_begin_names();
116 const char *NamesEnd = __llvm_profile_end_names();
117 const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
118 uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
119 uint64_t CountersSize =
120 __llvm_profile_get_counters_size(CountersBegin, CountersEnd);
121 uint64_t NumBitmapBytes =
122 __llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
124 /* Check that the counter, bitmap, and data sections in this image are
125 * page-aligned. */
126 unsigned PageSize = getpagesize();
127 if ((intptr_t)CountersBegin % PageSize != 0) {
128 PROF_ERR("Counters section not page-aligned (start = %p, pagesz = %u).\n",
129 CountersBegin, PageSize);
130 return 1;
132 if ((intptr_t)BitmapBegin % PageSize != 0) {
133 PROF_ERR("Bitmap section not page-aligned (start = %p, pagesz = %u).\n",
134 BitmapBegin, PageSize);
135 return 1;
137 if ((intptr_t)DataBegin % PageSize != 0) {
138 PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
139 DataBegin, PageSize);
140 return 1;
143 int Fileno = fileno(File);
144 /* Determine how much padding is needed before/after the counters and
145 * after the names. */
146 uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
147 PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes,
148 PaddingBytesAfterVTable, PaddingBytesAfterVNames;
149 __llvm_profile_get_padding_sizes_for_counters(
150 DataSize, CountersSize, NumBitmapBytes, NamesSize, /*VTableSize=*/0,
151 /*VNameSize=*/0, &PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
152 &PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames,
153 &PaddingBytesAfterVTable, &PaddingBytesAfterVNames);
155 uint64_t PageAlignedCountersLength = CountersSize + PaddingBytesAfterCounters;
156 uint64_t FileOffsetToCounters = CurrentFileOffset +
157 sizeof(__llvm_profile_header) + DataSize +
158 PaddingBytesBeforeCounters;
159 void *CounterMmap = mmap((void *)CountersBegin, PageAlignedCountersLength,
160 PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
161 Fileno, FileOffsetToCounters);
162 if (CounterMmap != CountersBegin) {
163 PROF_ERR(
164 "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
165 " - CountersBegin: %p\n"
166 " - PageAlignedCountersLength: %" PRIu64 "\n"
167 " - Fileno: %d\n"
168 " - FileOffsetToCounters: %" PRIu64 "\n",
169 strerror(errno), CountersBegin, PageAlignedCountersLength, Fileno,
170 FileOffsetToCounters);
171 return 1;
174 /* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()
175 * will fail with EINVAL. */
176 if (NumBitmapBytes == 0)
177 return 0;
179 uint64_t PageAlignedBitmapLength =
180 NumBitmapBytes + PaddingBytesAfterBitmapBytes;
181 uint64_t FileOffsetToBitmap =
182 FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters;
183 void *BitmapMmap =
184 mmap((void *)BitmapBegin, PageAlignedBitmapLength, PROT_READ | PROT_WRITE,
185 MAP_FIXED | MAP_SHARED, Fileno, FileOffsetToBitmap);
186 if (BitmapMmap != BitmapBegin) {
187 PROF_ERR(
188 "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
189 " - BitmapBegin: %p\n"
190 " - PageAlignedBitmapLength: %" PRIu64 "\n"
191 " - Fileno: %d\n"
192 " - FileOffsetToBitmap: %" PRIu64 "\n",
193 strerror(errno), BitmapBegin, PageAlignedBitmapLength, Fileno,
194 FileOffsetToBitmap);
195 return 1;
197 return 0;
199 #elif defined(__ELF__) || defined(_WIN32) || defined(_AIX)
201 #define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR \
202 INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR, _default)
203 COMPILER_RT_VISIBILITY int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR = 0;
204 #define INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR \
205 INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_BITMAP_BIAS_VAR, _default)
206 COMPILER_RT_VISIBILITY int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR = 0;
208 /* This variable is a weak external reference which could be used to detect
209 * whether or not the compiler defined this symbol. */
210 #if defined(_MSC_VER)
211 COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
212 COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR;
213 #if defined(_M_IX86) || defined(__i386__)
214 #define WIN_SYM_PREFIX "_"
215 #else
216 #define WIN_SYM_PREFIX
217 #endif
218 #pragma comment( \
219 linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \
220 INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \
221 INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))
222 #pragma comment( \
223 linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \
224 INSTR_PROF_PROFILE_BITMAP_BIAS_VAR) "=" WIN_SYM_PREFIX \
225 INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR))
226 #else
227 COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
228 __attribute__((weak, alias(INSTR_PROF_QUOTE(
229 INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))));
230 COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR
231 __attribute__((weak, alias(INSTR_PROF_QUOTE(
232 INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR))));
233 #endif
234 static const int ContinuousModeSupported = 1;
235 static const int UseBiasVar = 1;
236 /* TODO: If there are two DSOs, the second DSO initilization will truncate the
237 * first profile file. */
238 static const char *FileOpenMode = "w+b";
239 /* This symbol is defined by the compiler when runtime counter relocation is
240 * used and runtime provides a weak alias so we can check if it's defined. */
241 static void *BiasAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
242 static void *BiasDefaultAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR;
243 static void *BitmapBiasAddr = &INSTR_PROF_PROFILE_BITMAP_BIAS_VAR;
244 static void *BitmapBiasDefaultAddr =
245 &INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR;
246 static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
247 /* Get the sizes of various profile data sections. Taken from
248 * __llvm_profile_get_size_for_buffer(). */
249 const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
250 const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
251 const char *CountersBegin = __llvm_profile_begin_counters();
252 const char *CountersEnd = __llvm_profile_end_counters();
253 const char *BitmapBegin = __llvm_profile_begin_bitmap();
254 const char *BitmapEnd = __llvm_profile_end_bitmap();
255 uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
256 uint64_t CountersSize =
257 __llvm_profile_get_counters_size(CountersBegin, CountersEnd);
258 uint64_t NumBitmapBytes =
259 __llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
260 /* Get the file size. */
261 uint64_t FileSize = 0;
262 if (getProfileFileSizeForMerging(File, &FileSize))
263 return 1;
265 int Fileno = fileno(File);
266 uint64_t PaddingBytesAfterCounters =
267 __llvm_profile_get_num_padding_bytes(CountersSize);
268 uint64_t FileOffsetToCounters =
269 sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) + DataSize;
271 /* Map the profile. */
272 char *Profile = (char *)mmap(NULL, FileSize, PROT_READ | PROT_WRITE,
273 MAP_SHARED, Fileno, 0);
274 if (Profile == MAP_FAILED) {
275 PROF_ERR("Unable to mmap profile: %s\n", strerror(errno));
276 return 1;
278 /* Update the profile fields based on the current mapping. */
279 INSTR_PROF_PROFILE_COUNTER_BIAS_VAR =
280 (intptr_t)Profile - (uintptr_t)CountersBegin + FileOffsetToCounters;
282 /* Return the memory allocated for counters to OS. */
283 lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd);
285 /* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()
286 * will fail with EINVAL. */
287 if (NumBitmapBytes == 0)
288 return 0;
290 /* Update profbm_bias. */
291 uint64_t FileOffsetToBitmap =
292 FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters;
293 /* Update the profile fields based on the current mapping. */
294 INSTR_PROF_PROFILE_BITMAP_BIAS_VAR =
295 (uintptr_t)Profile - (uintptr_t)BitmapBegin + FileOffsetToBitmap;
297 /* Return the memory allocated for counters to OS. */
298 lprofReleaseMemoryPagesToOS((uintptr_t)BitmapBegin, (uintptr_t)BitmapEnd);
299 return 0;
301 #else
302 static const int ContinuousModeSupported = 0;
303 static const int UseBiasVar = 0;
304 static const char *FileOpenMode = "a+b";
305 static void *BiasAddr = NULL;
306 static void *BiasDefaultAddr = NULL;
307 static void *BitmapBiasAddr = NULL;
308 static void *BitmapBiasDefaultAddr = NULL;
309 static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
310 return 0;
312 #endif
314 static int isProfileMergeRequested(void) { return ProfileMergeRequested; }
315 static void setProfileMergeRequested(int EnableMerge) {
316 ProfileMergeRequested = EnableMerge;
319 static FILE *ProfileFile = NULL;
320 static FILE *getProfileFile(void) { return ProfileFile; }
321 static void setProfileFile(FILE *File) { ProfileFile = File; }
323 static int getCurFilenameLength(void);
324 static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf);
325 static unsigned doMerging(void) {
326 return lprofCurFilename.MergePoolSize || isProfileMergeRequested();
329 /* Return 1 if there is an error, otherwise return 0. */
330 static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
331 uint32_t NumIOVecs) {
332 uint32_t I;
333 FILE *File = (FILE *)This->WriterCtx;
334 char Zeroes[sizeof(uint64_t)] = {0};
335 for (I = 0; I < NumIOVecs; I++) {
336 if (IOVecs[I].Data) {
337 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
338 IOVecs[I].NumElm)
339 return 1;
340 } else if (IOVecs[I].UseZeroPadding) {
341 size_t BytesToWrite = IOVecs[I].ElmSize * IOVecs[I].NumElm;
342 while (BytesToWrite > 0) {
343 size_t PartialWriteLen =
344 (sizeof(uint64_t) > BytesToWrite) ? BytesToWrite : sizeof(uint64_t);
345 if (fwrite(Zeroes, sizeof(uint8_t), PartialWriteLen, File) !=
346 PartialWriteLen) {
347 return 1;
349 BytesToWrite -= PartialWriteLen;
351 } else {
352 if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1)
353 return 1;
356 return 0;
359 /* TODO: make buffer size controllable by an internal option, and compiler can pass the size
360 to runtime via a variable. */
361 static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) {
362 if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) !=
363 INSTR_ORDER_FILE_BUFFER_SIZE)
364 return 1;
365 return 0;
368 static void initFileWriter(ProfDataWriter *This, FILE *File) {
369 This->Write = fileWriter;
370 This->WriterCtx = File;
373 COMPILER_RT_VISIBILITY ProfBufferIO *
374 lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
375 FreeHook = &free;
376 DynamicBufferIOBuffer = (uint8_t *)calloc(1, BufferSz);
377 VPBufferSize = BufferSz;
378 ProfDataWriter *fileWriter =
379 (ProfDataWriter *)calloc(1, sizeof(ProfDataWriter));
380 initFileWriter(fileWriter, File);
381 ProfBufferIO *IO = lprofCreateBufferIO(fileWriter);
382 IO->OwnFileWriter = 1;
383 return IO;
386 static void setupIOBuffer(void) {
387 const char *BufferSzStr = 0;
388 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
389 if (BufferSzStr && BufferSzStr[0]) {
390 VPBufferSize = atoi(BufferSzStr);
391 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
395 /* Get the size of the profile file. If there are any errors, print the
396 * message under the assumption that the profile is being read for merging
397 * purposes, and return -1. Otherwise return the file size in the inout param
398 * \p ProfileFileSize. */
399 static int getProfileFileSizeForMerging(FILE *ProfileFile,
400 uint64_t *ProfileFileSize) {
401 if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
402 PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
403 strerror(errno));
404 return -1;
406 *ProfileFileSize = ftell(ProfileFile);
408 /* Restore file offset. */
409 if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
410 PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
411 strerror(errno));
412 return -1;
415 if (*ProfileFileSize > 0 &&
416 *ProfileFileSize < sizeof(__llvm_profile_header)) {
417 PROF_WARN("Unable to merge profile data: %s\n",
418 "source profile file is too small.");
419 return -1;
421 return 0;
424 /* mmap() \p ProfileFile for profile merging purposes, assuming that an
425 * exclusive lock is held on the file and that \p ProfileFileSize is the
426 * length of the file. Return the mmap'd buffer in the inout variable
427 * \p ProfileBuffer. Returns -1 on failure. On success, the caller is
428 * responsible for unmapping the mmap'd buffer in \p ProfileBuffer. */
429 static int mmapProfileForMerging(FILE *ProfileFile, uint64_t ProfileFileSize,
430 char **ProfileBuffer) {
431 *ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
432 fileno(ProfileFile), 0);
433 if (*ProfileBuffer == MAP_FAILED) {
434 PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
435 strerror(errno));
436 return -1;
439 if (__llvm_profile_check_compatibility(*ProfileBuffer, ProfileFileSize)) {
440 (void)munmap(*ProfileBuffer, ProfileFileSize);
441 PROF_WARN("Unable to merge profile data: %s\n",
442 "source profile file is not compatible.");
443 return -1;
445 return 0;
448 /* Read profile data in \c ProfileFile and merge with in-memory
449 profile counters. Returns -1 if there is fatal error, otheriwse
450 0 is returned. Returning 0 does not mean merge is actually
451 performed. If merge is actually done, *MergeDone is set to 1.
453 static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
454 uint64_t ProfileFileSize;
455 char *ProfileBuffer;
457 /* Get the size of the profile on disk. */
458 if (getProfileFileSizeForMerging(ProfileFile, &ProfileFileSize) == -1)
459 return -1;
461 /* Nothing to merge. */
462 if (!ProfileFileSize)
463 return 0;
465 /* mmap() the profile and check that it is compatible with the data in
466 * the current image. */
467 if (mmapProfileForMerging(ProfileFile, ProfileFileSize, &ProfileBuffer) == -1)
468 return -1;
470 /* Now start merging */
471 if (__llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize)) {
472 PROF_ERR("%s\n", "Invalid profile data to merge");
473 (void)munmap(ProfileBuffer, ProfileFileSize);
474 return -1;
477 // Truncate the file in case merging of value profile did not happen to
478 // prevent from leaving garbage data at the end of the profile file.
479 (void)COMPILER_RT_FTRUNCATE(ProfileFile,
480 __llvm_profile_get_size_for_buffer());
482 (void)munmap(ProfileBuffer, ProfileFileSize);
483 *MergeDone = 1;
485 return 0;
488 /* Create the directory holding the file, if needed. */
489 static void createProfileDir(const char *Filename) {
490 size_t Length = strlen(Filename);
491 if (lprofFindFirstDirSeparator(Filename)) {
492 char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
493 strncpy(Copy, Filename, Length + 1);
494 __llvm_profile_recursive_mkdir(Copy);
498 /* Open the profile data for merging. It opens the file in r+b mode with
499 * file locking. If the file has content which is compatible with the
500 * current process, it also reads in the profile data in the file and merge
501 * it with in-memory counters. After the profile data is merged in memory,
502 * the original profile data is truncated and gets ready for the profile
503 * dumper. With profile merging enabled, each executable as well as any of
504 * its instrumented shared libraries dump profile data into their own data file.
506 static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) {
507 FILE *ProfileFile = getProfileFile();
508 int rc;
509 // initializeProfileForContinuousMode will lock the profile, but if
510 // ProfileFile is set by user via __llvm_profile_set_file_object, it's assumed
511 // unlocked at this point.
512 if (ProfileFile && !__llvm_profile_is_continuous_mode_enabled()) {
513 lprofLockFileHandle(ProfileFile);
515 if (!ProfileFile) {
516 createProfileDir(ProfileFileName);
517 ProfileFile = lprofOpenFileEx(ProfileFileName);
519 if (!ProfileFile)
520 return NULL;
522 rc = doProfileMerging(ProfileFile, MergeDone);
523 if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) ||
524 fseek(ProfileFile, 0L, SEEK_SET) == -1) {
525 PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
526 strerror(errno));
527 fclose(ProfileFile);
528 return NULL;
530 return ProfileFile;
533 static FILE *getFileObject(const char *OutputName) {
534 FILE *File;
535 File = getProfileFile();
536 if (File != NULL) {
537 return File;
540 return fopen(OutputName, "ab");
543 /* Write profile data to file \c OutputName. */
544 static int writeFile(const char *OutputName) {
545 int RetVal;
546 FILE *OutputFile;
548 int MergeDone = 0;
549 VPMergeHook = &lprofMergeValueProfData;
550 if (doMerging())
551 OutputFile = openFileForMerging(OutputName, &MergeDone);
552 else
553 OutputFile = getFileObject(OutputName);
555 if (!OutputFile)
556 return -1;
558 FreeHook = &free;
559 setupIOBuffer();
560 ProfDataWriter fileWriter;
561 initFileWriter(&fileWriter, OutputFile);
562 RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);
564 if (OutputFile == getProfileFile()) {
565 fflush(OutputFile);
566 if (doMerging() && !__llvm_profile_is_continuous_mode_enabled()) {
567 lprofUnlockFileHandle(OutputFile);
569 } else {
570 fclose(OutputFile);
573 return RetVal;
576 /* Write order data to file \c OutputName. */
577 static int writeOrderFile(const char *OutputName) {
578 int RetVal;
579 FILE *OutputFile;
581 OutputFile = fopen(OutputName, "w");
583 if (!OutputFile) {
584 PROF_WARN("can't open file with mode ab: %s\n", OutputName);
585 return -1;
588 FreeHook = &free;
589 setupIOBuffer();
590 const uint32_t *DataBegin = __llvm_profile_begin_orderfile();
591 RetVal = orderFileWriter(OutputFile, DataBegin);
593 fclose(OutputFile);
594 return RetVal;
597 #define LPROF_INIT_ONCE_ENV "__LLVM_PROFILE_RT_INIT_ONCE"
599 static void truncateCurrentFile(void) {
600 const char *Filename;
601 char *FilenameBuf;
602 FILE *File;
603 int Length;
605 Length = getCurFilenameLength();
606 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
607 Filename = getCurFilename(FilenameBuf, 0);
608 if (!Filename)
609 return;
611 /* Only create the profile directory and truncate an existing profile once.
612 * In continuous mode, this is necessary, as the profile is written-to by the
613 * runtime initializer. */
614 int initialized = getenv(LPROF_INIT_ONCE_ENV) != NULL;
615 if (initialized)
616 return;
617 #if defined(_WIN32)
618 _putenv(LPROF_INIT_ONCE_ENV "=" LPROF_INIT_ONCE_ENV);
619 #else
620 setenv(LPROF_INIT_ONCE_ENV, LPROF_INIT_ONCE_ENV, 1);
621 #endif
623 /* Create the profile dir (even if online merging is enabled), so that
624 * the profile file can be set up if continuous mode is enabled. */
625 createProfileDir(Filename);
627 /* By pass file truncation to allow online raw profile merging. */
628 if (lprofCurFilename.MergePoolSize)
629 return;
631 /* Truncate the file. Later we'll reopen and append. */
632 File = fopen(Filename, "w");
633 if (!File)
634 return;
635 fclose(File);
638 /* Write a partial profile to \p Filename, which is required to be backed by
639 * the open file object \p File. */
640 static int writeProfileWithFileObject(const char *Filename, FILE *File) {
641 setProfileFile(File);
642 int rc = writeFile(Filename);
643 if (rc)
644 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
645 setProfileFile(NULL);
646 return rc;
649 static void initializeProfileForContinuousMode(void) {
650 if (!__llvm_profile_is_continuous_mode_enabled())
651 return;
652 if (!ContinuousModeSupported) {
653 PROF_ERR("%s\n", "continuous mode is unsupported on this platform");
654 return;
656 if (UseBiasVar && BiasAddr == BiasDefaultAddr &&
657 BitmapBiasAddr == BitmapBiasDefaultAddr) {
658 PROF_ERR("%s\n", "Neither __llvm_profile_counter_bias nor "
659 "__llvm_profile_bitmap_bias is defined");
660 return;
663 /* Get the sizes of counter section. */
664 uint64_t CountersSize = __llvm_profile_get_counters_size(
665 __llvm_profile_begin_counters(), __llvm_profile_end_counters());
667 int Length = getCurFilenameLength();
668 char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
669 const char *Filename = getCurFilename(FilenameBuf, 0);
670 if (!Filename)
671 return;
673 FILE *File = NULL;
674 uint64_t CurrentFileOffset = 0;
675 if (doMerging()) {
676 /* We are merging profiles. Map the counter section as shared memory into
677 * the profile, i.e. into each participating process. An increment in one
678 * process should be visible to every other process with the same counter
679 * section mapped. */
680 File = lprofOpenFileEx(Filename);
681 if (!File)
682 return;
684 uint64_t ProfileFileSize = 0;
685 if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {
686 lprofUnlockFileHandle(File);
687 fclose(File);
688 return;
690 if (ProfileFileSize == 0) {
691 /* Grow the profile so that mmap() can succeed. Leak the file handle, as
692 * the file should stay open. */
693 if (writeProfileWithFileObject(Filename, File) != 0) {
694 lprofUnlockFileHandle(File);
695 fclose(File);
696 return;
698 } else {
699 /* The merged profile has a non-zero length. Check that it is compatible
700 * with the data in this process. */
701 char *ProfileBuffer;
702 if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {
703 lprofUnlockFileHandle(File);
704 fclose(File);
705 return;
707 (void)munmap(ProfileBuffer, ProfileFileSize);
709 } else {
710 File = fopen(Filename, FileOpenMode);
711 if (!File)
712 return;
713 /* Check that the offset within the file is page-aligned. */
714 CurrentFileOffset = ftell(File);
715 unsigned PageSize = getpagesize();
716 if (CurrentFileOffset % PageSize != 0) {
717 PROF_ERR("Continuous counter sync mode is enabled, but raw profile is not"
718 "page-aligned. CurrentFileOffset = %" PRIu64 ", pagesz = %u.\n",
719 (uint64_t)CurrentFileOffset, PageSize);
720 fclose(File);
721 return;
723 if (writeProfileWithFileObject(Filename, File) != 0) {
724 fclose(File);
725 return;
729 /* mmap() the profile counters so long as there is at least one counter.
730 * If there aren't any counters, mmap() would fail with EINVAL. */
731 if (CountersSize > 0)
732 mmapForContinuousMode(CurrentFileOffset, File);
734 if (doMerging()) {
735 lprofUnlockFileHandle(File);
737 if (File != NULL) {
738 fclose(File);
742 static const char *DefaultProfileName = "default.profraw";
743 static void resetFilenameToDefault(void) {
744 if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
745 #ifdef __GNUC__
746 #pragma GCC diagnostic push
747 #pragma GCC diagnostic ignored "-Wcast-qual"
748 #elif defined(__clang__)
749 #pragma clang diagnostic push
750 #pragma clang diagnostic ignored "-Wcast-qual"
751 #endif
752 free((void *)lprofCurFilename.FilenamePat);
753 #ifdef __GNUC__
754 #pragma GCC diagnostic pop
755 #elif defined(__clang__)
756 #pragma clang diagnostic pop
757 #endif
759 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
760 lprofCurFilename.FilenamePat = DefaultProfileName;
761 lprofCurFilename.PNS = PNS_default;
764 static unsigned getMergePoolSize(const char *FilenamePat, int *I) {
765 unsigned J = 0, Num = 0;
766 for (;; ++J) {
767 char C = FilenamePat[*I + J];
768 if (C == 'm') {
769 *I += J;
770 return Num ? Num : 1;
772 if (C < '0' || C > '9')
773 break;
774 Num = Num * 10 + C - '0';
776 /* If FilenamePat[*I+J] is between '0' and '9', the next byte is guaranteed
777 * to be in-bound as the string is null terminated. */
779 return 0;
782 /* Assert that Idx does index past a string null terminator. Return the
783 * result of the check. */
784 static int checkBounds(int Idx, int Strlen) {
785 assert(Idx <= Strlen && "Indexing past string null terminator");
786 return Idx <= Strlen;
789 /* Parses the pattern string \p FilenamePat and stores the result to
790 * lprofcurFilename structure. */
791 static int parseFilenamePattern(const char *FilenamePat,
792 unsigned CopyFilenamePat) {
793 int NumPids = 0, NumHosts = 0, I;
794 char *PidChars = &lprofCurFilename.PidChars[0];
795 char *Hostname = &lprofCurFilename.Hostname[0];
796 int MergingEnabled = 0;
797 int FilenamePatLen = strlen(FilenamePat);
799 #ifdef __GNUC__
800 #pragma GCC diagnostic push
801 #pragma GCC diagnostic ignored "-Wcast-qual"
802 #elif defined(__clang__)
803 #pragma clang diagnostic push
804 #pragma clang diagnostic ignored "-Wcast-qual"
805 #endif
806 /* Clean up cached prefix and filename. */
807 if (lprofCurFilename.ProfilePathPrefix)
808 free((void *)lprofCurFilename.ProfilePathPrefix);
810 if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
811 free((void *)lprofCurFilename.FilenamePat);
813 #ifdef __GNUC__
814 #pragma GCC diagnostic pop
815 #elif defined(__clang__)
816 #pragma clang diagnostic pop
817 #endif
819 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
821 if (!CopyFilenamePat)
822 lprofCurFilename.FilenamePat = FilenamePat;
823 else {
824 lprofCurFilename.FilenamePat = strdup(FilenamePat);
825 lprofCurFilename.OwnsFilenamePat = 1;
827 /* Check the filename for "%p", which indicates a pid-substitution. */
828 for (I = 0; checkBounds(I, FilenamePatLen) && FilenamePat[I]; ++I) {
829 if (FilenamePat[I] == '%') {
830 ++I; /* Advance to the next character. */
831 if (!checkBounds(I, FilenamePatLen))
832 break;
833 if (FilenamePat[I] == 'p') {
834 if (!NumPids++) {
835 if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) {
836 PROF_WARN("Unable to get pid for filename pattern %s. Using the "
837 "default name.",
838 FilenamePat);
839 return -1;
842 } else if (FilenamePat[I] == 'h') {
843 if (!NumHosts++)
844 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {
845 PROF_WARN("Unable to get hostname for filename pattern %s. Using "
846 "the default name.",
847 FilenamePat);
848 return -1;
850 } else if (FilenamePat[I] == 't') {
851 lprofCurFilename.TmpDir = getenv("TMPDIR");
852 if (!lprofCurFilename.TmpDir) {
853 PROF_WARN("Unable to get the TMPDIR environment variable, referenced "
854 "in %s. Using the default path.",
855 FilenamePat);
856 return -1;
858 } else if (FilenamePat[I] == 'c') {
859 if (__llvm_profile_is_continuous_mode_enabled()) {
860 PROF_WARN("%%c specifier can only be specified once in %s.\n",
861 FilenamePat);
862 __llvm_profile_disable_continuous_mode();
863 return -1;
865 #if defined(__APPLE__) || defined(__ELF__) || defined(_WIN32) || defined(_AIX)
866 __llvm_profile_set_page_size(getpagesize());
867 __llvm_profile_enable_continuous_mode();
868 #else
869 PROF_WARN("%s", "Continous mode is currently only supported for Mach-O,"
870 " ELF and COFF formats.");
871 return -1;
872 #endif
873 } else {
874 unsigned MergePoolSize = getMergePoolSize(FilenamePat, &I);
875 if (!MergePoolSize)
876 continue;
877 if (MergingEnabled) {
878 PROF_WARN("%%m specifier can only be specified once in %s.\n",
879 FilenamePat);
880 return -1;
882 MergingEnabled = 1;
883 lprofCurFilename.MergePoolSize = MergePoolSize;
888 lprofCurFilename.NumPids = NumPids;
889 lprofCurFilename.NumHosts = NumHosts;
890 return 0;
893 static void parseAndSetFilename(const char *FilenamePat,
894 ProfileNameSpecifier PNS,
895 unsigned CopyFilenamePat) {
897 const char *OldFilenamePat = lprofCurFilename.FilenamePat;
898 ProfileNameSpecifier OldPNS = lprofCurFilename.PNS;
900 /* The old profile name specifier takes precedence over the old one. */
901 if (PNS < OldPNS)
902 return;
904 if (!FilenamePat)
905 FilenamePat = DefaultProfileName;
907 if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) {
908 lprofCurFilename.PNS = PNS;
909 return;
912 /* When PNS >= OldPNS, the last one wins. */
913 if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat))
914 resetFilenameToDefault();
915 lprofCurFilename.PNS = PNS;
917 if (!OldFilenamePat) {
918 if (getenv("LLVM_PROFILE_VERBOSE"))
919 PROF_NOTE("Set profile file path to \"%s\" via %s.\n",
920 lprofCurFilename.FilenamePat, getPNSStr(PNS));
921 } else {
922 if (getenv("LLVM_PROFILE_VERBOSE"))
923 PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",
924 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat,
925 getPNSStr(PNS));
928 truncateCurrentFile();
929 if (__llvm_profile_is_continuous_mode_enabled())
930 initializeProfileForContinuousMode();
933 /* Return buffer length that is required to store the current profile
934 * filename with PID and hostname substitutions. */
935 /* The length to hold uint64_t followed by 3 digits pool id including '_' */
936 #define SIGLEN 24
937 static int getCurFilenameLength(void) {
938 int Len;
939 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
940 return 0;
942 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
943 lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize))
944 return strlen(lprofCurFilename.FilenamePat);
946 Len = strlen(lprofCurFilename.FilenamePat) +
947 lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
948 lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2) +
949 (lprofCurFilename.TmpDir ? (strlen(lprofCurFilename.TmpDir) - 1) : 0);
950 if (lprofCurFilename.MergePoolSize)
951 Len += SIGLEN;
952 return Len;
955 /* Return the pointer to the current profile file name (after substituting
956 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
957 * to store the resulting filename. If no substitution is needed, the
958 * current filename pattern string is directly returned, unless ForceUseBuf
959 * is enabled. */
960 static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {
961 int I, J, PidLength, HostNameLength, TmpDirLength, FilenamePatLength;
962 const char *FilenamePat = lprofCurFilename.FilenamePat;
964 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
965 return 0;
967 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
968 lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize ||
969 __llvm_profile_is_continuous_mode_enabled())) {
970 if (!ForceUseBuf)
971 return lprofCurFilename.FilenamePat;
973 FilenamePatLength = strlen(lprofCurFilename.FilenamePat);
974 memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength);
975 FilenameBuf[FilenamePatLength] = '\0';
976 return FilenameBuf;
979 PidLength = strlen(lprofCurFilename.PidChars);
980 HostNameLength = strlen(lprofCurFilename.Hostname);
981 TmpDirLength = lprofCurFilename.TmpDir ? strlen(lprofCurFilename.TmpDir) : 0;
982 /* Construct the new filename. */
983 for (I = 0, J = 0; FilenamePat[I]; ++I)
984 if (FilenamePat[I] == '%') {
985 if (FilenamePat[++I] == 'p') {
986 memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength);
987 J += PidLength;
988 } else if (FilenamePat[I] == 'h') {
989 memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
990 J += HostNameLength;
991 } else if (FilenamePat[I] == 't') {
992 memcpy(FilenameBuf + J, lprofCurFilename.TmpDir, TmpDirLength);
993 FilenameBuf[J + TmpDirLength] = DIR_SEPARATOR;
994 J += TmpDirLength + 1;
995 } else {
996 if (!getMergePoolSize(FilenamePat, &I))
997 continue;
998 char LoadModuleSignature[SIGLEN + 1];
999 int S;
1000 int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize;
1001 S = snprintf(LoadModuleSignature, SIGLEN + 1, "%" PRIu64 "_%d",
1002 lprofGetLoadModuleSignature(), ProfilePoolId);
1003 if (S == -1 || S > SIGLEN)
1004 S = SIGLEN;
1005 memcpy(FilenameBuf + J, LoadModuleSignature, S);
1006 J += S;
1008 /* Drop any unknown substitutions. */
1009 } else
1010 FilenameBuf[J++] = FilenamePat[I];
1011 FilenameBuf[J] = 0;
1013 return FilenameBuf;
1016 /* Returns the pointer to the environment variable
1017 * string. Returns null if the env var is not set. */
1018 static const char *getFilenamePatFromEnv(void) {
1019 const char *Filename = getenv("LLVM_PROFILE_FILE");
1020 if (!Filename || !Filename[0])
1021 return 0;
1022 return Filename;
1025 COMPILER_RT_VISIBILITY
1026 const char *__llvm_profile_get_path_prefix(void) {
1027 int Length;
1028 char *FilenameBuf, *Prefix;
1029 const char *Filename, *PrefixEnd;
1031 if (lprofCurFilename.ProfilePathPrefix)
1032 return lprofCurFilename.ProfilePathPrefix;
1034 Length = getCurFilenameLength();
1035 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
1036 Filename = getCurFilename(FilenameBuf, 0);
1037 if (!Filename)
1038 return "\0";
1040 PrefixEnd = lprofFindLastDirSeparator(Filename);
1041 if (!PrefixEnd)
1042 return "\0";
1044 Length = PrefixEnd - Filename + 1;
1045 Prefix = (char *)malloc(Length + 1);
1046 if (!Prefix) {
1047 PROF_ERR("Failed to %s\n", "allocate memory.");
1048 return "\0";
1050 memcpy(Prefix, Filename, Length);
1051 Prefix[Length] = '\0';
1052 lprofCurFilename.ProfilePathPrefix = Prefix;
1053 return Prefix;
1056 COMPILER_RT_VISIBILITY
1057 const char *__llvm_profile_get_filename(void) {
1058 int Length;
1059 char *FilenameBuf;
1060 const char *Filename;
1062 Length = getCurFilenameLength();
1063 FilenameBuf = (char *)malloc(Length + 1);
1064 if (!FilenameBuf) {
1065 PROF_ERR("Failed to %s\n", "allocate memory.");
1066 return "\0";
1068 Filename = getCurFilename(FilenameBuf, 1);
1069 if (!Filename)
1070 return "\0";
1072 return FilenameBuf;
1075 /* This API initializes the file handling, both user specified
1076 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
1077 * environment variable can override this default value.
1079 COMPILER_RT_VISIBILITY
1080 void __llvm_profile_initialize_file(void) {
1081 const char *EnvFilenamePat;
1082 const char *SelectedPat = NULL;
1083 ProfileNameSpecifier PNS = PNS_unknown;
1084 int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0);
1086 EnvFilenamePat = getFilenamePatFromEnv();
1087 if (EnvFilenamePat) {
1088 /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid
1089 at the moment when __llvm_profile_write_file() gets executed. */
1090 parseAndSetFilename(EnvFilenamePat, PNS_environment, 1);
1091 return;
1092 } else if (hasCommandLineOverrider) {
1093 SelectedPat = INSTR_PROF_PROFILE_NAME_VAR;
1094 PNS = PNS_command_line;
1095 } else {
1096 SelectedPat = NULL;
1097 PNS = PNS_default;
1100 parseAndSetFilename(SelectedPat, PNS, 0);
1103 /* This method is invoked by the runtime initialization hook
1104 * InstrProfilingRuntime.o if it is linked in.
1106 COMPILER_RT_VISIBILITY
1107 void __llvm_profile_initialize(void) {
1108 __llvm_profile_initialize_file();
1109 if (!__llvm_profile_is_continuous_mode_enabled())
1110 __llvm_profile_register_write_file_atexit();
1113 /* This API is directly called by the user application code. It has the
1114 * highest precedence compared with LLVM_PROFILE_FILE environment variable
1115 * and command line option -fprofile-instr-generate=<profile_name>.
1117 COMPILER_RT_VISIBILITY
1118 void __llvm_profile_set_filename(const char *FilenamePat) {
1119 if (__llvm_profile_is_continuous_mode_enabled())
1120 return;
1121 parseAndSetFilename(FilenamePat, PNS_runtime_api, 1);
1124 /* The public API for writing profile data into the file with name
1125 * set by previous calls to __llvm_profile_set_filename or
1126 * __llvm_profile_override_default_filename or
1127 * __llvm_profile_initialize_file. */
1128 COMPILER_RT_VISIBILITY
1129 int __llvm_profile_write_file(void) {
1130 int rc, Length;
1131 const char *Filename;
1132 char *FilenameBuf;
1134 // Temporarily suspend getting SIGKILL when the parent exits.
1135 int PDeathSig = lprofSuspendSigKill();
1137 if (lprofProfileDumped() || __llvm_profile_is_continuous_mode_enabled()) {
1138 PROF_NOTE("Profile data not written to file: %s.\n", "already written");
1139 if (PDeathSig == 1)
1140 lprofRestoreSigKill();
1141 return 0;
1144 Length = getCurFilenameLength();
1145 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
1146 Filename = getCurFilename(FilenameBuf, 0);
1148 /* Check the filename. */
1149 if (!Filename) {
1150 PROF_ERR("Failed to write file : %s\n", "Filename not set");
1151 if (PDeathSig == 1)
1152 lprofRestoreSigKill();
1153 return -1;
1156 /* Check if there is llvm/runtime version mismatch. */
1157 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
1158 PROF_ERR("Runtime and instrumentation version mismatch : "
1159 "expected %d, but get %d\n",
1160 INSTR_PROF_RAW_VERSION,
1161 (int)GET_VERSION(__llvm_profile_get_version()));
1162 if (PDeathSig == 1)
1163 lprofRestoreSigKill();
1164 return -1;
1167 /* Write profile data to the file. */
1168 rc = writeFile(Filename);
1169 if (rc)
1170 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
1172 // Restore SIGKILL.
1173 if (PDeathSig == 1)
1174 lprofRestoreSigKill();
1176 return rc;
1179 COMPILER_RT_VISIBILITY
1180 int __llvm_profile_dump(void) {
1181 if (!doMerging())
1182 PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering "
1183 " of previously dumped profile data : %s. Either use %%m "
1184 "in profile name or change profile name before dumping.\n",
1185 "online profile merging is not on");
1186 int rc = __llvm_profile_write_file();
1187 lprofSetProfileDumped(1);
1188 return rc;
1191 /* Order file data will be saved in a file with suffx .order. */
1192 static const char *OrderFileSuffix = ".order";
1194 COMPILER_RT_VISIBILITY
1195 int __llvm_orderfile_write_file(void) {
1196 int rc, Length, LengthBeforeAppend, SuffixLength;
1197 const char *Filename;
1198 char *FilenameBuf;
1200 // Temporarily suspend getting SIGKILL when the parent exits.
1201 int PDeathSig = lprofSuspendSigKill();
1203 SuffixLength = strlen(OrderFileSuffix);
1204 Length = getCurFilenameLength() + SuffixLength;
1205 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
1206 Filename = getCurFilename(FilenameBuf, 1);
1208 /* Check the filename. */
1209 if (!Filename) {
1210 PROF_ERR("Failed to write file : %s\n", "Filename not set");
1211 if (PDeathSig == 1)
1212 lprofRestoreSigKill();
1213 return -1;
1216 /* Append order file suffix */
1217 LengthBeforeAppend = strlen(Filename);
1218 memcpy(FilenameBuf + LengthBeforeAppend, OrderFileSuffix, SuffixLength);
1219 FilenameBuf[LengthBeforeAppend + SuffixLength] = '\0';
1221 /* Check if there is llvm/runtime version mismatch. */
1222 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
1223 PROF_ERR("Runtime and instrumentation version mismatch : "
1224 "expected %d, but get %d\n",
1225 INSTR_PROF_RAW_VERSION,
1226 (int)GET_VERSION(__llvm_profile_get_version()));
1227 if (PDeathSig == 1)
1228 lprofRestoreSigKill();
1229 return -1;
1232 /* Write order data to the file. */
1233 rc = writeOrderFile(Filename);
1234 if (rc)
1235 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
1237 // Restore SIGKILL.
1238 if (PDeathSig == 1)
1239 lprofRestoreSigKill();
1241 return rc;
1244 COMPILER_RT_VISIBILITY
1245 int __llvm_orderfile_dump(void) {
1246 int rc = __llvm_orderfile_write_file();
1247 return rc;
1250 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
1252 COMPILER_RT_VISIBILITY
1253 int __llvm_profile_register_write_file_atexit(void) {
1254 static int HasBeenRegistered = 0;
1256 if (HasBeenRegistered)
1257 return 0;
1259 lprofSetupValueProfiler();
1261 HasBeenRegistered = 1;
1262 return lprofAtExit(writeFileWithoutReturn);
1265 COMPILER_RT_VISIBILITY int __llvm_profile_set_file_object(FILE *File,
1266 int EnableMerge) {
1267 if (__llvm_profile_is_continuous_mode_enabled()) {
1268 if (!EnableMerge) {
1269 PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported in "
1270 "continuous sync mode when merging is disabled\n",
1271 fileno(File));
1272 return 1;
1274 if (lprofLockFileHandle(File) != 0) {
1275 PROF_WARN("Data may be corrupted during profile merging : %s\n",
1276 "Fail to obtain file lock due to system limit.");
1278 uint64_t ProfileFileSize = 0;
1279 if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {
1280 lprofUnlockFileHandle(File);
1281 return 1;
1283 if (ProfileFileSize == 0) {
1284 FreeHook = &free;
1285 setupIOBuffer();
1286 ProfDataWriter fileWriter;
1287 initFileWriter(&fileWriter, File);
1288 if (lprofWriteData(&fileWriter, 0, 0)) {
1289 lprofUnlockFileHandle(File);
1290 PROF_ERR("Failed to write file \"%d\": %s\n", fileno(File),
1291 strerror(errno));
1292 return 1;
1294 fflush(File);
1295 } else {
1296 /* The merged profile has a non-zero length. Check that it is compatible
1297 * with the data in this process. */
1298 char *ProfileBuffer;
1299 if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {
1300 lprofUnlockFileHandle(File);
1301 return 1;
1303 (void)munmap(ProfileBuffer, ProfileFileSize);
1305 mmapForContinuousMode(0, File);
1306 lprofUnlockFileHandle(File);
1307 } else {
1308 setProfileFile(File);
1309 setProfileMergeRequested(EnableMerge);
1311 return 0;
1314 #endif