blob: bf50c02761d396f302bd0f8ca0b36f3e13320f40 [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
Nathan Slingerlandba86c922016-01-05 17:27:01 +000020#ifdef _MSC_VER
21#define snprintf _snprintf
22#endif
23
Xinliang David Li2d5bf072015-11-21 04:16:42 +000024/* Return 1 if there is an error, otherwise return 0. */
25static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
26 void **WriterCtx) {
27 uint32_t I;
28 FILE *File = (FILE *)*WriterCtx;
29 for (I = 0; I < NumIOVecs; I++) {
30 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
31 IOVecs[I].NumElm)
32 return 1;
33 }
34 return 0;
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000035}
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000036
Xinliang David Licda3bc22015-12-29 23:54:41 +000037COMPILER_RT_VISIBILITY ProfBufferIO *
38llvmCreateBufferIOInternal(void *File, uint32_t BufferSz) {
39 CallocHook = calloc;
40 FreeHook = free;
41 return llvmCreateBufferIO(fileWriter, File, BufferSz);
42}
43
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000044static int writeFile(FILE *File) {
Xinliang David Li54dd6832015-12-29 07:13:59 +000045 const char *BufferSzStr = 0;
46 uint64_t ValueDataSize = 0;
47 struct ValueProfData **ValueDataArray =
48 __llvm_profile_gather_value_data(&ValueDataSize);
49 FreeHook = &free;
50 CallocHook = &calloc;
51 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
52 if (BufferSzStr && BufferSzStr[0])
53 VPBufferSize = atoi(BufferSzStr);
54 return llvmWriteProfData(fileWriter, File, ValueDataArray, ValueDataSize);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000055}
56
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000057static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000058 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000059 FILE *OutputFile;
60 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000061 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000062
63 /* Append to the file to support profiling multiple shared objects. */
Xinliang David Libe492712015-12-15 22:18:11 +000064 OutputFile = fopen(OutputName, "ab");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000065 if (!OutputFile)
66 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000067
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000068 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000069
70 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000071 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000072}
73
Xinliang David Liabfd5532015-12-16 03:29:15 +000074COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
75COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000076
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000077static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000078 const char *Filename;
79 FILE *File;
80
81 Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000082 if (!Filename || !Filename[0])
83 return;
84
Diego Novilloeae95142015-07-09 17:21:52 +000085 /* Create the directory holding the file, if needed. */
86 if (strchr(Filename, '/')) {
87 char *Copy = malloc(strlen(Filename) + 1);
88 strcpy(Copy, Filename);
89 __llvm_profile_recursive_mkdir(Copy);
Alexey Samsonov6585b762015-07-15 22:50:39 +000090 free(Copy);
Diego Novilloeae95142015-07-09 17:21:52 +000091 }
92
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000093 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000094 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000095 if (!File)
96 return;
97 fclose(File);
98}
99
Eric Christopherd641b532015-04-28 22:54:51 +0000100static void setFilename(const char *Filename, int OwnsFilename) {
101 /* Check if this is a new filename and therefore needs truncation. */
102 int NewFile = !__llvm_profile_CurrentFilename ||
103 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
104 if (__llvm_profile_OwnsFilename)
105 free(UNCONST(__llvm_profile_CurrentFilename));
106
107 __llvm_profile_CurrentFilename = Filename;
108 __llvm_profile_OwnsFilename = OwnsFilename;
109
110 /* If not a new file, append to support profiling multiple shared objects. */
111 if (NewFile)
112 truncateCurrentFile();
113}
114
115static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000116
117int getpid(void);
Eric Christopherd641b532015-04-28 22:54:51 +0000118static int setFilenamePossiblyWithPid(const char *Filename) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000119#define MAX_PID_SIZE 16
120 char PidChars[MAX_PID_SIZE] = {0};
121 int NumPids = 0, PidLength = 0;
122 char *Allocated;
123 int I, J;
124
Eric Christopherd641b532015-04-28 22:54:51 +0000125 /* Reset filename on NULL, except with env var which is checked by caller. */
126 if (!Filename) {
127 resetFilenameToDefault();
128 return 0;
129 }
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000130
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000131 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000132 for (I = 0; Filename[I]; ++I)
133 if (Filename[I] == '%' && Filename[++I] == 'p')
134 if (!NumPids++) {
135 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
136 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000137 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000138 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000139 if (!NumPids) {
140 setFilename(Filename, 0);
141 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000142 }
143
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000144 /* Allocate enough space for the substituted filename. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000145 Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000146 if (!Allocated)
147 return -1;
148
149 /* Construct the new filename. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000150 for (I = 0, J = 0; Filename[I]; ++I)
151 if (Filename[I] == '%') {
152 if (Filename[++I] == 'p') {
153 memcpy(Allocated + J, PidChars, PidLength);
154 J += PidLength;
155 }
156 /* Drop any unknown substitutions. */
157 } else
158 Allocated[J++] = Filename[I];
159 Allocated[J] = 0;
160
161 /* Use the computed name. */
162 setFilename(Allocated, 1);
163 return 0;
164}
165
Eric Christopherd641b532015-04-28 22:54:51 +0000166static int setFilenameFromEnvironment(void) {
167 const char *Filename = getenv("LLVM_PROFILE_FILE");
168
169 if (!Filename || !Filename[0])
170 return -1;
171
172 return setFilenamePossiblyWithPid(Filename);
173}
174
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000175static void setFilenameAutomatically(void) {
176 if (!setFilenameFromEnvironment())
177 return;
178
Eric Christopherd641b532015-04-28 22:54:51 +0000179 resetFilenameToDefault();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000180}
181
Xinliang David Liabfd5532015-12-16 03:29:15 +0000182COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000183void __llvm_profile_initialize_file(void) {
184 /* Check if the filename has been initialized. */
185 if (__llvm_profile_CurrentFilename)
186 return;
187
188 /* Detect the filename and truncate. */
189 setFilenameAutomatically();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000190}
191
Xinliang David Liabfd5532015-12-16 03:29:15 +0000192COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000193void __llvm_profile_set_filename(const char *Filename) {
Eric Christopherd641b532015-04-28 22:54:51 +0000194 setFilenamePossiblyWithPid(Filename);
195}
196
Xinliang David Liabfd5532015-12-16 03:29:15 +0000197COMPILER_RT_VISIBILITY
Eric Christopherd641b532015-04-28 22:54:51 +0000198void __llvm_profile_override_default_filename(const char *Filename) {
199 /* If the env var is set, skip setting filename from argument. */
200 const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
201 if (Env_Filename && Env_Filename[0])
202 return;
203 setFilenamePossiblyWithPid(Filename);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000204}
205
Xinliang David Liabfd5532015-12-16 03:29:15 +0000206COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000207int __llvm_profile_write_file(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000208 int rc;
209
Xinliang David Li55d927a2015-12-07 21:18:16 +0000210 GetEnvHook = &getenv;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000211 /* Check the filename. */
Xinliang David Li9ea30642015-12-03 18:31:59 +0000212 if (!__llvm_profile_CurrentFilename) {
213 PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000214 return -1;
Xinliang David Li9ea30642015-12-03 18:31:59 +0000215 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000216
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000217 /* Write the file. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000218 rc = writeFileWithName(__llvm_profile_CurrentFilename);
Xinliang David Li9ea30642015-12-03 18:31:59 +0000219 if (rc)
220 PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n",
Justin Bogner66fd5c92015-01-16 20:10:56 +0000221 __llvm_profile_CurrentFilename, strerror(errno));
222 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000223}
224
Xinliang David Li6fe18f42015-11-23 04:38:17 +0000225static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000226
Xinliang David Liabfd5532015-12-16 03:29:15 +0000227COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000228int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000229 static int HasBeenRegistered = 0;
230
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000231 if (HasBeenRegistered)
232 return 0;
233
234 HasBeenRegistered = 1;
235 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000236}