1 /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
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
7 \*===----------------------------------------------------------------------===*/
9 #if !defined(__Fuchsia__)
21 #include "WindowsMMap.h"
29 #if defined(__linux__)
30 #include <sys/types.h>
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
{
49 } ProfileNameSpecifier
;
51 static const char *getPNSStr(ProfileNameSpecifier PNS
) {
54 return "default setting";
55 case PNS_command_line
:
56 return "command line";
58 return "environment variable";
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
73 unsigned OwnsFilenamePat
;
74 const char *ProfilePathPrefix
;
75 char PidChars
[MAX_PID_SIZE
];
77 char Hostname
[COMPILER_RT_MAX_HOSTLEN
];
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
;
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 int mmapForContinuousMode(uint64_t CurrentFileOffset
, FILE *File
) {
105 /* Get the sizes of various profile data sections. Taken from
106 * __llvm_profile_get_size_for_buffer(). */
107 const __llvm_profile_data
*DataBegin
= __llvm_profile_begin_data();
108 const __llvm_profile_data
*DataEnd
= __llvm_profile_end_data();
109 const char *CountersBegin
= __llvm_profile_begin_counters();
110 const char *CountersEnd
= __llvm_profile_end_counters();
111 const char *BitmapBegin
= __llvm_profile_begin_bitmap();
112 const char *BitmapEnd
= __llvm_profile_end_bitmap();
113 const char *NamesBegin
= __llvm_profile_begin_names();
114 const char *NamesEnd
= __llvm_profile_end_names();
115 const uint64_t NamesSize
= (NamesEnd
- NamesBegin
) * sizeof(char);
116 uint64_t DataSize
= __llvm_profile_get_data_size(DataBegin
, DataEnd
);
117 uint64_t CountersSize
=
118 __llvm_profile_get_counters_size(CountersBegin
, CountersEnd
);
119 uint64_t NumBitmapBytes
=
120 __llvm_profile_get_num_bitmap_bytes(BitmapBegin
, BitmapEnd
);
122 /* Check that the counter, bitmap, and data sections in this image are
124 unsigned PageSize
= getpagesize();
125 if ((intptr_t)CountersBegin
% PageSize
!= 0) {
126 PROF_ERR("Counters section not page-aligned (start = %p, pagesz = %u).\n",
127 CountersBegin
, PageSize
);
130 if ((intptr_t)BitmapBegin
% PageSize
!= 0) {
131 PROF_ERR("Bitmap section not page-aligned (start = %p, pagesz = %u).\n",
132 BitmapBegin
, PageSize
);
135 if ((intptr_t)DataBegin
% PageSize
!= 0) {
136 PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
137 DataBegin
, PageSize
);
140 int Fileno
= fileno(File
);
141 /* Determine how much padding is needed before/after the counters and
142 * after the names. */
143 uint64_t PaddingBytesBeforeCounters
, PaddingBytesAfterCounters
,
144 PaddingBytesAfterNames
, PaddingBytesAfterBitmapBytes
;
145 __llvm_profile_get_padding_sizes_for_counters(
146 DataSize
, CountersSize
, NumBitmapBytes
, NamesSize
,
147 &PaddingBytesBeforeCounters
, &PaddingBytesAfterCounters
,
148 &PaddingBytesAfterBitmapBytes
, &PaddingBytesAfterNames
);
150 uint64_t PageAlignedCountersLength
= CountersSize
+ PaddingBytesAfterCounters
;
151 uint64_t FileOffsetToCounters
= CurrentFileOffset
+
152 sizeof(__llvm_profile_header
) + DataSize
+
153 PaddingBytesBeforeCounters
;
154 void *CounterMmap
= mmap((void *)CountersBegin
, PageAlignedCountersLength
,
155 PROT_READ
| PROT_WRITE
, MAP_FIXED
| MAP_SHARED
,
156 Fileno
, FileOffsetToCounters
);
157 if (CounterMmap
!= CountersBegin
) {
159 "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
160 " - CountersBegin: %p\n"
161 " - PageAlignedCountersLength: %" PRIu64
"\n"
163 " - FileOffsetToCounters: %" PRIu64
"\n",
164 strerror(errno
), CountersBegin
, PageAlignedCountersLength
, Fileno
,
165 FileOffsetToCounters
);
169 /* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()
170 * will fail with EINVAL. */
171 if (NumBitmapBytes
== 0)
174 uint64_t PageAlignedBitmapLength
=
175 NumBitmapBytes
+ PaddingBytesAfterBitmapBytes
;
176 uint64_t FileOffsetToBitmap
=
177 CurrentFileOffset
+ sizeof(__llvm_profile_header
) + DataSize
+
178 PaddingBytesBeforeCounters
+ CountersSize
+ PaddingBytesAfterCounters
;
180 mmap((void *)BitmapBegin
, PageAlignedBitmapLength
, PROT_READ
| PROT_WRITE
,
181 MAP_FIXED
| MAP_SHARED
, Fileno
, FileOffsetToBitmap
);
182 if (BitmapMmap
!= BitmapBegin
) {
184 "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
185 " - BitmapBegin: %p\n"
186 " - PageAlignedBitmapLength: %" PRIu64
"\n"
188 " - FileOffsetToBitmap: %" PRIu64
"\n",
189 strerror(errno
), BitmapBegin
, PageAlignedBitmapLength
, Fileno
,
195 #elif defined(__ELF__) || defined(_WIN32)
197 #define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR \
198 INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR, _default)
199 COMPILER_RT_VISIBILITY
intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR
= 0;
201 /* This variable is a weak external reference which could be used to detect
202 * whether or not the compiler defined this symbol. */
203 #if defined(_MSC_VER)
204 COMPILER_RT_VISIBILITY
extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
;
205 #if defined(_M_IX86) || defined(__i386__)
206 #define WIN_SYM_PREFIX "_"
208 #define WIN_SYM_PREFIX
211 linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \
212 INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \
213 INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))
215 COMPILER_RT_VISIBILITY
extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
216 __attribute__((weak
, alias(INSTR_PROF_QUOTE(
217 INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR
))));
219 static const int ContinuousModeSupported
= 1;
220 static const int UseBiasVar
= 1;
221 /* TODO: If there are two DSOs, the second DSO initilization will truncate the
222 * first profile file. */
223 static const char *FileOpenMode
= "w+b";
224 /* This symbol is defined by the compiler when runtime counter relocation is
225 * used and runtime provides a weak alias so we can check if it's defined. */
226 static void *BiasAddr
= &INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
;
227 static void *BiasDefaultAddr
= &INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR
;
228 static int mmapForContinuousMode(uint64_t CurrentFileOffset
, FILE *File
) {
229 /* Get the sizes of various profile data sections. Taken from
230 * __llvm_profile_get_size_for_buffer(). */
231 const __llvm_profile_data
*DataBegin
= __llvm_profile_begin_data();
232 const __llvm_profile_data
*DataEnd
= __llvm_profile_end_data();
233 const char *CountersBegin
= __llvm_profile_begin_counters();
234 const char *CountersEnd
= __llvm_profile_end_counters();
235 const char *BitmapBegin
= __llvm_profile_begin_bitmap();
236 const char *BitmapEnd
= __llvm_profile_end_bitmap();
237 uint64_t DataSize
= __llvm_profile_get_data_size(DataBegin
, DataEnd
);
238 /* Get the file size. */
239 uint64_t FileSize
= 0;
240 if (getProfileFileSizeForMerging(File
, &FileSize
))
243 /* Map the profile. */
244 char *Profile
= (char *)mmap(NULL
, FileSize
, PROT_READ
| PROT_WRITE
,
245 MAP_SHARED
, fileno(File
), 0);
246 if (Profile
== MAP_FAILED
) {
247 PROF_ERR("Unable to mmap profile: %s\n", strerror(errno
));
250 const uint64_t CountersOffsetInBiasMode
=
251 sizeof(__llvm_profile_header
) + __llvm_write_binary_ids(NULL
) + DataSize
;
252 /* Update the profile fields based on the current mapping. */
253 INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
=
254 (intptr_t)Profile
- (uintptr_t)CountersBegin
+ CountersOffsetInBiasMode
;
256 /* Return the memory allocated for counters to OS. */
257 lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin
, (uintptr_t)CountersEnd
);
259 /* BIAS MODE not supported yet for Bitmap (MCDC). */
261 /* Return the memory allocated for counters to OS. */
262 lprofReleaseMemoryPagesToOS((uintptr_t)BitmapBegin
, (uintptr_t)BitmapEnd
);
266 static const int ContinuousModeSupported
= 0;
267 static const int UseBiasVar
= 0;
268 static const char *FileOpenMode
= "a+b";
269 static void *BiasAddr
= NULL
;
270 static void *BiasDefaultAddr
= NULL
;
271 static int mmapForContinuousMode(uint64_t CurrentFileOffset
, FILE *File
) {
276 static int isProfileMergeRequested(void) { return ProfileMergeRequested
; }
277 static void setProfileMergeRequested(int EnableMerge
) {
278 ProfileMergeRequested
= EnableMerge
;
281 static FILE *ProfileFile
= NULL
;
282 static FILE *getProfileFile(void) { return ProfileFile
; }
283 static void setProfileFile(FILE *File
) { ProfileFile
= File
; }
285 static int getCurFilenameLength(void);
286 static const char *getCurFilename(char *FilenameBuf
, int ForceUseBuf
);
287 static unsigned doMerging(void) {
288 return lprofCurFilename
.MergePoolSize
|| isProfileMergeRequested();
291 /* Return 1 if there is an error, otherwise return 0. */
292 static uint32_t fileWriter(ProfDataWriter
*This
, ProfDataIOVec
*IOVecs
,
293 uint32_t NumIOVecs
) {
295 FILE *File
= (FILE *)This
->WriterCtx
;
296 char Zeroes
[sizeof(uint64_t)] = {0};
297 for (I
= 0; I
< NumIOVecs
; I
++) {
298 if (IOVecs
[I
].Data
) {
299 if (fwrite(IOVecs
[I
].Data
, IOVecs
[I
].ElmSize
, IOVecs
[I
].NumElm
, File
) !=
302 } else if (IOVecs
[I
].UseZeroPadding
) {
303 size_t BytesToWrite
= IOVecs
[I
].ElmSize
* IOVecs
[I
].NumElm
;
304 while (BytesToWrite
> 0) {
305 size_t PartialWriteLen
=
306 (sizeof(uint64_t) > BytesToWrite
) ? BytesToWrite
: sizeof(uint64_t);
307 if (fwrite(Zeroes
, sizeof(uint8_t), PartialWriteLen
, File
) !=
311 BytesToWrite
-= PartialWriteLen
;
314 if (fseek(File
, IOVecs
[I
].ElmSize
* IOVecs
[I
].NumElm
, SEEK_CUR
) == -1)
321 /* TODO: make buffer size controllable by an internal option, and compiler can pass the size
322 to runtime via a variable. */
323 static uint32_t orderFileWriter(FILE *File
, const uint32_t *DataStart
) {
324 if (fwrite(DataStart
, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE
, File
) !=
325 INSTR_ORDER_FILE_BUFFER_SIZE
)
330 static void initFileWriter(ProfDataWriter
*This
, FILE *File
) {
331 This
->Write
= fileWriter
;
332 This
->WriterCtx
= File
;
335 COMPILER_RT_VISIBILITY ProfBufferIO
*
336 lprofCreateBufferIOInternal(void *File
, uint32_t BufferSz
) {
338 DynamicBufferIOBuffer
= (uint8_t *)calloc(BufferSz
, 1);
339 VPBufferSize
= BufferSz
;
340 ProfDataWriter
*fileWriter
=
341 (ProfDataWriter
*)calloc(sizeof(ProfDataWriter
), 1);
342 initFileWriter(fileWriter
, File
);
343 ProfBufferIO
*IO
= lprofCreateBufferIO(fileWriter
);
344 IO
->OwnFileWriter
= 1;
348 static void setupIOBuffer(void) {
349 const char *BufferSzStr
= 0;
350 BufferSzStr
= getenv("LLVM_VP_BUFFER_SIZE");
351 if (BufferSzStr
&& BufferSzStr
[0]) {
352 VPBufferSize
= atoi(BufferSzStr
);
353 DynamicBufferIOBuffer
= (uint8_t *)calloc(VPBufferSize
, 1);
357 /* Get the size of the profile file. If there are any errors, print the
358 * message under the assumption that the profile is being read for merging
359 * purposes, and return -1. Otherwise return the file size in the inout param
360 * \p ProfileFileSize. */
361 static int getProfileFileSizeForMerging(FILE *ProfileFile
,
362 uint64_t *ProfileFileSize
) {
363 if (fseek(ProfileFile
, 0L, SEEK_END
) == -1) {
364 PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
368 *ProfileFileSize
= ftell(ProfileFile
);
370 /* Restore file offset. */
371 if (fseek(ProfileFile
, 0L, SEEK_SET
) == -1) {
372 PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
377 if (*ProfileFileSize
> 0 &&
378 *ProfileFileSize
< sizeof(__llvm_profile_header
)) {
379 PROF_WARN("Unable to merge profile data: %s\n",
380 "source profile file is too small.");
386 /* mmap() \p ProfileFile for profile merging purposes, assuming that an
387 * exclusive lock is held on the file and that \p ProfileFileSize is the
388 * length of the file. Return the mmap'd buffer in the inout variable
389 * \p ProfileBuffer. Returns -1 on failure. On success, the caller is
390 * responsible for unmapping the mmap'd buffer in \p ProfileBuffer. */
391 static int mmapProfileForMerging(FILE *ProfileFile
, uint64_t ProfileFileSize
,
392 char **ProfileBuffer
) {
393 *ProfileBuffer
= mmap(NULL
, ProfileFileSize
, PROT_READ
, MAP_SHARED
| MAP_FILE
,
394 fileno(ProfileFile
), 0);
395 if (*ProfileBuffer
== MAP_FAILED
) {
396 PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
401 if (__llvm_profile_check_compatibility(*ProfileBuffer
, ProfileFileSize
)) {
402 (void)munmap(*ProfileBuffer
, ProfileFileSize
);
403 PROF_WARN("Unable to merge profile data: %s\n",
404 "source profile file is not compatible.");
410 /* Read profile data in \c ProfileFile and merge with in-memory
411 profile counters. Returns -1 if there is fatal error, otheriwse
412 0 is returned. Returning 0 does not mean merge is actually
413 performed. If merge is actually done, *MergeDone is set to 1.
415 static int doProfileMerging(FILE *ProfileFile
, int *MergeDone
) {
416 uint64_t ProfileFileSize
;
419 /* Get the size of the profile on disk. */
420 if (getProfileFileSizeForMerging(ProfileFile
, &ProfileFileSize
) == -1)
423 /* Nothing to merge. */
424 if (!ProfileFileSize
)
427 /* mmap() the profile and check that it is compatible with the data in
428 * the current image. */
429 if (mmapProfileForMerging(ProfileFile
, ProfileFileSize
, &ProfileBuffer
) == -1)
432 /* Now start merging */
433 if (__llvm_profile_merge_from_buffer(ProfileBuffer
, ProfileFileSize
)) {
434 PROF_ERR("%s\n", "Invalid profile data to merge");
435 (void)munmap(ProfileBuffer
, ProfileFileSize
);
439 // Truncate the file in case merging of value profile did not happen to
440 // prevent from leaving garbage data at the end of the profile file.
441 (void)COMPILER_RT_FTRUNCATE(ProfileFile
,
442 __llvm_profile_get_size_for_buffer());
444 (void)munmap(ProfileBuffer
, ProfileFileSize
);
450 /* Create the directory holding the file, if needed. */
451 static void createProfileDir(const char *Filename
) {
452 size_t Length
= strlen(Filename
);
453 if (lprofFindFirstDirSeparator(Filename
)) {
454 char *Copy
= (char *)COMPILER_RT_ALLOCA(Length
+ 1);
455 strncpy(Copy
, Filename
, Length
+ 1);
456 __llvm_profile_recursive_mkdir(Copy
);
460 /* Open the profile data for merging. It opens the file in r+b mode with
461 * file locking. If the file has content which is compatible with the
462 * current process, it also reads in the profile data in the file and merge
463 * it with in-memory counters. After the profile data is merged in memory,
464 * the original profile data is truncated and gets ready for the profile
465 * dumper. With profile merging enabled, each executable as well as any of
466 * its instrumented shared libraries dump profile data into their own data file.
468 static FILE *openFileForMerging(const char *ProfileFileName
, int *MergeDone
) {
469 FILE *ProfileFile
= getProfileFile();
471 // initializeProfileForContinuousMode will lock the profile, but if
472 // ProfileFile is set by user via __llvm_profile_set_file_object, it's assumed
473 // unlocked at this point.
474 if (ProfileFile
&& !__llvm_profile_is_continuous_mode_enabled()) {
475 lprofLockFileHandle(ProfileFile
);
478 createProfileDir(ProfileFileName
);
479 ProfileFile
= lprofOpenFileEx(ProfileFileName
);
484 rc
= doProfileMerging(ProfileFile
, MergeDone
);
485 if (rc
|| (!*MergeDone
&& COMPILER_RT_FTRUNCATE(ProfileFile
, 0L)) ||
486 fseek(ProfileFile
, 0L, SEEK_SET
) == -1) {
487 PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName
,
495 static FILE *getFileObject(const char *OutputName
) {
497 File
= getProfileFile();
502 return fopen(OutputName
, "ab");
505 /* Write profile data to file \c OutputName. */
506 static int writeFile(const char *OutputName
) {
511 VPMergeHook
= &lprofMergeValueProfData
;
513 OutputFile
= openFileForMerging(OutputName
, &MergeDone
);
515 OutputFile
= getFileObject(OutputName
);
522 ProfDataWriter fileWriter
;
523 initFileWriter(&fileWriter
, OutputFile
);
524 RetVal
= lprofWriteData(&fileWriter
, lprofGetVPDataReader(), MergeDone
);
526 if (OutputFile
== getProfileFile()) {
528 if (doMerging() && !__llvm_profile_is_continuous_mode_enabled()) {
529 lprofUnlockFileHandle(OutputFile
);
538 /* Write order data to file \c OutputName. */
539 static int writeOrderFile(const char *OutputName
) {
543 OutputFile
= fopen(OutputName
, "w");
546 PROF_WARN("can't open file with mode ab: %s\n", OutputName
);
552 const uint32_t *DataBegin
= __llvm_profile_begin_orderfile();
553 RetVal
= orderFileWriter(OutputFile
, DataBegin
);
559 #define LPROF_INIT_ONCE_ENV "__LLVM_PROFILE_RT_INIT_ONCE"
561 static void truncateCurrentFile(void) {
562 const char *Filename
;
567 Length
= getCurFilenameLength();
568 FilenameBuf
= (char *)COMPILER_RT_ALLOCA(Length
+ 1);
569 Filename
= getCurFilename(FilenameBuf
, 0);
573 /* Only create the profile directory and truncate an existing profile once.
574 * In continuous mode, this is necessary, as the profile is written-to by the
575 * runtime initializer. */
576 int initialized
= getenv(LPROF_INIT_ONCE_ENV
) != NULL
;
580 _putenv(LPROF_INIT_ONCE_ENV
"=" LPROF_INIT_ONCE_ENV
);
582 setenv(LPROF_INIT_ONCE_ENV
, LPROF_INIT_ONCE_ENV
, 1);
585 /* Create the profile dir (even if online merging is enabled), so that
586 * the profile file can be set up if continuous mode is enabled. */
587 createProfileDir(Filename
);
589 /* By pass file truncation to allow online raw profile merging. */
590 if (lprofCurFilename
.MergePoolSize
)
593 /* Truncate the file. Later we'll reopen and append. */
594 File
= fopen(Filename
, "w");
600 /* Write a partial profile to \p Filename, which is required to be backed by
601 * the open file object \p File. */
602 static int writeProfileWithFileObject(const char *Filename
, FILE *File
) {
603 setProfileFile(File
);
604 int rc
= writeFile(Filename
);
606 PROF_ERR("Failed to write file \"%s\": %s\n", Filename
, strerror(errno
));
607 setProfileFile(NULL
);
611 static void initializeProfileForContinuousMode(void) {
612 if (!__llvm_profile_is_continuous_mode_enabled())
614 if (!ContinuousModeSupported
) {
615 PROF_ERR("%s\n", "continuous mode is unsupported on this platform");
618 if (UseBiasVar
&& BiasAddr
== BiasDefaultAddr
) {
619 PROF_ERR("%s\n", "__llvm_profile_counter_bias is undefined");
623 /* Get the sizes of counter section. */
624 uint64_t CountersSize
= __llvm_profile_get_counters_size(
625 __llvm_profile_begin_counters(), __llvm_profile_end_counters());
627 int Length
= getCurFilenameLength();
628 char *FilenameBuf
= (char *)COMPILER_RT_ALLOCA(Length
+ 1);
629 const char *Filename
= getCurFilename(FilenameBuf
, 0);
634 uint64_t CurrentFileOffset
= 0;
636 /* We are merging profiles. Map the counter section as shared memory into
637 * the profile, i.e. into each participating process. An increment in one
638 * process should be visible to every other process with the same counter
640 File
= lprofOpenFileEx(Filename
);
644 uint64_t ProfileFileSize
= 0;
645 if (getProfileFileSizeForMerging(File
, &ProfileFileSize
) == -1) {
646 lprofUnlockFileHandle(File
);
650 if (ProfileFileSize
== 0) {
651 /* Grow the profile so that mmap() can succeed. Leak the file handle, as
652 * the file should stay open. */
653 if (writeProfileWithFileObject(Filename
, File
) != 0) {
654 lprofUnlockFileHandle(File
);
659 /* The merged profile has a non-zero length. Check that it is compatible
660 * with the data in this process. */
662 if (mmapProfileForMerging(File
, ProfileFileSize
, &ProfileBuffer
) == -1) {
663 lprofUnlockFileHandle(File
);
667 (void)munmap(ProfileBuffer
, ProfileFileSize
);
670 File
= fopen(Filename
, FileOpenMode
);
673 /* Check that the offset within the file is page-aligned. */
674 CurrentFileOffset
= ftell(File
);
675 unsigned PageSize
= getpagesize();
676 if (CurrentFileOffset
% PageSize
!= 0) {
677 PROF_ERR("Continuous counter sync mode is enabled, but raw profile is not"
678 "page-aligned. CurrentFileOffset = %" PRIu64
", pagesz = %u.\n",
679 (uint64_t)CurrentFileOffset
, PageSize
);
682 if (writeProfileWithFileObject(Filename
, File
) != 0) {
688 /* mmap() the profile counters so long as there is at least one counter.
689 * If there aren't any counters, mmap() would fail with EINVAL. */
690 if (CountersSize
> 0)
691 mmapForContinuousMode(CurrentFileOffset
, File
);
694 lprofUnlockFileHandle(File
);
699 static const char *DefaultProfileName
= "default.profraw";
700 static void resetFilenameToDefault(void) {
701 if (lprofCurFilename
.FilenamePat
&& lprofCurFilename
.OwnsFilenamePat
) {
703 #pragma GCC diagnostic push
704 #pragma GCC diagnostic ignored "-Wcast-qual"
706 free((void *)lprofCurFilename
.FilenamePat
);
708 #pragma GCC diagnostic pop
711 memset(&lprofCurFilename
, 0, sizeof(lprofCurFilename
));
712 lprofCurFilename
.FilenamePat
= DefaultProfileName
;
713 lprofCurFilename
.PNS
= PNS_default
;
716 static unsigned getMergePoolSize(const char *FilenamePat
, int *I
) {
717 unsigned J
= 0, Num
= 0;
719 char C
= FilenamePat
[*I
+ J
];
722 return Num
? Num
: 1;
724 if (C
< '0' || C
> '9')
726 Num
= Num
* 10 + C
- '0';
728 /* If FilenamePat[*I+J] is between '0' and '9', the next byte is guaranteed
729 * to be in-bound as the string is null terminated. */
734 /* Assert that Idx does index past a string null terminator. Return the
735 * result of the check. */
736 static int checkBounds(int Idx
, int Strlen
) {
737 assert(Idx
<= Strlen
&& "Indexing past string null terminator");
738 return Idx
<= Strlen
;
741 /* Parses the pattern string \p FilenamePat and stores the result to
742 * lprofcurFilename structure. */
743 static int parseFilenamePattern(const char *FilenamePat
,
744 unsigned CopyFilenamePat
) {
745 int NumPids
= 0, NumHosts
= 0, I
;
746 char *PidChars
= &lprofCurFilename
.PidChars
[0];
747 char *Hostname
= &lprofCurFilename
.Hostname
[0];
748 int MergingEnabled
= 0;
749 int FilenamePatLen
= strlen(FilenamePat
);
752 #pragma GCC diagnostic push
753 #pragma GCC diagnostic ignored "-Wcast-qual"
755 /* Clean up cached prefix and filename. */
756 if (lprofCurFilename
.ProfilePathPrefix
)
757 free((void *)lprofCurFilename
.ProfilePathPrefix
);
759 if (lprofCurFilename
.FilenamePat
&& lprofCurFilename
.OwnsFilenamePat
) {
760 free((void *)lprofCurFilename
.FilenamePat
);
763 #pragma GCC diagnostic pop
766 memset(&lprofCurFilename
, 0, sizeof(lprofCurFilename
));
768 if (!CopyFilenamePat
)
769 lprofCurFilename
.FilenamePat
= FilenamePat
;
771 lprofCurFilename
.FilenamePat
= strdup(FilenamePat
);
772 lprofCurFilename
.OwnsFilenamePat
= 1;
774 /* Check the filename for "%p", which indicates a pid-substitution. */
775 for (I
= 0; checkBounds(I
, FilenamePatLen
) && FilenamePat
[I
]; ++I
) {
776 if (FilenamePat
[I
] == '%') {
777 ++I
; /* Advance to the next character. */
778 if (!checkBounds(I
, FilenamePatLen
))
780 if (FilenamePat
[I
] == 'p') {
782 if (snprintf(PidChars
, MAX_PID_SIZE
, "%ld", (long)getpid()) <= 0) {
783 PROF_WARN("Unable to get pid for filename pattern %s. Using the "
789 } else if (FilenamePat
[I
] == 'h') {
791 if (COMPILER_RT_GETHOSTNAME(Hostname
, COMPILER_RT_MAX_HOSTLEN
)) {
792 PROF_WARN("Unable to get hostname for filename pattern %s. Using "
797 } else if (FilenamePat
[I
] == 't') {
798 lprofCurFilename
.TmpDir
= getenv("TMPDIR");
799 if (!lprofCurFilename
.TmpDir
) {
800 PROF_WARN("Unable to get the TMPDIR environment variable, referenced "
801 "in %s. Using the default path.",
805 } else if (FilenamePat
[I
] == 'c') {
806 if (__llvm_profile_is_continuous_mode_enabled()) {
807 PROF_WARN("%%c specifier can only be specified once in %s.\n",
811 #if defined(__APPLE__) || defined(__ELF__) || defined(_WIN32)
812 __llvm_profile_set_page_size(getpagesize());
813 __llvm_profile_enable_continuous_mode();
815 PROF_WARN("%s", "Continous mode is currently only supported for Mach-O,"
816 " ELF and COFF formats.");
820 unsigned MergePoolSize
= getMergePoolSize(FilenamePat
, &I
);
823 if (MergingEnabled
) {
824 PROF_WARN("%%m specifier can only be specified once in %s.\n",
829 lprofCurFilename
.MergePoolSize
= MergePoolSize
;
834 lprofCurFilename
.NumPids
= NumPids
;
835 lprofCurFilename
.NumHosts
= NumHosts
;
839 static void parseAndSetFilename(const char *FilenamePat
,
840 ProfileNameSpecifier PNS
,
841 unsigned CopyFilenamePat
) {
843 const char *OldFilenamePat
= lprofCurFilename
.FilenamePat
;
844 ProfileNameSpecifier OldPNS
= lprofCurFilename
.PNS
;
846 /* The old profile name specifier takes precedence over the old one. */
851 FilenamePat
= DefaultProfileName
;
853 if (OldFilenamePat
&& !strcmp(OldFilenamePat
, FilenamePat
)) {
854 lprofCurFilename
.PNS
= PNS
;
858 /* When PNS >= OldPNS, the last one wins. */
859 if (!FilenamePat
|| parseFilenamePattern(FilenamePat
, CopyFilenamePat
))
860 resetFilenameToDefault();
861 lprofCurFilename
.PNS
= PNS
;
863 if (!OldFilenamePat
) {
864 if (getenv("LLVM_PROFILE_VERBOSE"))
865 PROF_NOTE("Set profile file path to \"%s\" via %s.\n",
866 lprofCurFilename
.FilenamePat
, getPNSStr(PNS
));
868 if (getenv("LLVM_PROFILE_VERBOSE"))
869 PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",
870 OldFilenamePat
, getPNSStr(OldPNS
), lprofCurFilename
.FilenamePat
,
874 truncateCurrentFile();
875 if (__llvm_profile_is_continuous_mode_enabled())
876 initializeProfileForContinuousMode();
879 /* Return buffer length that is required to store the current profile
880 * filename with PID and hostname substitutions. */
881 /* The length to hold uint64_t followed by 3 digits pool id including '_' */
883 static int getCurFilenameLength(void) {
885 if (!lprofCurFilename
.FilenamePat
|| !lprofCurFilename
.FilenamePat
[0])
888 if (!(lprofCurFilename
.NumPids
|| lprofCurFilename
.NumHosts
||
889 lprofCurFilename
.TmpDir
|| lprofCurFilename
.MergePoolSize
))
890 return strlen(lprofCurFilename
.FilenamePat
);
892 Len
= strlen(lprofCurFilename
.FilenamePat
) +
893 lprofCurFilename
.NumPids
* (strlen(lprofCurFilename
.PidChars
) - 2) +
894 lprofCurFilename
.NumHosts
* (strlen(lprofCurFilename
.Hostname
) - 2) +
895 (lprofCurFilename
.TmpDir
? (strlen(lprofCurFilename
.TmpDir
) - 1) : 0);
896 if (lprofCurFilename
.MergePoolSize
)
901 /* Return the pointer to the current profile file name (after substituting
902 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
903 * to store the resulting filename. If no substitution is needed, the
904 * current filename pattern string is directly returned, unless ForceUseBuf
906 static const char *getCurFilename(char *FilenameBuf
, int ForceUseBuf
) {
907 int I
, J
, PidLength
, HostNameLength
, TmpDirLength
, FilenamePatLength
;
908 const char *FilenamePat
= lprofCurFilename
.FilenamePat
;
910 if (!lprofCurFilename
.FilenamePat
|| !lprofCurFilename
.FilenamePat
[0])
913 if (!(lprofCurFilename
.NumPids
|| lprofCurFilename
.NumHosts
||
914 lprofCurFilename
.TmpDir
|| lprofCurFilename
.MergePoolSize
||
915 __llvm_profile_is_continuous_mode_enabled())) {
917 return lprofCurFilename
.FilenamePat
;
919 FilenamePatLength
= strlen(lprofCurFilename
.FilenamePat
);
920 memcpy(FilenameBuf
, lprofCurFilename
.FilenamePat
, FilenamePatLength
);
921 FilenameBuf
[FilenamePatLength
] = '\0';
925 PidLength
= strlen(lprofCurFilename
.PidChars
);
926 HostNameLength
= strlen(lprofCurFilename
.Hostname
);
927 TmpDirLength
= lprofCurFilename
.TmpDir
? strlen(lprofCurFilename
.TmpDir
) : 0;
928 /* Construct the new filename. */
929 for (I
= 0, J
= 0; FilenamePat
[I
]; ++I
)
930 if (FilenamePat
[I
] == '%') {
931 if (FilenamePat
[++I
] == 'p') {
932 memcpy(FilenameBuf
+ J
, lprofCurFilename
.PidChars
, PidLength
);
934 } else if (FilenamePat
[I
] == 'h') {
935 memcpy(FilenameBuf
+ J
, lprofCurFilename
.Hostname
, HostNameLength
);
937 } else if (FilenamePat
[I
] == 't') {
938 memcpy(FilenameBuf
+ J
, lprofCurFilename
.TmpDir
, TmpDirLength
);
939 FilenameBuf
[J
+ TmpDirLength
] = DIR_SEPARATOR
;
940 J
+= TmpDirLength
+ 1;
942 if (!getMergePoolSize(FilenamePat
, &I
))
944 char LoadModuleSignature
[SIGLEN
+ 1];
946 int ProfilePoolId
= getpid() % lprofCurFilename
.MergePoolSize
;
947 S
= snprintf(LoadModuleSignature
, SIGLEN
+ 1, "%" PRIu64
"_%d",
948 lprofGetLoadModuleSignature(), ProfilePoolId
);
949 if (S
== -1 || S
> SIGLEN
)
951 memcpy(FilenameBuf
+ J
, LoadModuleSignature
, S
);
954 /* Drop any unknown substitutions. */
956 FilenameBuf
[J
++] = FilenamePat
[I
];
962 /* Returns the pointer to the environment variable
963 * string. Returns null if the env var is not set. */
964 static const char *getFilenamePatFromEnv(void) {
965 const char *Filename
= getenv("LLVM_PROFILE_FILE");
966 if (!Filename
|| !Filename
[0])
971 COMPILER_RT_VISIBILITY
972 const char *__llvm_profile_get_path_prefix(void) {
974 char *FilenameBuf
, *Prefix
;
975 const char *Filename
, *PrefixEnd
;
977 if (lprofCurFilename
.ProfilePathPrefix
)
978 return lprofCurFilename
.ProfilePathPrefix
;
980 Length
= getCurFilenameLength();
981 FilenameBuf
= (char *)COMPILER_RT_ALLOCA(Length
+ 1);
982 Filename
= getCurFilename(FilenameBuf
, 0);
986 PrefixEnd
= lprofFindLastDirSeparator(Filename
);
990 Length
= PrefixEnd
- Filename
+ 1;
991 Prefix
= (char *)malloc(Length
+ 1);
993 PROF_ERR("Failed to %s\n", "allocate memory.");
996 memcpy(Prefix
, Filename
, Length
);
997 Prefix
[Length
] = '\0';
998 lprofCurFilename
.ProfilePathPrefix
= Prefix
;
1002 COMPILER_RT_VISIBILITY
1003 const char *__llvm_profile_get_filename(void) {
1006 const char *Filename
;
1008 Length
= getCurFilenameLength();
1009 FilenameBuf
= (char *)malloc(Length
+ 1);
1011 PROF_ERR("Failed to %s\n", "allocate memory.");
1014 Filename
= getCurFilename(FilenameBuf
, 1);
1021 /* This API initializes the file handling, both user specified
1022 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
1023 * environment variable can override this default value.
1025 COMPILER_RT_VISIBILITY
1026 void __llvm_profile_initialize_file(void) {
1027 const char *EnvFilenamePat
;
1028 const char *SelectedPat
= NULL
;
1029 ProfileNameSpecifier PNS
= PNS_unknown
;
1030 int hasCommandLineOverrider
= (INSTR_PROF_PROFILE_NAME_VAR
[0] != 0);
1032 EnvFilenamePat
= getFilenamePatFromEnv();
1033 if (EnvFilenamePat
) {
1034 /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid
1035 at the moment when __llvm_profile_write_file() gets executed. */
1036 parseAndSetFilename(EnvFilenamePat
, PNS_environment
, 1);
1038 } else if (hasCommandLineOverrider
) {
1039 SelectedPat
= INSTR_PROF_PROFILE_NAME_VAR
;
1040 PNS
= PNS_command_line
;
1046 parseAndSetFilename(SelectedPat
, PNS
, 0);
1049 /* This method is invoked by the runtime initialization hook
1050 * InstrProfilingRuntime.o if it is linked in.
1052 COMPILER_RT_VISIBILITY
1053 void __llvm_profile_initialize(void) {
1054 __llvm_profile_initialize_file();
1055 if (!__llvm_profile_is_continuous_mode_enabled())
1056 __llvm_profile_register_write_file_atexit();
1059 /* This API is directly called by the user application code. It has the
1060 * highest precedence compared with LLVM_PROFILE_FILE environment variable
1061 * and command line option -fprofile-instr-generate=<profile_name>.
1063 COMPILER_RT_VISIBILITY
1064 void __llvm_profile_set_filename(const char *FilenamePat
) {
1065 if (__llvm_profile_is_continuous_mode_enabled())
1067 parseAndSetFilename(FilenamePat
, PNS_runtime_api
, 1);
1070 /* The public API for writing profile data into the file with name
1071 * set by previous calls to __llvm_profile_set_filename or
1072 * __llvm_profile_override_default_filename or
1073 * __llvm_profile_initialize_file. */
1074 COMPILER_RT_VISIBILITY
1075 int __llvm_profile_write_file(void) {
1077 const char *Filename
;
1080 // Temporarily suspend getting SIGKILL when the parent exits.
1081 int PDeathSig
= lprofSuspendSigKill();
1083 if (lprofProfileDumped() || __llvm_profile_is_continuous_mode_enabled()) {
1084 PROF_NOTE("Profile data not written to file: %s.\n", "already written");
1086 lprofRestoreSigKill();
1090 Length
= getCurFilenameLength();
1091 FilenameBuf
= (char *)COMPILER_RT_ALLOCA(Length
+ 1);
1092 Filename
= getCurFilename(FilenameBuf
, 0);
1094 /* Check the filename. */
1096 PROF_ERR("Failed to write file : %s\n", "Filename not set");
1098 lprofRestoreSigKill();
1102 /* Check if there is llvm/runtime version mismatch. */
1103 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION
) {
1104 PROF_ERR("Runtime and instrumentation version mismatch : "
1105 "expected %d, but get %d\n",
1106 INSTR_PROF_RAW_VERSION
,
1107 (int)GET_VERSION(__llvm_profile_get_version()));
1109 lprofRestoreSigKill();
1113 /* Write profile data to the file. */
1114 rc
= writeFile(Filename
);
1116 PROF_ERR("Failed to write file \"%s\": %s\n", Filename
, strerror(errno
));
1120 lprofRestoreSigKill();
1125 COMPILER_RT_VISIBILITY
1126 int __llvm_profile_dump(void) {
1128 PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering "
1129 " of previously dumped profile data : %s. Either use %%m "
1130 "in profile name or change profile name before dumping.\n",
1131 "online profile merging is not on");
1132 int rc
= __llvm_profile_write_file();
1133 lprofSetProfileDumped(1);
1137 /* Order file data will be saved in a file with suffx .order. */
1138 static const char *OrderFileSuffix
= ".order";
1140 COMPILER_RT_VISIBILITY
1141 int __llvm_orderfile_write_file(void) {
1142 int rc
, Length
, LengthBeforeAppend
, SuffixLength
;
1143 const char *Filename
;
1146 // Temporarily suspend getting SIGKILL when the parent exits.
1147 int PDeathSig
= lprofSuspendSigKill();
1149 SuffixLength
= strlen(OrderFileSuffix
);
1150 Length
= getCurFilenameLength() + SuffixLength
;
1151 FilenameBuf
= (char *)COMPILER_RT_ALLOCA(Length
+ 1);
1152 Filename
= getCurFilename(FilenameBuf
, 1);
1154 /* Check the filename. */
1156 PROF_ERR("Failed to write file : %s\n", "Filename not set");
1158 lprofRestoreSigKill();
1162 /* Append order file suffix */
1163 LengthBeforeAppend
= strlen(Filename
);
1164 memcpy(FilenameBuf
+ LengthBeforeAppend
, OrderFileSuffix
, SuffixLength
);
1165 FilenameBuf
[LengthBeforeAppend
+ SuffixLength
] = '\0';
1167 /* Check if there is llvm/runtime version mismatch. */
1168 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION
) {
1169 PROF_ERR("Runtime and instrumentation version mismatch : "
1170 "expected %d, but get %d\n",
1171 INSTR_PROF_RAW_VERSION
,
1172 (int)GET_VERSION(__llvm_profile_get_version()));
1174 lprofRestoreSigKill();
1178 /* Write order data to the file. */
1179 rc
= writeOrderFile(Filename
);
1181 PROF_ERR("Failed to write file \"%s\": %s\n", Filename
, strerror(errno
));
1185 lprofRestoreSigKill();
1190 COMPILER_RT_VISIBILITY
1191 int __llvm_orderfile_dump(void) {
1192 int rc
= __llvm_orderfile_write_file();
1196 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
1198 COMPILER_RT_VISIBILITY
1199 int __llvm_profile_register_write_file_atexit(void) {
1200 static int HasBeenRegistered
= 0;
1202 if (HasBeenRegistered
)
1205 lprofSetupValueProfiler();
1207 HasBeenRegistered
= 1;
1208 return atexit(writeFileWithoutReturn
);
1211 COMPILER_RT_VISIBILITY
int __llvm_profile_set_file_object(FILE *File
,
1213 if (__llvm_profile_is_continuous_mode_enabled()) {
1215 PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported in "
1216 "continuous sync mode when merging is disabled\n",
1220 if (lprofLockFileHandle(File
) != 0) {
1221 PROF_WARN("Data may be corrupted during profile merging : %s\n",
1222 "Fail to obtain file lock due to system limit.");
1224 uint64_t ProfileFileSize
= 0;
1225 if (getProfileFileSizeForMerging(File
, &ProfileFileSize
) == -1) {
1226 lprofUnlockFileHandle(File
);
1229 if (ProfileFileSize
== 0) {
1232 ProfDataWriter fileWriter
;
1233 initFileWriter(&fileWriter
, File
);
1234 if (lprofWriteData(&fileWriter
, 0, 0)) {
1235 lprofUnlockFileHandle(File
);
1236 PROF_ERR("Failed to write file \"%d\": %s\n", fileno(File
),
1242 /* The merged profile has a non-zero length. Check that it is compatible
1243 * with the data in this process. */
1244 char *ProfileBuffer
;
1245 if (mmapProfileForMerging(File
, ProfileFileSize
, &ProfileBuffer
) == -1) {
1246 lprofUnlockFileHandle(File
);
1249 (void)munmap(ProfileBuffer
, ProfileFileSize
);
1251 mmapForContinuousMode(0, File
);
1252 lprofUnlockFileHandle(File
);
1254 setProfileFile(File
);
1255 setProfileMergeRequested(EnableMerge
);