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 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
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
);
132 if ((intptr_t)BitmapBegin
% PageSize
!= 0) {
133 PROF_ERR("Bitmap section not page-aligned (start = %p, pagesz = %u).\n",
134 BitmapBegin
, PageSize
);
137 if ((intptr_t)DataBegin
% PageSize
!= 0) {
138 PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
139 DataBegin
, PageSize
);
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
) {
164 "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
165 " - CountersBegin: %p\n"
166 " - PageAlignedCountersLength: %" PRIu64
"\n"
168 " - FileOffsetToCounters: %" PRIu64
"\n",
169 strerror(errno
), CountersBegin
, PageAlignedCountersLength
, Fileno
,
170 FileOffsetToCounters
);
174 /* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()
175 * will fail with EINVAL. */
176 if (NumBitmapBytes
== 0)
179 uint64_t PageAlignedBitmapLength
=
180 NumBitmapBytes
+ PaddingBytesAfterBitmapBytes
;
181 uint64_t FileOffsetToBitmap
=
182 FileOffsetToCounters
+ CountersSize
+ PaddingBytesAfterCounters
;
184 mmap((void *)BitmapBegin
, PageAlignedBitmapLength
, PROT_READ
| PROT_WRITE
,
185 MAP_FIXED
| MAP_SHARED
, Fileno
, FileOffsetToBitmap
);
186 if (BitmapMmap
!= BitmapBegin
) {
188 "Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
189 " - BitmapBegin: %p\n"
190 " - PageAlignedBitmapLength: %" PRIu64
"\n"
192 " - FileOffsetToBitmap: %" PRIu64
"\n",
193 strerror(errno
), BitmapBegin
, PageAlignedBitmapLength
, Fileno
,
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 "_"
216 #define WIN_SYM_PREFIX
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))
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))
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
))));
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
))
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
));
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)
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
);
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
) {
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
) {
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
) !=
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
) !=
349 BytesToWrite
-= PartialWriteLen
;
352 if (fseek(File
, IOVecs
[I
].ElmSize
* IOVecs
[I
].NumElm
, SEEK_CUR
) == -1)
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
)
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
) {
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;
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",
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",
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.");
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",
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.");
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
;
457 /* Get the size of the profile on disk. */
458 if (getProfileFileSizeForMerging(ProfileFile
, &ProfileFileSize
) == -1)
461 /* Nothing to merge. */
462 if (!ProfileFileSize
)
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)
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
);
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
);
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();
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
);
516 createProfileDir(ProfileFileName
);
517 ProfileFile
= lprofOpenFileEx(ProfileFileName
);
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
,
533 static FILE *getFileObject(const char *OutputName
) {
535 File
= getProfileFile();
540 return fopen(OutputName
, "ab");
543 /* Write profile data to file \c OutputName. */
544 static int writeFile(const char *OutputName
) {
549 VPMergeHook
= &lprofMergeValueProfData
;
551 OutputFile
= openFileForMerging(OutputName
, &MergeDone
);
553 OutputFile
= getFileObject(OutputName
);
560 ProfDataWriter fileWriter
;
561 initFileWriter(&fileWriter
, OutputFile
);
562 RetVal
= lprofWriteData(&fileWriter
, lprofGetVPDataReader(), MergeDone
);
564 if (OutputFile
== getProfileFile()) {
566 if (doMerging() && !__llvm_profile_is_continuous_mode_enabled()) {
567 lprofUnlockFileHandle(OutputFile
);
576 /* Write order data to file \c OutputName. */
577 static int writeOrderFile(const char *OutputName
) {
581 OutputFile
= fopen(OutputName
, "w");
584 PROF_WARN("can't open file with mode ab: %s\n", OutputName
);
590 const uint32_t *DataBegin
= __llvm_profile_begin_orderfile();
591 RetVal
= orderFileWriter(OutputFile
, DataBegin
);
597 #define LPROF_INIT_ONCE_ENV "__LLVM_PROFILE_RT_INIT_ONCE"
599 static void truncateCurrentFile(void) {
600 const char *Filename
;
605 Length
= getCurFilenameLength();
606 FilenameBuf
= (char *)COMPILER_RT_ALLOCA(Length
+ 1);
607 Filename
= getCurFilename(FilenameBuf
, 0);
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
;
618 _putenv(LPROF_INIT_ONCE_ENV
"=" LPROF_INIT_ONCE_ENV
);
620 setenv(LPROF_INIT_ONCE_ENV
, LPROF_INIT_ONCE_ENV
, 1);
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
)
631 /* Truncate the file. Later we'll reopen and append. */
632 File
= fopen(Filename
, "w");
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
);
644 PROF_ERR("Failed to write file \"%s\": %s\n", Filename
, strerror(errno
));
645 setProfileFile(NULL
);
649 static void initializeProfileForContinuousMode(void) {
650 if (!__llvm_profile_is_continuous_mode_enabled())
652 if (!ContinuousModeSupported
) {
653 PROF_ERR("%s\n", "continuous mode is unsupported on this platform");
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");
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);
674 uint64_t CurrentFileOffset
= 0;
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
680 File
= lprofOpenFileEx(Filename
);
684 uint64_t ProfileFileSize
= 0;
685 if (getProfileFileSizeForMerging(File
, &ProfileFileSize
) == -1) {
686 lprofUnlockFileHandle(File
);
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
);
699 /* The merged profile has a non-zero length. Check that it is compatible
700 * with the data in this process. */
702 if (mmapProfileForMerging(File
, ProfileFileSize
, &ProfileBuffer
) == -1) {
703 lprofUnlockFileHandle(File
);
707 (void)munmap(ProfileBuffer
, ProfileFileSize
);
710 File
= fopen(Filename
, FileOpenMode
);
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
);
723 if (writeProfileWithFileObject(Filename
, File
) != 0) {
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
);
735 lprofUnlockFileHandle(File
);
742 static const char *DefaultProfileName
= "default.profraw";
743 static void resetFilenameToDefault(void) {
744 if (lprofCurFilename
.FilenamePat
&& lprofCurFilename
.OwnsFilenamePat
) {
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"
752 free((void *)lprofCurFilename
.FilenamePat
);
754 #pragma GCC diagnostic pop
755 #elif defined(__clang__)
756 #pragma clang diagnostic pop
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;
767 char C
= FilenamePat
[*I
+ J
];
770 return Num
? Num
: 1;
772 if (C
< '0' || C
> '9')
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. */
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
);
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"
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
);
814 #pragma GCC diagnostic pop
815 #elif defined(__clang__)
816 #pragma clang diagnostic pop
819 memset(&lprofCurFilename
, 0, sizeof(lprofCurFilename
));
821 if (!CopyFilenamePat
)
822 lprofCurFilename
.FilenamePat
= FilenamePat
;
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
))
833 if (FilenamePat
[I
] == 'p') {
835 if (snprintf(PidChars
, MAX_PID_SIZE
, "%ld", (long)getpid()) <= 0) {
836 PROF_WARN("Unable to get pid for filename pattern %s. Using the "
842 } else if (FilenamePat
[I
] == 'h') {
844 if (COMPILER_RT_GETHOSTNAME(Hostname
, COMPILER_RT_MAX_HOSTLEN
)) {
845 PROF_WARN("Unable to get hostname for filename pattern %s. Using "
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.",
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",
862 __llvm_profile_disable_continuous_mode();
865 #if defined(__APPLE__) || defined(__ELF__) || defined(_WIN32) || defined(_AIX)
866 __llvm_profile_set_page_size(getpagesize());
867 __llvm_profile_enable_continuous_mode();
869 PROF_WARN("%s", "Continous mode is currently only supported for Mach-O,"
870 " ELF and COFF formats.");
874 unsigned MergePoolSize
= getMergePoolSize(FilenamePat
, &I
);
877 if (MergingEnabled
) {
878 PROF_WARN("%%m specifier can only be specified once in %s.\n",
883 lprofCurFilename
.MergePoolSize
= MergePoolSize
;
888 lprofCurFilename
.NumPids
= NumPids
;
889 lprofCurFilename
.NumHosts
= NumHosts
;
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. */
905 FilenamePat
= DefaultProfileName
;
907 if (OldFilenamePat
&& !strcmp(OldFilenamePat
, FilenamePat
)) {
908 lprofCurFilename
.PNS
= PNS
;
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
));
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
,
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 '_' */
937 static int getCurFilenameLength(void) {
939 if (!lprofCurFilename
.FilenamePat
|| !lprofCurFilename
.FilenamePat
[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
)
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
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])
967 if (!(lprofCurFilename
.NumPids
|| lprofCurFilename
.NumHosts
||
968 lprofCurFilename
.TmpDir
|| lprofCurFilename
.MergePoolSize
||
969 __llvm_profile_is_continuous_mode_enabled())) {
971 return lprofCurFilename
.FilenamePat
;
973 FilenamePatLength
= strlen(lprofCurFilename
.FilenamePat
);
974 memcpy(FilenameBuf
, lprofCurFilename
.FilenamePat
, FilenamePatLength
);
975 FilenameBuf
[FilenamePatLength
] = '\0';
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
);
988 } else if (FilenamePat
[I
] == 'h') {
989 memcpy(FilenameBuf
+ J
, lprofCurFilename
.Hostname
, HostNameLength
);
991 } else if (FilenamePat
[I
] == 't') {
992 memcpy(FilenameBuf
+ J
, lprofCurFilename
.TmpDir
, TmpDirLength
);
993 FilenameBuf
[J
+ TmpDirLength
] = DIR_SEPARATOR
;
994 J
+= TmpDirLength
+ 1;
996 if (!getMergePoolSize(FilenamePat
, &I
))
998 char LoadModuleSignature
[SIGLEN
+ 1];
1000 int ProfilePoolId
= getpid() % lprofCurFilename
.MergePoolSize
;
1001 S
= snprintf(LoadModuleSignature
, SIGLEN
+ 1, "%" PRIu64
"_%d",
1002 lprofGetLoadModuleSignature(), ProfilePoolId
);
1003 if (S
== -1 || S
> SIGLEN
)
1005 memcpy(FilenameBuf
+ J
, LoadModuleSignature
, S
);
1008 /* Drop any unknown substitutions. */
1010 FilenameBuf
[J
++] = FilenamePat
[I
];
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])
1025 COMPILER_RT_VISIBILITY
1026 const char *__llvm_profile_get_path_prefix(void) {
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);
1040 PrefixEnd
= lprofFindLastDirSeparator(Filename
);
1044 Length
= PrefixEnd
- Filename
+ 1;
1045 Prefix
= (char *)malloc(Length
+ 1);
1047 PROF_ERR("Failed to %s\n", "allocate memory.");
1050 memcpy(Prefix
, Filename
, Length
);
1051 Prefix
[Length
] = '\0';
1052 lprofCurFilename
.ProfilePathPrefix
= Prefix
;
1056 COMPILER_RT_VISIBILITY
1057 const char *__llvm_profile_get_filename(void) {
1060 const char *Filename
;
1062 Length
= getCurFilenameLength();
1063 FilenameBuf
= (char *)malloc(Length
+ 1);
1065 PROF_ERR("Failed to %s\n", "allocate memory.");
1068 Filename
= getCurFilename(FilenameBuf
, 1);
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);
1092 } else if (hasCommandLineOverrider
) {
1093 SelectedPat
= INSTR_PROF_PROFILE_NAME_VAR
;
1094 PNS
= PNS_command_line
;
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())
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) {
1131 const char *Filename
;
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");
1140 lprofRestoreSigKill();
1144 Length
= getCurFilenameLength();
1145 FilenameBuf
= (char *)COMPILER_RT_ALLOCA(Length
+ 1);
1146 Filename
= getCurFilename(FilenameBuf
, 0);
1148 /* Check the filename. */
1150 PROF_ERR("Failed to write file : %s\n", "Filename not set");
1152 lprofRestoreSigKill();
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()));
1163 lprofRestoreSigKill();
1167 /* Write profile data to the file. */
1168 rc
= writeFile(Filename
);
1170 PROF_ERR("Failed to write file \"%s\": %s\n", Filename
, strerror(errno
));
1174 lprofRestoreSigKill();
1179 COMPILER_RT_VISIBILITY
1180 int __llvm_profile_dump(void) {
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);
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
;
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. */
1210 PROF_ERR("Failed to write file : %s\n", "Filename not set");
1212 lprofRestoreSigKill();
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()));
1228 lprofRestoreSigKill();
1232 /* Write order data to the file. */
1233 rc
= writeOrderFile(Filename
);
1235 PROF_ERR("Failed to write file \"%s\": %s\n", Filename
, strerror(errno
));
1239 lprofRestoreSigKill();
1244 COMPILER_RT_VISIBILITY
1245 int __llvm_orderfile_dump(void) {
1246 int rc
= __llvm_orderfile_write_file();
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
)
1259 lprofSetupValueProfiler();
1261 HasBeenRegistered
= 1;
1262 return lprofAtExit(writeFileWithoutReturn
);
1265 COMPILER_RT_VISIBILITY
int __llvm_profile_set_file_object(FILE *File
,
1267 if (__llvm_profile_is_continuous_mode_enabled()) {
1269 PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported in "
1270 "continuous sync mode when merging is disabled\n",
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
);
1283 if (ProfileFileSize
== 0) {
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
),
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
);
1303 (void)munmap(ProfileBuffer
, ProfileFileSize
);
1305 mmapForContinuousMode(0, File
);
1306 lprofUnlockFileHandle(File
);
1308 setProfileFile(File
);
1309 setProfileMergeRequested(EnableMerge
);