blob: 7f2923c3065816c09c8cfac4bcd61b3ae483c16c [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 Li1d8d46a2015-11-18 21:08:03 +000033static int writeFile(FILE *File) {
34 uint8_t *ValueDataBegin = NULL;
Xinliang David Li6e557162015-11-18 21:11:46 +000035 const uint64_t ValueDataSize =
36 __llvm_profile_gather_value_data(&ValueDataBegin);
Xinliang David Li2d5bf072015-11-21 04:16:42 +000037 int r = llvmWriteProfData(fileWriter, File, ValueDataBegin, ValueDataSize);
Xinliang David Li6e557162015-11-18 21:11:46 +000038 free(ValueDataBegin);
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000039 return r;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000040}
41
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000042static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000043 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000044 FILE *OutputFile;
45 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000046 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000047
48 /* Append to the file to support profiling multiple shared objects. */
Xinliang David Libe492712015-12-15 22:18:11 +000049 OutputFile = fopen(OutputName, "ab");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000050 if (!OutputFile)
51 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000052
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000053 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000054
55 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000056 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000057}
58
Xinliang David Liabfd5532015-12-16 03:29:15 +000059COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
60COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000061
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000062static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000063 const char *Filename;
64 FILE *File;
65
66 Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000067 if (!Filename || !Filename[0])
68 return;
69
Diego Novilloeae95142015-07-09 17:21:52 +000070 /* Create the directory holding the file, if needed. */
71 if (strchr(Filename, '/')) {
72 char *Copy = malloc(strlen(Filename) + 1);
73 strcpy(Copy, Filename);
74 __llvm_profile_recursive_mkdir(Copy);
Alexey Samsonov6585b762015-07-15 22:50:39 +000075 free(Copy);
Diego Novilloeae95142015-07-09 17:21:52 +000076 }
77
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000078 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000079 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000080 if (!File)
81 return;
82 fclose(File);
83}
84
Eric Christopherd641b532015-04-28 22:54:51 +000085static void setFilename(const char *Filename, int OwnsFilename) {
86 /* Check if this is a new filename and therefore needs truncation. */
87 int NewFile = !__llvm_profile_CurrentFilename ||
88 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
89 if (__llvm_profile_OwnsFilename)
90 free(UNCONST(__llvm_profile_CurrentFilename));
91
92 __llvm_profile_CurrentFilename = Filename;
93 __llvm_profile_OwnsFilename = OwnsFilename;
94
95 /* If not a new file, append to support profiling multiple shared objects. */
96 if (NewFile)
97 truncateCurrentFile();
98}
99
100static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000101
102int getpid(void);
Eric Christopherd641b532015-04-28 22:54:51 +0000103static int setFilenamePossiblyWithPid(const char *Filename) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000104#define MAX_PID_SIZE 16
105 char PidChars[MAX_PID_SIZE] = {0};
106 int NumPids = 0, PidLength = 0;
107 char *Allocated;
108 int I, J;
109
Eric Christopherd641b532015-04-28 22:54:51 +0000110 /* Reset filename on NULL, except with env var which is checked by caller. */
111 if (!Filename) {
112 resetFilenameToDefault();
113 return 0;
114 }
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000115
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000116 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000117 for (I = 0; Filename[I]; ++I)
118 if (Filename[I] == '%' && Filename[++I] == 'p')
119 if (!NumPids++) {
120 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
121 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000122 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000123 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000124 if (!NumPids) {
125 setFilename(Filename, 0);
126 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000127 }
128
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000129 /* Allocate enough space for the substituted filename. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000130 Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000131 if (!Allocated)
132 return -1;
133
134 /* Construct the new filename. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000135 for (I = 0, J = 0; Filename[I]; ++I)
136 if (Filename[I] == '%') {
137 if (Filename[++I] == 'p') {
138 memcpy(Allocated + J, PidChars, PidLength);
139 J += PidLength;
140 }
141 /* Drop any unknown substitutions. */
142 } else
143 Allocated[J++] = Filename[I];
144 Allocated[J] = 0;
145
146 /* Use the computed name. */
147 setFilename(Allocated, 1);
148 return 0;
149}
150
Eric Christopherd641b532015-04-28 22:54:51 +0000151static int setFilenameFromEnvironment(void) {
152 const char *Filename = getenv("LLVM_PROFILE_FILE");
153
154 if (!Filename || !Filename[0])
155 return -1;
156
157 return setFilenamePossiblyWithPid(Filename);
158}
159
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000160static void setFilenameAutomatically(void) {
161 if (!setFilenameFromEnvironment())
162 return;
163
Eric Christopherd641b532015-04-28 22:54:51 +0000164 resetFilenameToDefault();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000165}
166
Xinliang David Liabfd5532015-12-16 03:29:15 +0000167COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000168void __llvm_profile_initialize_file(void) {
169 /* Check if the filename has been initialized. */
170 if (__llvm_profile_CurrentFilename)
171 return;
172
173 /* Detect the filename and truncate. */
174 setFilenameAutomatically();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000175}
176
Xinliang David Liabfd5532015-12-16 03:29:15 +0000177COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000178void __llvm_profile_set_filename(const char *Filename) {
Eric Christopherd641b532015-04-28 22:54:51 +0000179 setFilenamePossiblyWithPid(Filename);
180}
181
Xinliang David Liabfd5532015-12-16 03:29:15 +0000182COMPILER_RT_VISIBILITY
Eric Christopherd641b532015-04-28 22:54:51 +0000183void __llvm_profile_override_default_filename(const char *Filename) {
184 /* If the env var is set, skip setting filename from argument. */
185 const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
186 if (Env_Filename && Env_Filename[0])
187 return;
188 setFilenamePossiblyWithPid(Filename);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000189}
190
Xinliang David Liabfd5532015-12-16 03:29:15 +0000191COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000192int __llvm_profile_write_file(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000193 int rc;
194
Xinliang David Li55d927a2015-12-07 21:18:16 +0000195 GetEnvHook = &getenv;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000196 /* Check the filename. */
Xinliang David Li9ea30642015-12-03 18:31:59 +0000197 if (!__llvm_profile_CurrentFilename) {
198 PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000199 return -1;
Xinliang David Li9ea30642015-12-03 18:31:59 +0000200 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000201
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000202 /* Write the file. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000203 rc = writeFileWithName(__llvm_profile_CurrentFilename);
Xinliang David Li9ea30642015-12-03 18:31:59 +0000204 if (rc)
205 PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n",
Justin Bogner66fd5c92015-01-16 20:10:56 +0000206 __llvm_profile_CurrentFilename, strerror(errno));
207 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000208}
209
Xinliang David Li6fe18f42015-11-23 04:38:17 +0000210static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000211
Xinliang David Liabfd5532015-12-16 03:29:15 +0000212COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000213int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000214 static int HasBeenRegistered = 0;
215
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000216 if (HasBeenRegistered)
217 return 0;
218
219 HasBeenRegistered = 1;
220 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000221}