blob: 856d8f7e600c3e14a4ad4618e33ee78b15c65b1b [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
Xinliang David Li315e49d2016-05-24 21:29:18 +000018/* 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
Xinliang David Li315e49d2016-05-24 21:29:18 +000022#define MAX_PID_SIZE 16
23/* Data structure holding the result of parsed filename pattern. */
24typedef struct lprofFilename {
25 /* File name string possibly with %p or %h specifiers. */
26 const char *FilenamePat;
27 char PidChars[MAX_PID_SIZE];
28 char Hostname[COMPILER_RT_MAX_HOSTLEN];
29 unsigned NumPids;
30 unsigned NumHosts;
31} lprofFilename;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000032
Vedant Kumar33b8b642016-06-08 01:33:15 +000033lprofFilename lprofCurFilename = {0, {0}, {0}, 0, 0};
Xinliang David Li315e49d2016-05-24 21:29:18 +000034
35int getpid(void);
36static int getCurFilenameLength();
37static const char *getCurFilename(char *FilenameBuf);
Joerg Sonnenbergerb1cc6d52014-05-20 16:37:07 +000038
Xinliang David Li2d5bf072015-11-21 04:16:42 +000039/* Return 1 if there is an error, otherwise return 0. */
40static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
41 void **WriterCtx) {
42 uint32_t I;
43 FILE *File = (FILE *)*WriterCtx;
44 for (I = 0; I < NumIOVecs; I++) {
45 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
46 IOVecs[I].NumElm)
47 return 1;
48 }
49 return 0;
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000050}
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000051
Xinliang David Licda3bc22015-12-29 23:54:41 +000052COMPILER_RT_VISIBILITY ProfBufferIO *
Xinliang David Licf1a8d62016-03-06 04:18:13 +000053lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
Xinliang David Li609fae32016-05-13 18:26:26 +000054 FreeHook = &free;
55 DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1);
56 VPBufferSize = BufferSz;
57 return lprofCreateBufferIO(fileWriter, File);
58}
59
60static void setupIOBuffer() {
61 const char *BufferSzStr = 0;
62 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
63 if (BufferSzStr && BufferSzStr[0]) {
64 VPBufferSize = atoi(BufferSzStr);
65 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
66 }
Xinliang David Licda3bc22015-12-29 23:54:41 +000067}
68
Xinliang David Li315e49d2016-05-24 21:29:18 +000069/* Write profile data to file \c OutputName. */
70static int writeFile(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000071 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000072 FILE *OutputFile;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000073
74 /* Append to the file to support profiling multiple shared objects. */
Xinliang David Libe492712015-12-15 22:18:11 +000075 OutputFile = fopen(OutputName, "ab");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000076 if (!OutputFile)
77 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000078
Xinliang David Li315e49d2016-05-24 21:29:18 +000079 FreeHook = &free;
80 setupIOBuffer();
81 RetVal = lprofWriteData(fileWriter, OutputFile, lprofGetVPDataReader());
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000082
83 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000084 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000085}
86
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000087static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000088 const char *Filename;
Xinliang David Li315e49d2016-05-24 21:29:18 +000089 char *FilenameBuf;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000090 FILE *File;
Xinliang David Li315e49d2016-05-24 21:29:18 +000091 int Length;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000092
Xinliang David Li315e49d2016-05-24 21:29:18 +000093 Length = getCurFilenameLength();
94 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
95 Filename = getCurFilename(FilenameBuf);
96 if (!Filename)
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000097 return;
98
Diego Novilloeae95142015-07-09 17:21:52 +000099 /* Create the directory holding the file, if needed. */
Sean Silvac2feac72016-03-28 21:32:46 +0000100 if (strchr(Filename, '/') || strchr(Filename, '\\')) {
Xinliang David Li315e49d2016-05-24 21:29:18 +0000101 char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
102 strncpy(Copy, Filename, Length + 1);
Diego Novilloeae95142015-07-09 17:21:52 +0000103 __llvm_profile_recursive_mkdir(Copy);
104 }
105
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000106 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000107 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000108 if (!File)
109 return;
110 fclose(File);
111}
112
Xinliang David Li315e49d2016-05-24 21:29:18 +0000113static void resetFilenameToDefault(void) {
Xinliang David Li7f08d122016-05-25 17:30:15 +0000114 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
115 lprofCurFilename.FilenamePat = "default.profraw";
Xinliang David Li315e49d2016-05-24 21:29:18 +0000116}
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000117
Xinliang David Li315e49d2016-05-24 21:29:18 +0000118/* Parses the pattern string \p FilenamePat and store the result to
119 * lprofcurFilename structure. */
Xinliang David Li7f08d122016-05-25 17:30:15 +0000120
Xinliang David Li315e49d2016-05-24 21:29:18 +0000121static int parseFilenamePattern(const char *FilenamePat) {
122 int NumPids = 0, NumHosts = 0, I;
Xinliang David Li7f08d122016-05-25 17:30:15 +0000123 char *PidChars = &lprofCurFilename.PidChars[0];
124 char *Hostname = &lprofCurFilename.Hostname[0];
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000125
Xinliang David Li7f08d122016-05-25 17:30:15 +0000126 lprofCurFilename.FilenamePat = FilenamePat;
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000127 /* Check the filename for "%p", which indicates a pid-substitution. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000128 for (I = 0; FilenamePat[I]; ++I)
129 if (FilenamePat[I] == '%') {
130 if (FilenamePat[++I] == 'p') {
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000131 if (!NumPids++) {
Xinliang David Li315e49d2016-05-24 21:29:18 +0000132 if (snprintf(PidChars, MAX_PID_SIZE, "%d", getpid()) <= 0) {
133 PROF_WARN(
134 "Unable to parse filename pattern %s. Using the default name.",
135 FilenamePat);
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000136 return -1;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000137 }
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000138 }
Xinliang David Li315e49d2016-05-24 21:29:18 +0000139 } else if (FilenamePat[I] == 'h') {
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000140 if (!NumHosts++)
Xinliang David Li315e49d2016-05-24 21:29:18 +0000141 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {
142 PROF_WARN(
143 "Unable to parse filename pattern %s. Using the default name.",
144 FilenamePat);
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000145 return -1;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000146 }
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000147 }
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000148 }
149
Xinliang David Li7f08d122016-05-25 17:30:15 +0000150 lprofCurFilename.NumPids = NumPids;
151 lprofCurFilename.NumHosts = NumHosts;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000152 return 0;
153}
154
Xinliang David Li7f08d122016-05-25 17:30:15 +0000155static void parseAndSetFilename(const char *FilenamePat) {
156 int NewFile;
157 const char *OldFilenamePat = lprofCurFilename.FilenamePat;
158
159 if (!FilenamePat || parseFilenamePattern(FilenamePat))
160 resetFilenameToDefault();
161
162 NewFile =
163 !OldFilenamePat || (strcmp(OldFilenamePat, lprofCurFilename.FilenamePat));
164
165 if (NewFile)
166 truncateCurrentFile();
167}
168
Xinliang David Li315e49d2016-05-24 21:29:18 +0000169/* Return buffer length that is required to store the current profile
170 * filename with PID and hostname substitutions. */
171static int getCurFilenameLength() {
172 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000173 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000174
Xinliang David Li315e49d2016-05-24 21:29:18 +0000175 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts))
176 return strlen(lprofCurFilename.FilenamePat);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000177
Xinliang David Li315e49d2016-05-24 21:29:18 +0000178 return strlen(lprofCurFilename.FilenamePat) +
179 lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
180 lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2);
181}
182
183/* Return the pointer to the current profile file name (after substituting
184 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
185 * to store the resulting filename. If no substitution is needed, the
186 * current filename pattern string is directly returned. */
187static const char *getCurFilename(char *FilenameBuf) {
188 int I, J, PidLength, HostNameLength;
189 const char *FilenamePat = lprofCurFilename.FilenamePat;
190
191 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
192 return 0;
193
194 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts))
195 return lprofCurFilename.FilenamePat;
196
197 PidLength = strlen(lprofCurFilename.PidChars);
198 HostNameLength = strlen(lprofCurFilename.Hostname);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000199 /* Construct the new filename. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000200 for (I = 0, J = 0; FilenamePat[I]; ++I)
201 if (FilenamePat[I] == '%') {
202 if (FilenamePat[++I] == 'p') {
203 memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000204 J += PidLength;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000205 } else if (FilenamePat[I] == 'h') {
206 memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000207 J += HostNameLength;
208 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000209 /* Drop any unknown substitutions. */
210 } else
Xinliang David Li315e49d2016-05-24 21:29:18 +0000211 FilenameBuf[J++] = FilenamePat[I];
212 FilenameBuf[J] = 0;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000213
Xinliang David Li315e49d2016-05-24 21:29:18 +0000214 return FilenameBuf;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000215}
216
Xinliang David Li315e49d2016-05-24 21:29:18 +0000217/* Returns the pointer to the environment variable
218 * string. Returns null if the env var is not set. */
219static const char *getFilenamePatFromEnv(void) {
Eric Christopherd641b532015-04-28 22:54:51 +0000220 const char *Filename = getenv("LLVM_PROFILE_FILE");
Eric Christopherd641b532015-04-28 22:54:51 +0000221 if (!Filename || !Filename[0])
Xinliang David Li51fe0022016-05-24 01:23:09 +0000222 return 0;
223 return Filename;
Eric Christopherd641b532015-04-28 22:54:51 +0000224}
225
Xinliang David Li51fe0022016-05-24 01:23:09 +0000226/* This method is invoked by the runtime initialization hook
227 * InstrProfilingRuntime.o if it is linked in. Both user specified
228 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
229 * environment variable can override this default value. */
Xinliang David Liabfd5532015-12-16 03:29:15 +0000230COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000231void __llvm_profile_initialize_file(void) {
Xinliang David Li315e49d2016-05-24 21:29:18 +0000232 const char *FilenamePat;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000233 /* Check if the filename has been initialized. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000234 if (lprofCurFilename.FilenamePat)
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000235 return;
236
237 /* Detect the filename and truncate. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000238 FilenamePat = getFilenamePatFromEnv();
Xinliang David Li7f08d122016-05-25 17:30:15 +0000239 parseAndSetFilename(FilenamePat);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000240}
241
Xinliang David Li51fe0022016-05-24 01:23:09 +0000242/* This API is directly called by the user application code. It has the
243 * highest precedence compared with LLVM_PROFILE_FILE environment variable
Xinliang David Li41518942016-05-24 02:37:07 +0000244 * and command line option -fprofile-instr-generate=<profile_name>.
Xinliang David Li51fe0022016-05-24 01:23:09 +0000245 */
Xinliang David Liabfd5532015-12-16 03:29:15 +0000246COMPILER_RT_VISIBILITY
Xinliang David Li315e49d2016-05-24 21:29:18 +0000247void __llvm_profile_set_filename(const char *FilenamePat) {
Xinliang David Li7f08d122016-05-25 17:30:15 +0000248 parseAndSetFilename(FilenamePat);
Eric Christopherd641b532015-04-28 22:54:51 +0000249}
250
Xinliang David Li315e49d2016-05-24 21:29:18 +0000251/*
Xinliang David Li51fe0022016-05-24 01:23:09 +0000252 * This API is invoked by the global initializers emitted by Clang/LLVM when
253 * -fprofile-instr-generate=<..> is specified (vs -fprofile-instr-generate
254 * without an argument). This option has lower precedence than the
255 * LLVM_PROFILE_FILE environment variable.
256 */
Xinliang David Liabfd5532015-12-16 03:29:15 +0000257COMPILER_RT_VISIBILITY
Xinliang David Li315e49d2016-05-24 21:29:18 +0000258void __llvm_profile_override_default_filename(const char *FilenamePat) {
Eric Christopherd641b532015-04-28 22:54:51 +0000259 /* If the env var is set, skip setting filename from argument. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000260 const char *Env_Filename = getFilenamePatFromEnv();
Xinliang David Li51fe0022016-05-24 01:23:09 +0000261 if (Env_Filename)
Eric Christopherd641b532015-04-28 22:54:51 +0000262 return;
Xinliang David Li7f08d122016-05-25 17:30:15 +0000263
264 parseAndSetFilename(FilenamePat);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000265}
266
Xinliang David Li315e49d2016-05-24 21:29:18 +0000267/* The public API for writing profile data into the file with name
268 * set by previous calls to __llvm_profile_set_filename or
269 * __llvm_profile_override_default_filename or
270 * __llvm_profile_initialize_file. */
Xinliang David Liabfd5532015-12-16 03:29:15 +0000271COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000272int __llvm_profile_write_file(void) {
Xinliang David Li315e49d2016-05-24 21:29:18 +0000273 int rc, Length;
274 const char *Filename;
275 char *FilenameBuf;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000276
Xinliang David Li315e49d2016-05-24 21:29:18 +0000277 Length = getCurFilenameLength();
278 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
279 Filename = getCurFilename(FilenameBuf);
280
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000281 /* Check the filename. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000282 if (!Filename) {
Xinliang David Li690c31f2016-05-20 05:15:42 +0000283 PROF_ERR("Failed to write file : %s\n", "Filename not set");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000284 return -1;
Xinliang David Li9ea30642015-12-03 18:31:59 +0000285 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000286
Xinliang David Lid85c32c2016-01-08 23:42:28 +0000287 /* Check if there is llvm/runtime version mismatch. */
Xinliang David Lia6924212016-01-08 23:31:57 +0000288 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
Xinliang David Li690c31f2016-05-20 05:15:42 +0000289 PROF_ERR("Runtime and instrumentation version mismatch : "
Xinliang David Lia6924212016-01-08 23:31:57 +0000290 "expected %d, but get %d\n",
291 INSTR_PROF_RAW_VERSION,
292 (int)GET_VERSION(__llvm_profile_get_version()));
293 return -1;
294 }
295
Xinliang David Li315e49d2016-05-24 21:29:18 +0000296 /* Write profile data to the file. */
297 rc = writeFile(Filename);
Xinliang David Li9ea30642015-12-03 18:31:59 +0000298 if (rc)
Xinliang David Li315e49d2016-05-24 21:29:18 +0000299 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
Justin Bogner66fd5c92015-01-16 20:10:56 +0000300 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000301}
302
Xinliang David Li6fe18f42015-11-23 04:38:17 +0000303static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000304
Xinliang David Liabfd5532015-12-16 03:29:15 +0000305COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000306int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000307 static int HasBeenRegistered = 0;
308
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000309 if (HasBeenRegistered)
310 return 0;
311
Xinliang David Li4617aa72016-05-18 22:34:05 +0000312 lprofSetupValueProfiler();
313
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000314 HasBeenRegistered = 1;
315 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000316}