1 /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
3 |* The LLVM Compiler Infrastructure
5 |* This file is distributed under the University of Illinois Open Source
6 |* License. See LICENSE.TXT for details.
8 \*===----------------------------------------------------------------------===*/
10 #include "InstrProfiling.h"
11 #include "InstrProfilingInternal.h"
12 #include "InstrProfilingUtil.h"
18 #define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
20 /* Return 1 if there is an error, otherwise return 0. */
21 static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
24 FILE *File = (FILE *)*WriterCtx;
25 for (I = 0; I < NumIOVecs; I++) {
26 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
33 COMPILER_RT_VISIBILITY ProfBufferIO *
34 llvmCreateBufferIOInternal(void *File, uint32_t BufferSz) {
37 return llvmCreateBufferIO(fileWriter, File, BufferSz);
40 static int writeFile(FILE *File) {
41 const char *BufferSzStr = 0;
42 uint64_t ValueDataSize = 0;
43 struct ValueProfData **ValueDataArray =
44 __llvm_profile_gather_value_data(&ValueDataSize);
47 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
48 if (BufferSzStr && BufferSzStr[0])
49 VPBufferSize = atoi(BufferSzStr);
50 return llvmWriteProfData(fileWriter, File, ValueDataArray, ValueDataSize);
53 static int writeFileWithName(const char *OutputName) {
56 if (!OutputName || !OutputName[0])
59 /* Append to the file to support profiling multiple shared objects. */
60 OutputFile = fopen(OutputName, "ab");
64 RetVal = writeFile(OutputFile);
70 COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
71 COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
73 static void truncateCurrentFile(void) {
77 Filename = __llvm_profile_CurrentFilename;
78 if (!Filename || !Filename[0])
81 /* Create the directory holding the file, if needed. */
82 if (strchr(Filename, '/')) {
83 char *Copy = malloc(strlen(Filename) + 1);
84 strcpy(Copy, Filename);
85 __llvm_profile_recursive_mkdir(Copy);
89 /* Truncate the file. Later we'll reopen and append. */
90 File = fopen(Filename, "w");
96 static void setFilename(const char *Filename, int OwnsFilename) {
97 /* Check if this is a new filename and therefore needs truncation. */
98 int NewFile = !__llvm_profile_CurrentFilename ||
99 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
100 if (__llvm_profile_OwnsFilename)
101 free(UNCONST(__llvm_profile_CurrentFilename));
103 __llvm_profile_CurrentFilename = Filename;
104 __llvm_profile_OwnsFilename = OwnsFilename;
106 /* If not a new file, append to support profiling multiple shared objects. */
108 truncateCurrentFile();
111 static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
114 static int setFilenamePossiblyWithPid(const char *Filename) {
115 #define MAX_PID_SIZE 16
116 char PidChars[MAX_PID_SIZE] = {0};
117 int NumPids = 0, PidLength = 0;
121 /* Reset filename on NULL, except with env var which is checked by caller. */
123 resetFilenameToDefault();
127 /* Check the filename for "%p", which indicates a pid-substitution. */
128 for (I = 0; Filename[I]; ++I)
129 if (Filename[I] == '%' && Filename[++I] == 'p')
131 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
136 setFilename(Filename, 0);
140 /* Allocate enough space for the substituted filename. */
141 Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
145 /* Construct the new filename. */
146 for (I = 0, J = 0; Filename[I]; ++I)
147 if (Filename[I] == '%') {
148 if (Filename[++I] == 'p') {
149 memcpy(Allocated + J, PidChars, PidLength);
152 /* Drop any unknown substitutions. */
154 Allocated[J++] = Filename[I];
157 /* Use the computed name. */
158 setFilename(Allocated, 1);
162 static int setFilenameFromEnvironment(void) {
163 const char *Filename = getenv("LLVM_PROFILE_FILE");
165 if (!Filename || !Filename[0])
168 return setFilenamePossiblyWithPid(Filename);
171 static void setFilenameAutomatically(void) {
172 if (!setFilenameFromEnvironment())
175 resetFilenameToDefault();
178 COMPILER_RT_VISIBILITY
179 void __llvm_profile_initialize_file(void) {
180 /* Check if the filename has been initialized. */
181 if (__llvm_profile_CurrentFilename)
184 /* Detect the filename and truncate. */
185 setFilenameAutomatically();
188 COMPILER_RT_VISIBILITY
189 void __llvm_profile_set_filename(const char *Filename) {
190 setFilenamePossiblyWithPid(Filename);
193 COMPILER_RT_VISIBILITY
194 void __llvm_profile_override_default_filename(const char *Filename) {
195 /* If the env var is set, skip setting filename from argument. */
196 const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
197 if (Env_Filename && Env_Filename[0])
199 setFilenamePossiblyWithPid(Filename);
202 COMPILER_RT_VISIBILITY
203 int __llvm_profile_write_file(void) {
206 GetEnvHook = &getenv;
207 /* Check the filename. */
208 if (!__llvm_profile_CurrentFilename) {
209 PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set");
213 /* Write the file. */
214 rc = writeFileWithName(__llvm_profile_CurrentFilename);
216 PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n",
217 __llvm_profile_CurrentFilename, strerror(errno));
221 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
223 COMPILER_RT_VISIBILITY
224 int __llvm_profile_register_write_file_atexit(void) {
225 static int HasBeenRegistered = 0;
227 if (HasBeenRegistered)
230 HasBeenRegistered = 1;
231 return atexit(writeFileWithoutReturn);