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