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 "InstrProfilingUtil.h"
17 #define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
19 static int writeFile(FILE *File
) {
20 /* Match logic in __llvm_profile_write_buffer(). */
21 const __llvm_profile_data
*DataBegin
= __llvm_profile_begin_data();
22 const __llvm_profile_data
*DataEnd
= __llvm_profile_end_data();
23 const uint64_t *CountersBegin
= __llvm_profile_begin_counters();
24 const uint64_t *CountersEnd
= __llvm_profile_end_counters();
25 const char *NamesBegin
= __llvm_profile_begin_names();
26 const char *NamesEnd
= __llvm_profile_end_names();
28 /* Calculate size of sections. */
29 const uint64_t DataSize
= DataEnd
- DataBegin
;
30 const uint64_t CountersSize
= CountersEnd
- CountersBegin
;
31 const uint64_t NamesSize
= NamesEnd
- NamesBegin
;
32 const uint64_t Padding
= sizeof(uint64_t) - NamesSize
% sizeof(uint64_t);
34 /* Enough zeroes for padding. */
35 const char Zeroes
[sizeof(uint64_t)] = {0};
37 /* Create the header. */
38 __llvm_profile_header Header
;
39 Header
.Magic
= __llvm_profile_get_magic();
40 Header
.Version
= __llvm_profile_get_version();
41 Header
.DataSize
= DataSize
;
42 Header
.CountersSize
= CountersSize
;
43 Header
.NamesSize
= NamesSize
;
44 Header
.CountersDelta
= (uintptr_t)CountersBegin
;
45 Header
.NamesDelta
= (uintptr_t)NamesBegin
;
48 #define CHECK_fwrite(Data, Size, Length, File) \
49 do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
50 CHECK_fwrite(&Header
, sizeof(__llvm_profile_header
), 1, File
);
51 CHECK_fwrite(DataBegin
, sizeof(__llvm_profile_data
), DataSize
, File
);
52 CHECK_fwrite(CountersBegin
, sizeof(uint64_t), CountersSize
, File
);
53 CHECK_fwrite(NamesBegin
, sizeof(char), NamesSize
, File
);
54 CHECK_fwrite(Zeroes
, sizeof(char), Padding
, File
);
60 static int writeFileWithName(const char *OutputName
) {
63 if (!OutputName
|| !OutputName
[0])
66 /* Append to the file to support profiling multiple shared objects. */
67 OutputFile
= fopen(OutputName
, "a");
71 RetVal
= writeFile(OutputFile
);
77 __attribute__((weak
)) int __llvm_profile_OwnsFilename
= 0;
78 __attribute__((weak
)) const char *__llvm_profile_CurrentFilename
= NULL
;
80 static void truncateCurrentFile(void) {
84 Filename
= __llvm_profile_CurrentFilename
;
85 if (!Filename
|| !Filename
[0])
88 /* Create the directory holding the file, if needed. */
89 if (strchr(Filename
, '/')) {
90 char *Copy
= malloc(strlen(Filename
) + 1);
91 strcpy(Copy
, Filename
);
92 __llvm_profile_recursive_mkdir(Copy
);
96 /* Truncate the file. Later we'll reopen and append. */
97 File
= fopen(Filename
, "w");
103 static void setFilename(const char *Filename
, int OwnsFilename
) {
104 /* Check if this is a new filename and therefore needs truncation. */
105 int NewFile
= !__llvm_profile_CurrentFilename
||
106 (Filename
&& strcmp(Filename
, __llvm_profile_CurrentFilename
));
107 if (__llvm_profile_OwnsFilename
)
108 free(UNCONST(__llvm_profile_CurrentFilename
));
110 __llvm_profile_CurrentFilename
= Filename
;
111 __llvm_profile_OwnsFilename
= OwnsFilename
;
113 /* If not a new file, append to support profiling multiple shared objects. */
115 truncateCurrentFile();
118 static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
121 static int setFilenamePossiblyWithPid(const char *Filename
) {
122 #define MAX_PID_SIZE 16
123 char PidChars
[MAX_PID_SIZE
] = {0};
124 int NumPids
= 0, PidLength
= 0;
128 /* Reset filename on NULL, except with env var which is checked by caller. */
130 resetFilenameToDefault();
134 /* Check the filename for "%p", which indicates a pid-substitution. */
135 for (I
= 0; Filename
[I
]; ++I
)
136 if (Filename
[I
] == '%' && Filename
[++I
] == 'p')
138 PidLength
= snprintf(PidChars
, MAX_PID_SIZE
, "%d", getpid());
143 setFilename(Filename
, 0);
147 /* Allocate enough space for the substituted filename. */
148 Allocated
= malloc(I
+ NumPids
*(PidLength
- 2) + 1);
152 /* Construct the new filename. */
153 for (I
= 0, J
= 0; Filename
[I
]; ++I
)
154 if (Filename
[I
] == '%') {
155 if (Filename
[++I
] == 'p') {
156 memcpy(Allocated
+ J
, PidChars
, PidLength
);
159 /* Drop any unknown substitutions. */
161 Allocated
[J
++] = Filename
[I
];
164 /* Use the computed name. */
165 setFilename(Allocated
, 1);
169 static int setFilenameFromEnvironment(void) {
170 const char *Filename
= getenv("LLVM_PROFILE_FILE");
172 if (!Filename
|| !Filename
[0])
175 return setFilenamePossiblyWithPid(Filename
);
178 static void setFilenameAutomatically(void) {
179 if (!setFilenameFromEnvironment())
182 resetFilenameToDefault();
185 __attribute__((visibility("hidden")))
186 void __llvm_profile_initialize_file(void) {
187 /* Check if the filename has been initialized. */
188 if (__llvm_profile_CurrentFilename
)
191 /* Detect the filename and truncate. */
192 setFilenameAutomatically();
195 __attribute__((visibility("hidden")))
196 void __llvm_profile_set_filename(const char *Filename
) {
197 setFilenamePossiblyWithPid(Filename
);
200 __attribute__((visibility("hidden")))
201 void __llvm_profile_override_default_filename(const char *Filename
) {
202 /* If the env var is set, skip setting filename from argument. */
203 const char *Env_Filename
= getenv("LLVM_PROFILE_FILE");
204 if (Env_Filename
&& Env_Filename
[0])
206 setFilenamePossiblyWithPid(Filename
);
209 __attribute__((visibility("hidden")))
210 int __llvm_profile_write_file(void) {
213 /* Check the filename. */
214 if (!__llvm_profile_CurrentFilename
)
217 /* Write the file. */
218 rc
= writeFileWithName(__llvm_profile_CurrentFilename
);
219 if (rc
&& getenv("LLVM_PROFILE_VERBOSE_ERRORS"))
220 fprintf(stderr
, "LLVM Profile: Failed to write file \"%s\": %s\n",
221 __llvm_profile_CurrentFilename
, strerror(errno
));
225 static void writeFileWithoutReturn(void) {
226 __llvm_profile_write_file();
229 __attribute__((visibility("hidden")))
230 int __llvm_profile_register_write_file_atexit(void) {
231 static int HasBeenRegistered
= 0;
233 if (HasBeenRegistered
)
236 HasBeenRegistered
= 1;
237 return atexit(writeFileWithoutReturn
);