blob: 1e2d44be09f49c576354babc252bbbf9f14c59f0 [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"
Diego Novilloeae95142015-07-09 17:21:52 +000011#include "InstrProfilingUtil.h"
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000012#include "InstrProfilingInternal.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 Li1d8d46a2015-11-18 21:08:03 +000020static size_t FileWriter(const void *Data, size_t ElmSize, size_t NumElm,
21 void **File) {
22 return fwrite(Data, ElmSize, NumElm, (FILE *)*File);
23}
Betul Buyukkurt808385f2015-11-18 18:12:35 +000024 uint8_t *ValueDataBegin = NULL;
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000025
Xinliang David Li1d8d46a2015-11-18 21:08:03 +000026static int writeFile(FILE *File) {
27 uint8_t *ValueDataBegin = NULL;
28 const uint64_t ValueDataSize = __llvm_profile_gather_value_data(&ValueDataBegin);
29 int r = llvmWriteProfData(File, ValueDataBegin, ValueDataSize, FileWriter);
30 free (ValueDataBegin);
31 return r;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000032}
33
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000034static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000035 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000036 FILE *OutputFile;
37 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000038 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000039
40 /* Append to the file to support profiling multiple shared objects. */
41 OutputFile = fopen(OutputName, "a");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000042 if (!OutputFile)
43 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000044
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000045 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000046
47 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000048 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000049}
50
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000051__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000052__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000053
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000054static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000055 const char *Filename;
56 FILE *File;
57
58 Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000059 if (!Filename || !Filename[0])
60 return;
61
Diego Novilloeae95142015-07-09 17:21:52 +000062 /* Create the directory holding the file, if needed. */
63 if (strchr(Filename, '/')) {
64 char *Copy = malloc(strlen(Filename) + 1);
65 strcpy(Copy, Filename);
66 __llvm_profile_recursive_mkdir(Copy);
Alexey Samsonov6585b762015-07-15 22:50:39 +000067 free(Copy);
Diego Novilloeae95142015-07-09 17:21:52 +000068 }
69
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000070 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000071 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000072 if (!File)
73 return;
74 fclose(File);
75}
76
Eric Christopherd641b532015-04-28 22:54:51 +000077static void setFilename(const char *Filename, int OwnsFilename) {
78 /* Check if this is a new filename and therefore needs truncation. */
79 int NewFile = !__llvm_profile_CurrentFilename ||
80 (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
81 if (__llvm_profile_OwnsFilename)
82 free(UNCONST(__llvm_profile_CurrentFilename));
83
84 __llvm_profile_CurrentFilename = Filename;
85 __llvm_profile_OwnsFilename = OwnsFilename;
86
87 /* If not a new file, append to support profiling multiple shared objects. */
88 if (NewFile)
89 truncateCurrentFile();
90}
91
92static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000093
94int getpid(void);
Eric Christopherd641b532015-04-28 22:54:51 +000095static int setFilenamePossiblyWithPid(const char *Filename) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +000096#define MAX_PID_SIZE 16
97 char PidChars[MAX_PID_SIZE] = {0};
98 int NumPids = 0, PidLength = 0;
99 char *Allocated;
100 int I, J;
101
Eric Christopherd641b532015-04-28 22:54:51 +0000102 /* Reset filename on NULL, except with env var which is checked by caller. */
103 if (!Filename) {
104 resetFilenameToDefault();
105 return 0;
106 }
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000107
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000108 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000109 for (I = 0; Filename[I]; ++I)
110 if (Filename[I] == '%' && Filename[++I] == 'p')
111 if (!NumPids++) {
112 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
113 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000114 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000115 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000116 if (!NumPids) {
117 setFilename(Filename, 0);
118 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000119 }
120
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000121 /* Allocate enough space for the substituted filename. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000122 Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000123 if (!Allocated)
124 return -1;
125
126 /* Construct the new filename. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000127 for (I = 0, J = 0; Filename[I]; ++I)
128 if (Filename[I] == '%') {
129 if (Filename[++I] == 'p') {
130 memcpy(Allocated + J, PidChars, PidLength);
131 J += PidLength;
132 }
133 /* Drop any unknown substitutions. */
134 } else
135 Allocated[J++] = Filename[I];
136 Allocated[J] = 0;
137
138 /* Use the computed name. */
139 setFilename(Allocated, 1);
140 return 0;
141}
142
Eric Christopherd641b532015-04-28 22:54:51 +0000143static int setFilenameFromEnvironment(void) {
144 const char *Filename = getenv("LLVM_PROFILE_FILE");
145
146 if (!Filename || !Filename[0])
147 return -1;
148
149 return setFilenamePossiblyWithPid(Filename);
150}
151
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000152static void setFilenameAutomatically(void) {
153 if (!setFilenameFromEnvironment())
154 return;
155
Eric Christopherd641b532015-04-28 22:54:51 +0000156 resetFilenameToDefault();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000157}
158
159__attribute__((visibility("hidden")))
160void __llvm_profile_initialize_file(void) {
161 /* Check if the filename has been initialized. */
162 if (__llvm_profile_CurrentFilename)
163 return;
164
165 /* Detect the filename and truncate. */
166 setFilenameAutomatically();
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000167}
168
169__attribute__((visibility("hidden")))
170void __llvm_profile_set_filename(const char *Filename) {
Eric Christopherd641b532015-04-28 22:54:51 +0000171 setFilenamePossiblyWithPid(Filename);
172}
173
174__attribute__((visibility("hidden")))
175void __llvm_profile_override_default_filename(const char *Filename) {
176 /* If the env var is set, skip setting filename from argument. */
177 const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
178 if (Env_Filename && Env_Filename[0])
179 return;
180 setFilenamePossiblyWithPid(Filename);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000181}
182
183__attribute__((visibility("hidden")))
184int __llvm_profile_write_file(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000185 int rc;
186
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000187 /* Check the filename. */
188 if (!__llvm_profile_CurrentFilename)
189 return -1;
190
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000191 /* Write the file. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000192 rc = writeFileWithName(__llvm_profile_CurrentFilename);
Justin Bogner66fd5c92015-01-16 20:10:56 +0000193 if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS"))
194 fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n",
195 __llvm_profile_CurrentFilename, strerror(errno));
196 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000197}
198
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000199static void writeFileWithoutReturn(void) {
200 __llvm_profile_write_file();
201}
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000202
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000203__attribute__((visibility("hidden")))
204int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000205 static int HasBeenRegistered = 0;
206
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000207 if (HasBeenRegistered)
208 return 0;
209
210 HasBeenRegistered = 1;
211 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000212}