xref: /freebsd/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingFile.c (revision f2530c80db7b29b95368fce956b3a778f096b368)
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 \*===----------------------------------------------------------------------===*/
8 
9 #if !defined(__Fuchsia__)
10 
11 #include <errno.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #ifdef _MSC_VER
16 /* For _alloca. */
17 #include <malloc.h>
18 #endif
19 #if defined(_WIN32)
20 #include "WindowsMMap.h"
21 /* For _chsize_s */
22 #include <io.h>
23 #include <process.h>
24 #else
25 #include <sys/file.h>
26 #include <sys/mman.h>
27 #include <unistd.h>
28 #if defined(__linux__)
29 #include <sys/types.h>
30 #endif
31 #endif
32 
33 #include "InstrProfiling.h"
34 #include "InstrProfilingInternal.h"
35 #include "InstrProfilingUtil.h"
36 
37 /* From where is profile name specified.
38  * The order the enumerators define their
39  * precedence. Re-order them may lead to
40  * runtime behavior change. */
41 typedef enum ProfileNameSpecifier {
42   PNS_unknown = 0,
43   PNS_default,
44   PNS_command_line,
45   PNS_environment,
46   PNS_runtime_api
47 } ProfileNameSpecifier;
48 
49 static const char *getPNSStr(ProfileNameSpecifier PNS) {
50   switch (PNS) {
51   case PNS_default:
52     return "default setting";
53   case PNS_command_line:
54     return "command line";
55   case PNS_environment:
56     return "environment variable";
57   case PNS_runtime_api:
58     return "runtime API";
59   default:
60     return "Unknown";
61   }
62 }
63 
64 #define MAX_PID_SIZE 16
65 /* Data structure holding the result of parsed filename pattern. */
66 typedef struct lprofFilename {
67   /* File name string possibly with %p or %h specifiers. */
68   const char *FilenamePat;
69   /* A flag indicating if FilenamePat's memory is allocated
70    * by runtime. */
71   unsigned OwnsFilenamePat;
72   const char *ProfilePathPrefix;
73   const char *Filename;
74   char PidChars[MAX_PID_SIZE];
75   char Hostname[COMPILER_RT_MAX_HOSTLEN];
76   unsigned NumPids;
77   unsigned NumHosts;
78   /* When in-process merging is enabled, this parameter specifies
79    * the total number of profile data files shared by all the processes
80    * spawned from the same binary. By default the value is 1. If merging
81    * is not enabled, its value should be 0. This parameter is specified
82    * by the %[0-9]m specifier. For instance %2m enables merging using
83    * 2 profile data files. %1m is equivalent to %m. Also %m specifier
84    * can only appear once at the end of the name pattern. */
85   unsigned MergePoolSize;
86   ProfileNameSpecifier PNS;
87 } lprofFilename;
88 
89 COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0,   0, 0, 0, {0},
90                                                    {0}, 0, 0, 0, PNS_unknown};
91 
92 static int ProfileMergeRequested = 0;
93 static int isProfileMergeRequested() { return ProfileMergeRequested; }
94 static void setProfileMergeRequested(int EnableMerge) {
95   ProfileMergeRequested = EnableMerge;
96 }
97 
98 static FILE *ProfileFile = NULL;
99 static FILE *getProfileFile() { return ProfileFile; }
100 static void setProfileFile(FILE *File) { ProfileFile = File; }
101 
102 COMPILER_RT_VISIBILITY void __llvm_profile_set_file_object(FILE *File,
103                                                            int EnableMerge) {
104   setProfileFile(File);
105   setProfileMergeRequested(EnableMerge);
106 }
107 
108 static int getCurFilenameLength();
109 static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf);
110 static unsigned doMerging() {
111   return lprofCurFilename.MergePoolSize || isProfileMergeRequested();
112 }
113 
114 /* Return 1 if there is an error, otherwise return  0.  */
115 static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
116                            uint32_t NumIOVecs) {
117   uint32_t I;
118   FILE *File = (FILE *)This->WriterCtx;
119   for (I = 0; I < NumIOVecs; I++) {
120     if (IOVecs[I].Data) {
121       if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
122           IOVecs[I].NumElm)
123         return 1;
124     } else {
125       if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1)
126         return 1;
127     }
128   }
129   return 0;
130 }
131 
132 /* TODO: make buffer size controllable by an internal option, and compiler can pass the size
133    to runtime via a variable. */
134 static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) {
135   if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) !=
136       INSTR_ORDER_FILE_BUFFER_SIZE)
137     return 1;
138   return 0;
139 }
140 
141 static void initFileWriter(ProfDataWriter *This, FILE *File) {
142   This->Write = fileWriter;
143   This->WriterCtx = File;
144 }
145 
146 COMPILER_RT_VISIBILITY ProfBufferIO *
147 lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
148   FreeHook = &free;
149   DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1);
150   VPBufferSize = BufferSz;
151   ProfDataWriter *fileWriter =
152       (ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1);
153   initFileWriter(fileWriter, File);
154   ProfBufferIO *IO = lprofCreateBufferIO(fileWriter);
155   IO->OwnFileWriter = 1;
156   return IO;
157 }
158 
159 static void setupIOBuffer() {
160   const char *BufferSzStr = 0;
161   BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
162   if (BufferSzStr && BufferSzStr[0]) {
163     VPBufferSize = atoi(BufferSzStr);
164     DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
165   }
166 }
167 
168 /* Read profile data in \c ProfileFile and merge with in-memory
169    profile counters. Returns -1 if there is fatal error, otheriwse
170    0 is returned. Returning 0 does not mean merge is actually
171    performed. If merge is actually done, *MergeDone is set to 1.
172 */
173 static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
174   uint64_t ProfileFileSize;
175   char *ProfileBuffer;
176 
177   if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
178     PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
179              strerror(errno));
180     return -1;
181   }
182   ProfileFileSize = ftell(ProfileFile);
183 
184   /* Restore file offset.  */
185   if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
186     PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
187              strerror(errno));
188     return -1;
189   }
190 
191   /* Nothing to merge.  */
192   if (ProfileFileSize < sizeof(__llvm_profile_header)) {
193     if (ProfileFileSize)
194       PROF_WARN("Unable to merge profile data: %s\n",
195                 "source profile file is too small.");
196     return 0;
197   }
198 
199   ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
200                        fileno(ProfileFile), 0);
201   if (ProfileBuffer == MAP_FAILED) {
202     PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
203              strerror(errno));
204     return -1;
205   }
206 
207   if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) {
208     (void)munmap(ProfileBuffer, ProfileFileSize);
209     PROF_WARN("Unable to merge profile data: %s\n",
210               "source profile file is not compatible.");
211     return 0;
212   }
213 
214   /* Now start merging */
215   __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
216 
217   // Truncate the file in case merging of value profile did not happend to
218   // prevent from leaving garbage data at the end of the profile file.
219   COMPILER_RT_FTRUNCATE(ProfileFile, __llvm_profile_get_size_for_buffer());
220 
221   (void)munmap(ProfileBuffer, ProfileFileSize);
222   *MergeDone = 1;
223 
224   return 0;
225 }
226 
227 /* Create the directory holding the file, if needed. */
228 static void createProfileDir(const char *Filename) {
229   size_t Length = strlen(Filename);
230   if (lprofFindFirstDirSeparator(Filename)) {
231     char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
232     strncpy(Copy, Filename, Length + 1);
233     __llvm_profile_recursive_mkdir(Copy);
234   }
235 }
236 
237 /* Open the profile data for merging. It opens the file in r+b mode with
238  * file locking.  If the file has content which is compatible with the
239  * current process, it also reads in the profile data in the file and merge
240  * it with in-memory counters. After the profile data is merged in memory,
241  * the original profile data is truncated and gets ready for the profile
242  * dumper. With profile merging enabled, each executable as well as any of
243  * its instrumented shared libraries dump profile data into their own data file.
244 */
245 static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) {
246   FILE *ProfileFile = NULL;
247   int rc;
248 
249   ProfileFile = getProfileFile();
250   if (ProfileFile) {
251     lprofLockFileHandle(ProfileFile);
252   } else {
253     createProfileDir(ProfileFileName);
254     ProfileFile = lprofOpenFileEx(ProfileFileName);
255   }
256   if (!ProfileFile)
257     return NULL;
258 
259   rc = doProfileMerging(ProfileFile, MergeDone);
260   if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) ||
261       fseek(ProfileFile, 0L, SEEK_SET) == -1) {
262     PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
263              strerror(errno));
264     fclose(ProfileFile);
265     return NULL;
266   }
267   return ProfileFile;
268 }
269 
270 static FILE *getFileObject(const char *OutputName) {
271   FILE *File;
272   File = getProfileFile();
273   if (File != NULL) {
274     return File;
275   }
276 
277   return fopen(OutputName, "ab");
278 }
279 
280 /* Write profile data to file \c OutputName.  */
281 static int writeFile(const char *OutputName) {
282   int RetVal;
283   FILE *OutputFile;
284 
285   int MergeDone = 0;
286   VPMergeHook = &lprofMergeValueProfData;
287   if (doMerging())
288     OutputFile = openFileForMerging(OutputName, &MergeDone);
289   else
290     OutputFile = getFileObject(OutputName);
291 
292   if (!OutputFile)
293     return -1;
294 
295   FreeHook = &free;
296   setupIOBuffer();
297   ProfDataWriter fileWriter;
298   initFileWriter(&fileWriter, OutputFile);
299   RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);
300 
301   if (OutputFile == getProfileFile()) {
302     fflush(OutputFile);
303     if (doMerging()) {
304       lprofUnlockFileHandle(OutputFile);
305     }
306   } else {
307     fclose(OutputFile);
308   }
309 
310   return RetVal;
311 }
312 
313 /* Write order data to file \c OutputName.  */
314 static int writeOrderFile(const char *OutputName) {
315   int RetVal;
316   FILE *OutputFile;
317 
318   OutputFile = fopen(OutputName, "w");
319 
320   if (!OutputFile) {
321     PROF_WARN("can't open file with mode ab: %s\n", OutputName);
322     return -1;
323   }
324 
325   FreeHook = &free;
326   setupIOBuffer();
327   const uint32_t *DataBegin = __llvm_profile_begin_orderfile();
328   RetVal = orderFileWriter(OutputFile, DataBegin);
329 
330   fclose(OutputFile);
331   return RetVal;
332 }
333 
334 static void truncateCurrentFile(void) {
335   const char *Filename;
336   char *FilenameBuf;
337   FILE *File;
338   int Length;
339 
340   Length = getCurFilenameLength();
341   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
342   Filename = getCurFilename(FilenameBuf, 0);
343   if (!Filename)
344     return;
345 
346   /* By pass file truncation to allow online raw profile
347    * merging. */
348   if (lprofCurFilename.MergePoolSize)
349     return;
350 
351   createProfileDir(Filename);
352 
353   /* Truncate the file.  Later we'll reopen and append. */
354   File = fopen(Filename, "w");
355   if (!File)
356     return;
357   fclose(File);
358 }
359 
360 static const char *DefaultProfileName = "default.profraw";
361 static void resetFilenameToDefault(void) {
362   if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
363     free((void *)lprofCurFilename.FilenamePat);
364   }
365   memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
366   lprofCurFilename.FilenamePat = DefaultProfileName;
367   lprofCurFilename.PNS = PNS_default;
368 }
369 
370 static int containsMergeSpecifier(const char *FilenamePat, int I) {
371   return (FilenamePat[I] == 'm' ||
372           (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' &&
373            /* If FilenamePat[I] is not '\0', the next byte is guaranteed
374             * to be in-bound as the string is null terminated. */
375            FilenamePat[I + 1] == 'm'));
376 }
377 
378 /* Parses the pattern string \p FilenamePat and stores the result to
379  * lprofcurFilename structure. */
380 static int parseFilenamePattern(const char *FilenamePat,
381                                 unsigned CopyFilenamePat) {
382   int NumPids = 0, NumHosts = 0, I;
383   char *PidChars = &lprofCurFilename.PidChars[0];
384   char *Hostname = &lprofCurFilename.Hostname[0];
385   int MergingEnabled = 0;
386 
387   /* Clean up cached prefix and filename.  */
388   if (lprofCurFilename.ProfilePathPrefix)
389     free((void *)lprofCurFilename.ProfilePathPrefix);
390   if (lprofCurFilename.Filename)
391     free((void *)lprofCurFilename.Filename);
392 
393   if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
394     free((void *)lprofCurFilename.FilenamePat);
395   }
396 
397   memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
398 
399   if (!CopyFilenamePat)
400     lprofCurFilename.FilenamePat = FilenamePat;
401   else {
402     lprofCurFilename.FilenamePat = strdup(FilenamePat);
403     lprofCurFilename.OwnsFilenamePat = 1;
404   }
405   /* Check the filename for "%p", which indicates a pid-substitution. */
406   for (I = 0; FilenamePat[I]; ++I)
407     if (FilenamePat[I] == '%') {
408       if (FilenamePat[++I] == 'p') {
409         if (!NumPids++) {
410           if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) {
411             PROF_WARN("Unable to get pid for filename pattern %s. Using the "
412                       "default name.",
413                       FilenamePat);
414             return -1;
415           }
416         }
417       } else if (FilenamePat[I] == 'h') {
418         if (!NumHosts++)
419           if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {
420             PROF_WARN("Unable to get hostname for filename pattern %s. Using "
421                       "the default name.",
422                       FilenamePat);
423             return -1;
424           }
425       } else if (containsMergeSpecifier(FilenamePat, I)) {
426         if (MergingEnabled) {
427           PROF_WARN("%%m specifier can only be specified once in %s.\n",
428                     FilenamePat);
429           return -1;
430         }
431         MergingEnabled = 1;
432         if (FilenamePat[I] == 'm')
433           lprofCurFilename.MergePoolSize = 1;
434         else {
435           lprofCurFilename.MergePoolSize = FilenamePat[I] - '0';
436           I++; /* advance to 'm' */
437         }
438       }
439     }
440 
441   lprofCurFilename.NumPids = NumPids;
442   lprofCurFilename.NumHosts = NumHosts;
443   return 0;
444 }
445 
446 static void parseAndSetFilename(const char *FilenamePat,
447                                 ProfileNameSpecifier PNS,
448                                 unsigned CopyFilenamePat) {
449 
450   const char *OldFilenamePat = lprofCurFilename.FilenamePat;
451   ProfileNameSpecifier OldPNS = lprofCurFilename.PNS;
452 
453   if (PNS < OldPNS)
454     return;
455 
456   if (!FilenamePat)
457     FilenamePat = DefaultProfileName;
458 
459   if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) {
460     lprofCurFilename.PNS = PNS;
461     return;
462   }
463 
464   /* When PNS >= OldPNS, the last one wins. */
465   if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat))
466     resetFilenameToDefault();
467   lprofCurFilename.PNS = PNS;
468 
469   if (!OldFilenamePat) {
470     if (getenv("LLVM_PROFILE_VERBOSE"))
471       PROF_NOTE("Set profile file path to \"%s\" via %s.\n",
472                 lprofCurFilename.FilenamePat, getPNSStr(PNS));
473   } else {
474     if (getenv("LLVM_PROFILE_VERBOSE"))
475       PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",
476                 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat,
477                 getPNSStr(PNS));
478   }
479 
480   truncateCurrentFile();
481 }
482 
483 /* Return buffer length that is required to store the current profile
484  * filename with PID and hostname substitutions. */
485 /* The length to hold uint64_t followed by 2 digit pool id including '_' */
486 #define SIGLEN 24
487 static int getCurFilenameLength() {
488   int Len;
489   if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
490     return 0;
491 
492   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
493         lprofCurFilename.MergePoolSize))
494     return strlen(lprofCurFilename.FilenamePat);
495 
496   Len = strlen(lprofCurFilename.FilenamePat) +
497         lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
498         lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2);
499   if (lprofCurFilename.MergePoolSize)
500     Len += SIGLEN;
501   return Len;
502 }
503 
504 /* Return the pointer to the current profile file name (after substituting
505  * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
506  * to store the resulting filename. If no substitution is needed, the
507  * current filename pattern string is directly returned, unless ForceUseBuf
508  * is enabled. */
509 static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {
510   int I, J, PidLength, HostNameLength, FilenamePatLength;
511   const char *FilenamePat = lprofCurFilename.FilenamePat;
512 
513   if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
514     return 0;
515 
516   if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
517         lprofCurFilename.MergePoolSize)) {
518     if (!ForceUseBuf)
519       return lprofCurFilename.FilenamePat;
520 
521     FilenamePatLength = strlen(lprofCurFilename.FilenamePat);
522     memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength);
523     FilenameBuf[FilenamePatLength] = '\0';
524     return FilenameBuf;
525   }
526 
527   PidLength = strlen(lprofCurFilename.PidChars);
528   HostNameLength = strlen(lprofCurFilename.Hostname);
529   /* Construct the new filename. */
530   for (I = 0, J = 0; FilenamePat[I]; ++I)
531     if (FilenamePat[I] == '%') {
532       if (FilenamePat[++I] == 'p') {
533         memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength);
534         J += PidLength;
535       } else if (FilenamePat[I] == 'h') {
536         memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
537         J += HostNameLength;
538       } else if (containsMergeSpecifier(FilenamePat, I)) {
539         char LoadModuleSignature[SIGLEN];
540         int S;
541         int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize;
542         S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d",
543                      lprofGetLoadModuleSignature(), ProfilePoolId);
544         if (S == -1 || S > SIGLEN)
545           S = SIGLEN;
546         memcpy(FilenameBuf + J, LoadModuleSignature, S);
547         J += S;
548         if (FilenamePat[I] != 'm')
549           I++;
550       }
551       /* Drop any unknown substitutions. */
552     } else
553       FilenameBuf[J++] = FilenamePat[I];
554   FilenameBuf[J] = 0;
555 
556   return FilenameBuf;
557 }
558 
559 /* Returns the pointer to the environment variable
560  * string. Returns null if the env var is not set. */
561 static const char *getFilenamePatFromEnv(void) {
562   const char *Filename = getenv("LLVM_PROFILE_FILE");
563   if (!Filename || !Filename[0])
564     return 0;
565   return Filename;
566 }
567 
568 COMPILER_RT_VISIBILITY
569 const char *__llvm_profile_get_path_prefix(void) {
570   int Length;
571   char *FilenameBuf, *Prefix;
572   const char *Filename, *PrefixEnd;
573 
574   if (lprofCurFilename.ProfilePathPrefix)
575     return lprofCurFilename.ProfilePathPrefix;
576 
577   Length = getCurFilenameLength();
578   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
579   Filename = getCurFilename(FilenameBuf, 0);
580   if (!Filename)
581     return "\0";
582 
583   PrefixEnd = lprofFindLastDirSeparator(Filename);
584   if (!PrefixEnd)
585     return "\0";
586 
587   Length = PrefixEnd - Filename + 1;
588   Prefix = (char *)malloc(Length + 1);
589   if (!Prefix) {
590     PROF_ERR("Failed to %s\n", "allocate memory.");
591     return "\0";
592   }
593   memcpy(Prefix, Filename, Length);
594   Prefix[Length] = '\0';
595   lprofCurFilename.ProfilePathPrefix = Prefix;
596   return Prefix;
597 }
598 
599 COMPILER_RT_VISIBILITY
600 const char *__llvm_profile_get_filename(void) {
601   int Length;
602   char *FilenameBuf;
603   const char *Filename;
604 
605   if (lprofCurFilename.Filename)
606     return lprofCurFilename.Filename;
607 
608   Length = getCurFilenameLength();
609   FilenameBuf = (char *)malloc(Length + 1);
610   if (!FilenameBuf) {
611     PROF_ERR("Failed to %s\n", "allocate memory.");
612     return "\0";
613   }
614   Filename = getCurFilename(FilenameBuf, 1);
615   if (!Filename)
616     return "\0";
617 
618   lprofCurFilename.Filename = FilenameBuf;
619   return FilenameBuf;
620 }
621 
622 /* This method is invoked by the runtime initialization hook
623  * InstrProfilingRuntime.o if it is linked in. Both user specified
624  * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
625  * environment variable can override this default value. */
626 COMPILER_RT_VISIBILITY
627 void __llvm_profile_initialize_file(void) {
628   const char *EnvFilenamePat;
629   const char *SelectedPat = NULL;
630   ProfileNameSpecifier PNS = PNS_unknown;
631   int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0);
632 
633   EnvFilenamePat = getFilenamePatFromEnv();
634   if (EnvFilenamePat) {
635     /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid
636        at the  moment when __llvm_profile_write_file() gets executed. */
637     parseAndSetFilename(EnvFilenamePat, PNS_environment, 1);
638     return;
639   } else if (hasCommandLineOverrider) {
640     SelectedPat = INSTR_PROF_PROFILE_NAME_VAR;
641     PNS = PNS_command_line;
642   } else {
643     SelectedPat = NULL;
644     PNS = PNS_default;
645   }
646 
647   parseAndSetFilename(SelectedPat, PNS, 0);
648 }
649 
650 /* This API is directly called by the user application code. It has the
651  * highest precedence compared with LLVM_PROFILE_FILE environment variable
652  * and command line option -fprofile-instr-generate=<profile_name>.
653  */
654 COMPILER_RT_VISIBILITY
655 void __llvm_profile_set_filename(const char *FilenamePat) {
656   parseAndSetFilename(FilenamePat, PNS_runtime_api, 1);
657 }
658 
659 /* The public API for writing profile data into the file with name
660  * set by previous calls to __llvm_profile_set_filename or
661  * __llvm_profile_override_default_filename or
662  * __llvm_profile_initialize_file. */
663 COMPILER_RT_VISIBILITY
664 int __llvm_profile_write_file(void) {
665   int rc, Length;
666   const char *Filename;
667   char *FilenameBuf;
668   int PDeathSig = 0;
669 
670   if (lprofProfileDumped()) {
671     PROF_NOTE("Profile data not written to file: %s.\n", "already written");
672     return 0;
673   }
674 
675   Length = getCurFilenameLength();
676   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
677   Filename = getCurFilename(FilenameBuf, 0);
678 
679   /* Check the filename. */
680   if (!Filename) {
681     PROF_ERR("Failed to write file : %s\n", "Filename not set");
682     return -1;
683   }
684 
685   /* Check if there is llvm/runtime version mismatch.  */
686   if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
687     PROF_ERR("Runtime and instrumentation version mismatch : "
688              "expected %d, but get %d\n",
689              INSTR_PROF_RAW_VERSION,
690              (int)GET_VERSION(__llvm_profile_get_version()));
691     return -1;
692   }
693 
694   // Temporarily suspend getting SIGKILL when the parent exits.
695   PDeathSig = lprofSuspendSigKill();
696 
697   /* Write profile data to the file. */
698   rc = writeFile(Filename);
699   if (rc)
700     PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
701 
702   // Restore SIGKILL.
703   if (PDeathSig == 1)
704     lprofRestoreSigKill();
705 
706   return rc;
707 }
708 
709 COMPILER_RT_VISIBILITY
710 int __llvm_profile_dump(void) {
711   if (!doMerging())
712     PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering "
713               " of previously dumped profile data : %s. Either use %%m "
714               "in profile name or change profile name before dumping.\n",
715               "online profile merging is not on");
716   int rc = __llvm_profile_write_file();
717   lprofSetProfileDumped();
718   return rc;
719 }
720 
721 /* Order file data will be saved in a file with suffx .order. */
722 static const char *OrderFileSuffix = ".order";
723 
724 COMPILER_RT_VISIBILITY
725 int __llvm_orderfile_write_file(void) {
726   int rc, Length, LengthBeforeAppend, SuffixLength;
727   const char *Filename;
728   char *FilenameBuf;
729   int PDeathSig = 0;
730 
731   SuffixLength = strlen(OrderFileSuffix);
732   Length = getCurFilenameLength() + SuffixLength;
733   FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
734   Filename = getCurFilename(FilenameBuf, 1);
735 
736   /* Check the filename. */
737   if (!Filename) {
738     PROF_ERR("Failed to write file : %s\n", "Filename not set");
739     return -1;
740   }
741 
742   /* Append order file suffix */
743   LengthBeforeAppend = strlen(Filename);
744   memcpy(FilenameBuf + LengthBeforeAppend, OrderFileSuffix, SuffixLength);
745   FilenameBuf[LengthBeforeAppend + SuffixLength] = '\0';
746 
747   /* Check if there is llvm/runtime version mismatch.  */
748   if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
749     PROF_ERR("Runtime and instrumentation version mismatch : "
750              "expected %d, but get %d\n",
751              INSTR_PROF_RAW_VERSION,
752              (int)GET_VERSION(__llvm_profile_get_version()));
753     return -1;
754   }
755 
756   // Temporarily suspend getting SIGKILL when the parent exits.
757   PDeathSig = lprofSuspendSigKill();
758 
759   /* Write order data to the file. */
760   rc = writeOrderFile(Filename);
761   if (rc)
762     PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
763 
764   // Restore SIGKILL.
765   if (PDeathSig == 1)
766     lprofRestoreSigKill();
767 
768   return rc;
769 }
770 
771 COMPILER_RT_VISIBILITY
772 int __llvm_orderfile_dump(void) {
773   int rc = __llvm_orderfile_write_file();
774   return rc;
775 }
776 
777 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
778 
779 COMPILER_RT_VISIBILITY
780 int __llvm_profile_register_write_file_atexit(void) {
781   static int HasBeenRegistered = 0;
782 
783   if (HasBeenRegistered)
784     return 0;
785 
786   lprofSetupValueProfiler();
787 
788   HasBeenRegistered = 1;
789   return atexit(writeFileWithoutReturn);
790 }
791 
792 #endif
793