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