blob: 14f7517b6a9d2885bdcb9a2a7186d187337ac0b8 [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"
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000011#include "InstrProfilingInternal.h"
Xinliang David Li6e557162015-11-18 21:11:46 +000012#include "InstrProfilingUtil.h"
Joerg Sonnenbergeref24b412015-03-09 11:23:29 +000013#include <errno.h>
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000014#include <stdio.h>
15#include <stdlib.h>
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000016#include <string.h>
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000017
Joerg Sonnenbergerb1cc6d52014-05-20 16:37:07 +000018#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
19
Xinliang David Li2d5bf072015-11-21 04:16:42 +000020/* Return 1 if there is an error, otherwise return 0. */
21static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
22 void **WriterCtx) {
23 uint32_t I;
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) !=
27 IOVecs[I].NumElm)
28 return 1;
29 }
30 return 0;
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000031}
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000032
Xinliang David Licda3bc22015-12-29 23:54:41 +000033COMPILER_RT_VISIBILITY ProfBufferIO *
Xinliang David Licf1a8d62016-03-06 04:18:13 +000034lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
Xinliang David Licda3bc22015-12-29 23:54:41 +000035 CallocHook = calloc;
36 FreeHook = free;
Xinliang David Licf1a8d62016-03-06 04:18:13 +000037 return lprofCreateBufferIO(fileWriter, File, BufferSz);
Xinliang David Licda3bc22015-12-29 23:54:41 +000038}
39
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000040static int writeFile(FILE *File) {
Xinliang David Li54dd6832015-12-29 07:13:59 +000041 const char *BufferSzStr = 0;
Xinliang David Li54dd6832015-12-29 07:13:59 +000042 FreeHook = &free;
43 CallocHook = &calloc;
44 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
45 if (BufferSzStr && BufferSzStr[0])
46 VPBufferSize = atoi(BufferSzStr);
Xinliang David Lie9a8574d2016-05-10 00:17:31 +000047 return lprofWriteData(fileWriter, File, lprofGatherValueProfData);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000048}
49
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000050static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000051 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000052 FILE *OutputFile;
53 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000054 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000055
56 /* Append to the file to support profiling multiple shared objects. */
Xinliang David Libe492712015-12-15 22:18:11 +000057 OutputFile = fopen(OutputName, "ab");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000058 if (!OutputFile)
59 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000060
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000061 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000062
63 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000064 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000065}
66
Xinliang David Liabfd5532015-12-16 03:29:15 +000067COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
68COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000069
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000070static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000071 const char *Filename;
72 FILE *File;
73
74 Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000075 if (!Filename || !Filename[0])
76 return;
77
Diego Novilloeae95142015-07-09 17:21:52 +000078 /* Create the directory holding the file, if needed. */
Sean Silvac2feac72016-03-28 21:32:46 +000079 if (strchr(Filename, '/') || strchr(Filename, '\\')) {
Diego Novilloeae95142015-07-09 17:21:52 +000080 char *Copy = malloc(strlen(Filename) + 1);
81 strcpy(Copy, Filename);
82 __llvm_profile_recursive_mkdir(Copy);
Alexey Samsonov6585b762015-07-15 22:50:39 +000083 free(Copy);
Diego Novilloeae95142015-07-09 17:21:52 +000084 }
85
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000086 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000087 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000088 if (!File)
89 return;
90 fclose(File);
91}
92
Eric Christopherd641b532015-04-28 22:54:51 +000093static void setFilename(const char *Filename, int OwnsFilename) {
94 /* Check if this is a new filename and therefore needs truncation. */
95 int NewFile = !__llvm_profile_CurrentFilename ||
96 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
97 if (__llvm_profile_OwnsFilename)
98 free(UNCONST(__llvm_profile_CurrentFilename));
99
100 __llvm_profile_CurrentFilename = Filename;
101 __llvm_profile_OwnsFilename = OwnsFilename;
102
103 /* If not a new file, append to support profiling multiple shared objects. */
104 if (NewFile)
105 truncateCurrentFile();
106}
107
108static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000109
110int getpid(void);
Eric Christopherd641b532015-04-28 22:54:51 +0000111static int setFilenamePossiblyWithPid(const char *Filename) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000112#define MAX_PID_SIZE 16
113 char PidChars[MAX_PID_SIZE] = {0};
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000114 int NumPids = 0, PidLength = 0, NumHosts = 0, HostNameLength = 0;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000115 char *Allocated;
116 int I, J;
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000117 char Hostname[COMPILER_RT_MAX_HOSTLEN];
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000118
Eric Christopherd641b532015-04-28 22:54:51 +0000119 /* Reset filename on NULL, except with env var which is checked by caller. */
120 if (!Filename) {
121 resetFilenameToDefault();
122 return 0;
123 }
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000124
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000125 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000126 for (I = 0; Filename[I]; ++I)
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000127 if (Filename[I] == '%') {
128 if (Filename[++I] == 'p') {
129 if (!NumPids++) {
130 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
131 if (PidLength <= 0)
132 return -1;
133 }
134 } else if (Filename[I] == 'h') {
135 if (!NumHosts++)
136 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN))
137 return -1;
138 HostNameLength = strlen(Hostname);
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000139 }
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000140 }
141
142 if (!(NumPids || NumHosts)) {
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000143 setFilename(Filename, 0);
144 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000145 }
146
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000147 /* Allocate enough space for the substituted filename. */
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000148 Allocated = malloc(I + NumPids*(PidLength - 2) +
149 NumHosts*(HostNameLength - 2) + 1);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000150 if (!Allocated)
151 return -1;
152
153 /* Construct the new filename. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000154 for (I = 0, J = 0; Filename[I]; ++I)
155 if (Filename[I] == '%') {
156 if (Filename[++I] == 'p') {
157 memcpy(Allocated + J, PidChars, PidLength);
158 J += PidLength;
159 }
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000160 else if (Filename[I] == 'h') {
161 memcpy(Allocated + J, Hostname, HostNameLength);
162 J += HostNameLength;
163 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000164 /* Drop any unknown substitutions. */
165 } else
166 Allocated[J++] = Filename[I];
167 Allocated[J] = 0;
168
169 /* Use the computed name. */
170 setFilename(Allocated, 1);
171 return 0;
172}
173
Eric Christopherd641b532015-04-28 22:54:51 +0000174static int setFilenameFromEnvironment(void) {
175 const char *Filename = getenv("LLVM_PROFILE_FILE");
176
177 if (!Filename || !Filename[0])
178 return -1;
179
180 return setFilenamePossiblyWithPid(Filename);
181}
182
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000183static void setFilenameAutomatically(void) {
184 if (!setFilenameFromEnvironment())
185 return;
186
Eric Christopherd641b532015-04-28 22:54:51 +0000187 resetFilenameToDefault();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000188}
189
Xinliang David Liabfd5532015-12-16 03:29:15 +0000190COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000191void __llvm_profile_initialize_file(void) {
192 /* Check if the filename has been initialized. */
193 if (__llvm_profile_CurrentFilename)
194 return;
195
196 /* Detect the filename and truncate. */
197 setFilenameAutomatically();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000198}
199
Xinliang David Liabfd5532015-12-16 03:29:15 +0000200COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000201void __llvm_profile_set_filename(const char *Filename) {
Eric Christopherd641b532015-04-28 22:54:51 +0000202 setFilenamePossiblyWithPid(Filename);
203}
204
Xinliang David Liabfd5532015-12-16 03:29:15 +0000205COMPILER_RT_VISIBILITY
Eric Christopherd641b532015-04-28 22:54:51 +0000206void __llvm_profile_override_default_filename(const char *Filename) {
207 /* If the env var is set, skip setting filename from argument. */
208 const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
209 if (Env_Filename && Env_Filename[0])
210 return;
211 setFilenamePossiblyWithPid(Filename);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000212}
213
Xinliang David Liabfd5532015-12-16 03:29:15 +0000214COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000215int __llvm_profile_write_file(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000216 int rc;
217
Xinliang David Li55d927a2015-12-07 21:18:16 +0000218 GetEnvHook = &getenv;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000219 /* Check the filename. */
Xinliang David Li9ea30642015-12-03 18:31:59 +0000220 if (!__llvm_profile_CurrentFilename) {
221 PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000222 return -1;
Xinliang David Li9ea30642015-12-03 18:31:59 +0000223 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000224
Xinliang David Lid85c32c2016-01-08 23:42:28 +0000225 /* Check if there is llvm/runtime version mismatch. */
Xinliang David Lia6924212016-01-08 23:31:57 +0000226 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
227 PROF_ERR("LLVM Profile: runtime and instrumentation version mismatch : "
228 "expected %d, but get %d\n",
229 INSTR_PROF_RAW_VERSION,
230 (int)GET_VERSION(__llvm_profile_get_version()));
231 return -1;
232 }
233
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000234 /* Write the file. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000235 rc = writeFileWithName(__llvm_profile_CurrentFilename);
Xinliang David Li9ea30642015-12-03 18:31:59 +0000236 if (rc)
237 PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n",
Justin Bogner66fd5c92015-01-16 20:10:56 +0000238 __llvm_profile_CurrentFilename, strerror(errno));
239 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000240}
241
Xinliang David Li6fe18f42015-11-23 04:38:17 +0000242static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000243
Xinliang David Liabfd5532015-12-16 03:29:15 +0000244COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000245int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000246 static int HasBeenRegistered = 0;
247
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000248 if (HasBeenRegistered)
249 return 0;
250
251 HasBeenRegistered = 1;
252 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000253}