blob: 06df67d6be2fc5f962935171061d1a960d7581c9 [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();
Betul Buyukkurt808385f2015-11-18 18:12:35 +000027 uint8_t *ValueDataBegin = NULL;
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000028
29 /* Calculate size of sections. */
30 const uint64_t DataSize = DataEnd - DataBegin;
31 const uint64_t CountersSize = CountersEnd - CountersBegin;
32 const uint64_t NamesSize = NamesEnd - NamesBegin;
Betul Buyukkurt808385f2015-11-18 18:12:35 +000033 const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
34 const uint64_t ValueDataSize =
35 __llvm_profile_gather_value_data(&ValueDataBegin);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000036
37 /* Enough zeroes for padding. */
38 const char Zeroes[sizeof(uint64_t)] = {0};
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000039
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000040 /* Create the header. */
Xinliang David Li4da5de92015-10-16 22:21:56 +000041 __llvm_profile_header Header;
Xinliang David Lib6c81d22015-11-13 22:33:07 +000042
43 if (!DataSize)
44 return 0;
45
Xinliang David Li4da5de92015-10-16 22:21:56 +000046 Header.Magic = __llvm_profile_get_magic();
47 Header.Version = __llvm_profile_get_version();
48 Header.DataSize = DataSize;
49 Header.CountersSize = CountersSize;
50 Header.NamesSize = NamesSize;
51 Header.CountersDelta = (uintptr_t)CountersBegin;
52 Header.NamesDelta = (uintptr_t)NamesBegin;
Betul Buyukkurt808385f2015-11-18 18:12:35 +000053 Header.ValueKindLast = VK_LAST;
54 Header.ValueDataSize = ValueDataSize;
55 Header.ValueDataDelta = (uintptr_t)ValueDataBegin;
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000056
57 /* Write the data. */
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000058#define CHECK_fwrite(Data, Size, Length, File) \
59 do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
Betul Buyukkurt808385f2015-11-18 18:12:35 +000060 CHECK_fwrite(&Header, sizeof(__llvm_profile_header), 1, File);
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000061 CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000062 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000063 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000064 CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
Betul Buyukkurt808385f2015-11-18 18:12:35 +000065 CHECK_fwrite(ValueDataBegin,
66 sizeof(__llvm_profile_value_data), ValueDataSize, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000067#undef CHECK_fwrite
Betul Buyukkurt808385f2015-11-18 18:12:35 +000068 free(ValueDataBegin);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000069 return 0;
70}
71
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000072static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000073 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000074 FILE *OutputFile;
75 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000076 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000077
78 /* Append to the file to support profiling multiple shared objects. */
79 OutputFile = fopen(OutputName, "a");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000080 if (!OutputFile)
81 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000082
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000083 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000084
85 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000086 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000087}
88
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000089__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000090__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000091
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000092static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000093 const char *Filename;
94 FILE *File;
95
96 Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000097 if (!Filename || !Filename[0])
98 return;
99
Diego Novilloeae95142015-07-09 17:21:52 +0000100 /* Create the directory holding the file, if needed. */
101 if (strchr(Filename, '/')) {
102 char *Copy = malloc(strlen(Filename) + 1);
103 strcpy(Copy, Filename);
104 __llvm_profile_recursive_mkdir(Copy);
Alexey Samsonov6585b762015-07-15 22:50:39 +0000105 free(Copy);
Diego Novilloeae95142015-07-09 17:21:52 +0000106 }
107
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000108 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000109 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000110 if (!File)
111 return;
112 fclose(File);
113}
114
Eric Christopherd641b532015-04-28 22:54:51 +0000115static void setFilename(const char *Filename, int OwnsFilename) {
116 /* Check if this is a new filename and therefore needs truncation. */
117 int NewFile = !__llvm_profile_CurrentFilename ||
118 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
119 if (__llvm_profile_OwnsFilename)
120 free(UNCONST(__llvm_profile_CurrentFilename));
121
122 __llvm_profile_CurrentFilename = Filename;
123 __llvm_profile_OwnsFilename = OwnsFilename;
124
125 /* If not a new file, append to support profiling multiple shared objects. */
126 if (NewFile)
127 truncateCurrentFile();
128}
129
130static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000131
132int getpid(void);
Eric Christopherd641b532015-04-28 22:54:51 +0000133static int setFilenamePossiblyWithPid(const char *Filename) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000134#define MAX_PID_SIZE 16
135 char PidChars[MAX_PID_SIZE] = {0};
136 int NumPids = 0, PidLength = 0;
137 char *Allocated;
138 int I, J;
139
Eric Christopherd641b532015-04-28 22:54:51 +0000140 /* Reset filename on NULL, except with env var which is checked by caller. */
141 if (!Filename) {
142 resetFilenameToDefault();
143 return 0;
144 }
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000145
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000146 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000147 for (I = 0; Filename[I]; ++I)
148 if (Filename[I] == '%' && Filename[++I] == 'p')
149 if (!NumPids++) {
150 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
151 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000152 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000153 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000154 if (!NumPids) {
155 setFilename(Filename, 0);
156 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000157 }
158
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000159 /* Allocate enough space for the substituted filename. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000160 Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000161 if (!Allocated)
162 return -1;
163
164 /* Construct the new filename. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000165 for (I = 0, J = 0; Filename[I]; ++I)
166 if (Filename[I] == '%') {
167 if (Filename[++I] == 'p') {
168 memcpy(Allocated + J, PidChars, PidLength);
169 J += PidLength;
170 }
171 /* Drop any unknown substitutions. */
172 } else
173 Allocated[J++] = Filename[I];
174 Allocated[J] = 0;
175
176 /* Use the computed name. */
177 setFilename(Allocated, 1);
178 return 0;
179}
180
Eric Christopherd641b532015-04-28 22:54:51 +0000181static int setFilenameFromEnvironment(void) {
182 const char *Filename = getenv("LLVM_PROFILE_FILE");
183
184 if (!Filename || !Filename[0])
185 return -1;
186
187 return setFilenamePossiblyWithPid(Filename);
188}
189
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000190static void setFilenameAutomatically(void) {
191 if (!setFilenameFromEnvironment())
192 return;
193
Eric Christopherd641b532015-04-28 22:54:51 +0000194 resetFilenameToDefault();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000195}
196
197__attribute__((visibility("hidden")))
198void __llvm_profile_initialize_file(void) {
199 /* Check if the filename has been initialized. */
200 if (__llvm_profile_CurrentFilename)
201 return;
202
203 /* Detect the filename and truncate. */
204 setFilenameAutomatically();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000205}
206
207__attribute__((visibility("hidden")))
208void __llvm_profile_set_filename(const char *Filename) {
Eric Christopherd641b532015-04-28 22:54:51 +0000209 setFilenamePossiblyWithPid(Filename);
210}
211
212__attribute__((visibility("hidden")))
213void __llvm_profile_override_default_filename(const char *Filename) {
214 /* If the env var is set, skip setting filename from argument. */
215 const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
216 if (Env_Filename && Env_Filename[0])
217 return;
218 setFilenamePossiblyWithPid(Filename);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000219}
220
221__attribute__((visibility("hidden")))
222int __llvm_profile_write_file(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000223 int rc;
224
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000225 /* Check the filename. */
226 if (!__llvm_profile_CurrentFilename)
227 return -1;
228
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000229 /* Write the file. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000230 rc = writeFileWithName(__llvm_profile_CurrentFilename);
Justin Bogner66fd5c92015-01-16 20:10:56 +0000231 if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS"))
232 fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n",
233 __llvm_profile_CurrentFilename, strerror(errno));
234 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000235}
236
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000237static void writeFileWithoutReturn(void) {
238 __llvm_profile_write_file();
239}
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000240
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000241__attribute__((visibility("hidden")))
242int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000243 static int HasBeenRegistered = 0;
244
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000245 if (HasBeenRegistered)
246 return 0;
247
248 HasBeenRegistered = 1;
249 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000250}