blob: ab98cb8daf45d0288f2f477da73a963fcae49e8c [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>
Xinliang David Li71eddbf2016-05-20 04:52:27 +000017#ifdef _MSC_VER
18/* For _alloca */
Xinliang David Li71eddbf2016-05-20 04:52:27 +000019#include <malloc.h>
Xinliang David Lifb320a12016-05-20 05:40:07 +000020#endif
Xinliang David Li71eddbf2016-05-20 04:52:27 +000021
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000022
Joerg Sonnenbergerb1cc6d52014-05-20 16:37:07 +000023#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
24
Xinliang David Li2d5bf072015-11-21 04:16:42 +000025/* Return 1 if there is an error, otherwise return 0. */
26static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
27 void **WriterCtx) {
28 uint32_t I;
29 FILE *File = (FILE *)*WriterCtx;
30 for (I = 0; I < NumIOVecs; I++) {
31 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
32 IOVecs[I].NumElm)
33 return 1;
34 }
35 return 0;
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000036}
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000037
Xinliang David Licda3bc22015-12-29 23:54:41 +000038COMPILER_RT_VISIBILITY ProfBufferIO *
Xinliang David Licf1a8d62016-03-06 04:18:13 +000039lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
Xinliang David Li609fae32016-05-13 18:26:26 +000040 FreeHook = &free;
41 DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1);
42 VPBufferSize = BufferSz;
43 return lprofCreateBufferIO(fileWriter, File);
44}
45
46static void setupIOBuffer() {
47 const char *BufferSzStr = 0;
48 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
49 if (BufferSzStr && BufferSzStr[0]) {
50 VPBufferSize = atoi(BufferSzStr);
51 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
52 }
Xinliang David Licda3bc22015-12-29 23:54:41 +000053}
54
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000055static int writeFile(FILE *File) {
Xinliang David Li54dd6832015-12-29 07:13:59 +000056 FreeHook = &free;
Xinliang David Li609fae32016-05-13 18:26:26 +000057 setupIOBuffer();
Xinliang David Li23a66e42016-05-14 20:12:42 +000058 return lprofWriteData(fileWriter, File, lprofGetVPDataReader());
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000059}
60
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000061static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000062 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000063 FILE *OutputFile;
64 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000065 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000066
67 /* Append to the file to support profiling multiple shared objects. */
Xinliang David Libe492712015-12-15 22:18:11 +000068 OutputFile = fopen(OutputName, "ab");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000069 if (!OutputFile)
70 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000071
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000072 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000073
74 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000075 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000076}
77
Xinliang David Liabfd5532015-12-16 03:29:15 +000078COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
79COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000080
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000081static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000082 const char *Filename;
83 FILE *File;
84
85 Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000086 if (!Filename || !Filename[0])
87 return;
88
Diego Novilloeae95142015-07-09 17:21:52 +000089 /* Create the directory holding the file, if needed. */
Sean Silvac2feac72016-03-28 21:32:46 +000090 if (strchr(Filename, '/') || strchr(Filename, '\\')) {
Xinliang David Li71eddbf2016-05-20 04:52:27 +000091 char *Copy = (char *)COMPILER_RT_ALLOCA(strlen(Filename) + 1);
Diego Novilloeae95142015-07-09 17:21:52 +000092 strcpy(Copy, Filename);
93 __llvm_profile_recursive_mkdir(Copy);
94 }
95
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000096 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000097 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000098 if (!File)
99 return;
100 fclose(File);
101}
102
Eric Christopherd641b532015-04-28 22:54:51 +0000103static 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));
109
110 __llvm_profile_CurrentFilename = Filename;
111 __llvm_profile_OwnsFilename = OwnsFilename;
112
113 /* If not a new file, append to support profiling multiple shared objects. */
114 if (NewFile)
115 truncateCurrentFile();
116}
117
118static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000119
120int getpid(void);
Eric Christopherd641b532015-04-28 22:54:51 +0000121static int setFilenamePossiblyWithPid(const char *Filename) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000122#define MAX_PID_SIZE 16
123 char PidChars[MAX_PID_SIZE] = {0};
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000124 int NumPids = 0, PidLength = 0, NumHosts = 0, HostNameLength = 0;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000125 char *Allocated;
126 int I, J;
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000127 char Hostname[COMPILER_RT_MAX_HOSTLEN];
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000128
Eric Christopherd641b532015-04-28 22:54:51 +0000129 /* Reset filename on NULL, except with env var which is checked by caller. */
130 if (!Filename) {
131 resetFilenameToDefault();
132 return 0;
133 }
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000134
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000135 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000136 for (I = 0; Filename[I]; ++I)
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000137 if (Filename[I] == '%') {
138 if (Filename[++I] == 'p') {
139 if (!NumPids++) {
140 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
141 if (PidLength <= 0)
142 return -1;
143 }
144 } else if (Filename[I] == 'h') {
145 if (!NumHosts++)
146 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN))
147 return -1;
148 HostNameLength = strlen(Hostname);
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000149 }
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000150 }
151
152 if (!(NumPids || NumHosts)) {
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000153 setFilename(Filename, 0);
154 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000155 }
156
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000157 /* Allocate enough space for the substituted filename. */
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000158 Allocated = malloc(I + NumPids*(PidLength - 2) +
159 NumHosts*(HostNameLength - 2) + 1);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000160 if (!Allocated)
161 return -1;
162
163 /* Construct the new filename. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000164 for (I = 0, J = 0; Filename[I]; ++I)
165 if (Filename[I] == '%') {
166 if (Filename[++I] == 'p') {
167 memcpy(Allocated + J, PidChars, PidLength);
168 J += PidLength;
169 }
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000170 else if (Filename[I] == 'h') {
171 memcpy(Allocated + J, Hostname, HostNameLength);
172 J += HostNameLength;
173 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000174 /* Drop any unknown substitutions. */
175 } else
176 Allocated[J++] = Filename[I];
177 Allocated[J] = 0;
178
179 /* Use the computed name. */
180 setFilename(Allocated, 1);
181 return 0;
182}
183
Eric Christopherd641b532015-04-28 22:54:51 +0000184static int setFilenameFromEnvironment(void) {
185 const char *Filename = getenv("LLVM_PROFILE_FILE");
186
187 if (!Filename || !Filename[0])
188 return -1;
189
190 return setFilenamePossiblyWithPid(Filename);
191}
192
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000193static void setFilenameAutomatically(void) {
194 if (!setFilenameFromEnvironment())
195 return;
196
Eric Christopherd641b532015-04-28 22:54:51 +0000197 resetFilenameToDefault();
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_initialize_file(void) {
202 /* Check if the filename has been initialized. */
203 if (__llvm_profile_CurrentFilename)
204 return;
205
206 /* Detect the filename and truncate. */
207 setFilenameAutomatically();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000208}
209
Xinliang David Liabfd5532015-12-16 03:29:15 +0000210COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000211void __llvm_profile_set_filename(const char *Filename) {
Eric Christopherd641b532015-04-28 22:54:51 +0000212 setFilenamePossiblyWithPid(Filename);
213}
214
Xinliang David Liabfd5532015-12-16 03:29:15 +0000215COMPILER_RT_VISIBILITY
Eric Christopherd641b532015-04-28 22:54:51 +0000216void __llvm_profile_override_default_filename(const char *Filename) {
217 /* If the env var is set, skip setting filename from argument. */
218 const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
219 if (Env_Filename && Env_Filename[0])
220 return;
221 setFilenamePossiblyWithPid(Filename);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000222}
223
Xinliang David Liabfd5532015-12-16 03:29:15 +0000224COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000225int __llvm_profile_write_file(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000226 int rc;
227
Xinliang David Li55d927a2015-12-07 21:18:16 +0000228 GetEnvHook = &getenv;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000229 /* Check the filename. */
Xinliang David Li9ea30642015-12-03 18:31:59 +0000230 if (!__llvm_profile_CurrentFilename) {
Xinliang David Li690c31f2016-05-20 05:15:42 +0000231 PROF_ERR("Failed to write file : %s\n", "Filename not set");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000232 return -1;
Xinliang David Li9ea30642015-12-03 18:31:59 +0000233 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000234
Xinliang David Lid85c32c2016-01-08 23:42:28 +0000235 /* Check if there is llvm/runtime version mismatch. */
Xinliang David Lia6924212016-01-08 23:31:57 +0000236 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
Xinliang David Li690c31f2016-05-20 05:15:42 +0000237 PROF_ERR("Runtime and instrumentation version mismatch : "
Xinliang David Lia6924212016-01-08 23:31:57 +0000238 "expected %d, but get %d\n",
239 INSTR_PROF_RAW_VERSION,
240 (int)GET_VERSION(__llvm_profile_get_version()));
241 return -1;
242 }
243
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000244 /* Write the file. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000245 rc = writeFileWithName(__llvm_profile_CurrentFilename);
Xinliang David Li9ea30642015-12-03 18:31:59 +0000246 if (rc)
Xinliang David Li690c31f2016-05-20 05:15:42 +0000247 PROF_ERR("Failed to write file \"%s\": %s\n",
Justin Bogner66fd5c92015-01-16 20:10:56 +0000248 __llvm_profile_CurrentFilename, strerror(errno));
249 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000250}
251
Xinliang David Li6fe18f42015-11-23 04:38:17 +0000252static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000253
Xinliang David Liabfd5532015-12-16 03:29:15 +0000254COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000255int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000256 static int HasBeenRegistered = 0;
257
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000258 if (HasBeenRegistered)
259 return 0;
260
Xinliang David Li4617aa72016-05-18 22:34:05 +0000261 lprofSetupValueProfiler();
262
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000263 HasBeenRegistered = 1;
264 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000265}