blob: 940223829f835d86d7522c6ca7226a77bac47eb1 [file] [log] [blame]
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +00001/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +00002|*
3|* The LLVM Compiler Infrastructure
4|*
5|* This file is distributed under the University of Illinois Open Source
6|* License. See LICENSE.TXT for details.
7|*
8\*===----------------------------------------------------------------------===*/
9
10#include "InstrProfiling.h"
Diego Novilloeae95142015-07-09 17:21:52 +000011#include "InstrProfilingUtil.h"
Joerg Sonnenbergeref24b412015-03-09 11:23:29 +000012#include <errno.h>
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000013#include <stdio.h>
14#include <stdlib.h>
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000015#include <string.h>
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000016
Joerg Sonnenbergerb1cc6d52014-05-20 16:37:07 +000017#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
18
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000019static int writeFile(FILE *File) {
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000020 /* Match logic in __llvm_profile_write_buffer(). */
Justin Bognercc0d7ee2014-09-04 15:45:31 +000021 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();
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000027
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;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000032 const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
33
34 /* Enough zeroes for padding. */
35 const char Zeroes[sizeof(uint64_t)] = {0};
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000036
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000037 /* Create the header. */
Reid Kleckneraf6b2502014-05-01 18:52:14 +000038 uint64_t Header[PROFILE_HEADER_SIZE];
39 Header[0] = __llvm_profile_get_magic();
40 Header[1] = __llvm_profile_get_version();
41 Header[2] = DataSize;
42 Header[3] = CountersSize;
43 Header[4] = NamesSize;
44 Header[5] = (uintptr_t)CountersBegin;
45 Header[6] = (uintptr_t)NamesBegin;
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000046
47 /* Write the data. */
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000048#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(uint64_t), PROFILE_HEADER_SIZE, File);
51 CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000052 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000053 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000054 CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000055#undef CHECK_fwrite
56
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000057 return 0;
58}
59
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000060static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000061 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000062 FILE *OutputFile;
63 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000064 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000065
66 /* Append to the file to support profiling multiple shared objects. */
67 OutputFile = fopen(OutputName, "a");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000068 if (!OutputFile)
69 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000070
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000071 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000072
73 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000074 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000075}
76
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000077__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000078__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000079
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000080static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000081 const char *Filename;
82 FILE *File;
83
84 Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000085 if (!Filename || !Filename[0])
86 return;
87
Diego Novilloeae95142015-07-09 17:21:52 +000088 /* 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);
93 }
94
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000095 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000096 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000097 if (!File)
98 return;
99 fclose(File);
100}
101
Eric Christopherd641b532015-04-28 22:54:51 +0000102static void setFilename(const char *Filename, int OwnsFilename) {
103 /* Check if this is a new filename and therefore needs truncation. */
104 int NewFile = !__llvm_profile_CurrentFilename ||
105 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
106 if (__llvm_profile_OwnsFilename)
107 free(UNCONST(__llvm_profile_CurrentFilename));
108
109 __llvm_profile_CurrentFilename = Filename;
110 __llvm_profile_OwnsFilename = OwnsFilename;
111
112 /* If not a new file, append to support profiling multiple shared objects. */
113 if (NewFile)
114 truncateCurrentFile();
115}
116
117static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000118
119int getpid(void);
Eric Christopherd641b532015-04-28 22:54:51 +0000120static int setFilenamePossiblyWithPid(const char *Filename) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000121#define MAX_PID_SIZE 16
122 char PidChars[MAX_PID_SIZE] = {0};
123 int NumPids = 0, PidLength = 0;
124 char *Allocated;
125 int I, J;
126
Eric Christopherd641b532015-04-28 22:54:51 +0000127 /* Reset filename on NULL, except with env var which is checked by caller. */
128 if (!Filename) {
129 resetFilenameToDefault();
130 return 0;
131 }
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000132
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000133 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000134 for (I = 0; Filename[I]; ++I)
135 if (Filename[I] == '%' && Filename[++I] == 'p')
136 if (!NumPids++) {
137 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
138 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000139 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000140 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000141 if (!NumPids) {
142 setFilename(Filename, 0);
143 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000144 }
145
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000146 /* Allocate enough space for the substituted filename. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000147 Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000148 if (!Allocated)
149 return -1;
150
151 /* Construct the new filename. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000152 for (I = 0, J = 0; Filename[I]; ++I)
153 if (Filename[I] == '%') {
154 if (Filename[++I] == 'p') {
155 memcpy(Allocated + J, PidChars, PidLength);
156 J += PidLength;
157 }
158 /* Drop any unknown substitutions. */
159 } else
160 Allocated[J++] = Filename[I];
161 Allocated[J] = 0;
162
163 /* Use the computed name. */
164 setFilename(Allocated, 1);
165 return 0;
166}
167
Eric Christopherd641b532015-04-28 22:54:51 +0000168static int setFilenameFromEnvironment(void) {
169 const char *Filename = getenv("LLVM_PROFILE_FILE");
170
171 if (!Filename || !Filename[0])
172 return -1;
173
174 return setFilenamePossiblyWithPid(Filename);
175}
176
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000177static void setFilenameAutomatically(void) {
178 if (!setFilenameFromEnvironment())
179 return;
180
Eric Christopherd641b532015-04-28 22:54:51 +0000181 resetFilenameToDefault();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000182}
183
184__attribute__((visibility("hidden")))
185void __llvm_profile_initialize_file(void) {
186 /* Check if the filename has been initialized. */
187 if (__llvm_profile_CurrentFilename)
188 return;
189
190 /* Detect the filename and truncate. */
191 setFilenameAutomatically();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000192}
193
194__attribute__((visibility("hidden")))
195void __llvm_profile_set_filename(const char *Filename) {
Eric Christopherd641b532015-04-28 22:54:51 +0000196 setFilenamePossiblyWithPid(Filename);
197}
198
199__attribute__((visibility("hidden")))
200void __llvm_profile_override_default_filename(const char *Filename) {
201 /* If the env var is set, skip setting filename from argument. */
202 const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
203 if (Env_Filename && Env_Filename[0])
204 return;
205 setFilenamePossiblyWithPid(Filename);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000206}
207
208__attribute__((visibility("hidden")))
209int __llvm_profile_write_file(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000210 int rc;
211
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000212 /* Check the filename. */
213 if (!__llvm_profile_CurrentFilename)
214 return -1;
215
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000216 /* Write the file. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000217 rc = writeFileWithName(__llvm_profile_CurrentFilename);
Justin Bogner66fd5c92015-01-16 20:10:56 +0000218 if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS"))
219 fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n",
220 __llvm_profile_CurrentFilename, strerror(errno));
221 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000222}
223
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000224static void writeFileWithoutReturn(void) {
225 __llvm_profile_write_file();
226}
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000227
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000228__attribute__((visibility("hidden")))
229int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000230 static int HasBeenRegistered = 0;
231
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000232 if (HasBeenRegistered)
233 return 0;
234
235 HasBeenRegistered = 1;
236 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000237}