blob: 1299a6d8cbee59aef1acbab44231d1728796e68e [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
Joerg Sonnenbergeref24b412015-03-09 11:23:29 +000010#include <errno.h>
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000011#include <stdio.h>
12#include <stdlib.h>
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000013#include <string.h>
Xinliang David Li71eddbf2016-05-20 04:52:27 +000014#ifdef _MSC_VER
Xinliang David Li315e49d2016-05-24 21:29:18 +000015/* For _alloca. */
Xinliang David Li71eddbf2016-05-20 04:52:27 +000016#include <malloc.h>
Xinliang David Lifb320a12016-05-20 05:40:07 +000017#endif
Xinliang David Lie2ce2e02016-06-08 23:43:56 +000018#if defined(_WIN32)
19#include "WindowsMMap.h"
20/* For _chsize_s */
21#include <io.h>
Reid Kleckner963aba32018-04-23 17:05:47 +000022#include <process.h>
Xinliang David Lie2ce2e02016-06-08 23:43:56 +000023#else
24#include <sys/file.h>
25#include <sys/mman.h>
26#include <unistd.h>
27#if defined(__linux__)
28#include <sys/types.h>
29#endif
30#endif
Xinliang David Li71eddbf2016-05-20 04:52:27 +000031
Vedant Kumard7c93362017-12-14 19:01:04 +000032#include "InstrProfiling.h"
33#include "InstrProfilingInternal.h"
34#include "InstrProfilingUtil.h"
35
Xinliang David Li153e8b62016-06-10 20:35:01 +000036/* From where is profile name specified.
37 * The order the enumerators define their
38 * precedence. Re-order them may lead to
39 * runtime behavior change. */
40typedef enum ProfileNameSpecifier {
41 PNS_unknown = 0,
42 PNS_default,
43 PNS_command_line,
44 PNS_environment,
45 PNS_runtime_api
46} ProfileNameSpecifier;
47
48static const char *getPNSStr(ProfileNameSpecifier PNS) {
49 switch (PNS) {
50 case PNS_default:
51 return "default setting";
52 case PNS_command_line:
53 return "command line";
54 case PNS_environment:
55 return "environment variable";
56 case PNS_runtime_api:
57 return "runtime API";
58 default:
59 return "Unknown";
60 }
61}
62
Xinliang David Li315e49d2016-05-24 21:29:18 +000063#define MAX_PID_SIZE 16
Ying Yi2c614cf2016-08-10 10:48:02 +000064/* Data structure holding the result of parsed filename pattern. */
Xinliang David Li315e49d2016-05-24 21:29:18 +000065typedef struct lprofFilename {
66 /* File name string possibly with %p or %h specifiers. */
67 const char *FilenamePat;
Xinliang David Li14c91c42016-08-02 19:34:00 +000068 /* A flag indicating if FilenamePat's memory is allocated
69 * by runtime. */
70 unsigned OwnsFilenamePat;
Xinliang David Lieaf238d2016-07-20 04:26:09 +000071 const char *ProfilePathPrefix;
Xinliang David Li315e49d2016-05-24 21:29:18 +000072 char PidChars[MAX_PID_SIZE];
73 char Hostname[COMPILER_RT_MAX_HOSTLEN];
74 unsigned NumPids;
75 unsigned NumHosts;
Xinliang David Lie2ce2e02016-06-08 23:43:56 +000076 /* When in-process merging is enabled, this parameter specifies
77 * the total number of profile data files shared by all the processes
78 * spawned from the same binary. By default the value is 1. If merging
79 * is not enabled, its value should be 0. This parameter is specified
80 * by the %[0-9]m specifier. For instance %2m enables merging using
81 * 2 profile data files. %1m is equivalent to %m. Also %m specifier
82 * can only appear once at the end of the name pattern. */
83 unsigned MergePoolSize;
Xinliang David Li153e8b62016-06-10 20:35:01 +000084 ProfileNameSpecifier PNS;
Xinliang David Li315e49d2016-05-24 21:29:18 +000085} lprofFilename;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000086
Vedant Kumar6ff82bd2016-10-18 00:02:28 +000087COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0, 0, 0, {0}, {0},
88 0, 0, 0, PNS_unknown};
Xinliang David Li315e49d2016-05-24 21:29:18 +000089
Alex Lorenz341317f2017-08-31 15:51:23 +000090static int getCurFilenameLength();
Xinliang David Li315e49d2016-05-24 21:29:18 +000091static const char *getCurFilename(char *FilenameBuf);
Xinliang David Lie2ce2e02016-06-08 23:43:56 +000092static unsigned doMerging() { return lprofCurFilename.MergePoolSize; }
Joerg Sonnenbergerb1cc6d52014-05-20 16:37:07 +000093
Xinliang David Li2d5bf072015-11-21 04:16:42 +000094/* Return 1 if there is an error, otherwise return 0. */
Xinliang David Li967669f2017-06-27 17:28:01 +000095static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
96 uint32_t NumIOVecs) {
Xinliang David Li2d5bf072015-11-21 04:16:42 +000097 uint32_t I;
Xinliang David Li967669f2017-06-27 17:28:01 +000098 FILE *File = (FILE *)This->WriterCtx;
Xinliang David Li2d5bf072015-11-21 04:16:42 +000099 for (I = 0; I < NumIOVecs; I++) {
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000100 if (IOVecs[I].Data) {
101 if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
102 IOVecs[I].NumElm)
103 return 1;
104 } else {
105 if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1)
106 return 1;
107 }
Xinliang David Li2d5bf072015-11-21 04:16:42 +0000108 }
109 return 0;
Xinliang David Li1d8d46a2015-11-18 21:08:03 +0000110}
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +0000111
Xinliang David Li967669f2017-06-27 17:28:01 +0000112static void initFileWriter(ProfDataWriter *This, FILE *File) {
113 This->Write = fileWriter;
114 This->WriterCtx = File;
115}
116
Xinliang David Licda3bc22015-12-29 23:54:41 +0000117COMPILER_RT_VISIBILITY ProfBufferIO *
Xinliang David Licf1a8d62016-03-06 04:18:13 +0000118lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
Xinliang David Li609fae32016-05-13 18:26:26 +0000119 FreeHook = &free;
120 DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1);
121 VPBufferSize = BufferSz;
Xinliang David Li967669f2017-06-27 17:28:01 +0000122 ProfDataWriter *fileWriter =
123 (ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1);
124 initFileWriter(fileWriter, File);
125 ProfBufferIO *IO = lprofCreateBufferIO(fileWriter);
126 IO->OwnFileWriter = 1;
127 return IO;
Xinliang David Li609fae32016-05-13 18:26:26 +0000128}
129
130static void setupIOBuffer() {
131 const char *BufferSzStr = 0;
132 BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
133 if (BufferSzStr && BufferSzStr[0]) {
134 VPBufferSize = atoi(BufferSzStr);
135 DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
136 }
Xinliang David Licda3bc22015-12-29 23:54:41 +0000137}
138
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000139/* Read profile data in \c ProfileFile and merge with in-memory
140 profile counters. Returns -1 if there is fatal error, otheriwse
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000141 0 is returned. Returning 0 does not mean merge is actually
142 performed. If merge is actually done, *MergeDone is set to 1.
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000143*/
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000144static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000145 uint64_t ProfileFileSize;
146 char *ProfileBuffer;
147
148 if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
149 PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
150 strerror(errno));
151 return -1;
152 }
153 ProfileFileSize = ftell(ProfileFile);
154
155 /* Restore file offset. */
156 if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
157 PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
158 strerror(errno));
159 return -1;
160 }
161
162 /* Nothing to merge. */
163 if (ProfileFileSize < sizeof(__llvm_profile_header)) {
164 if (ProfileFileSize)
165 PROF_WARN("Unable to merge profile data: %s\n",
166 "source profile file is too small.");
167 return 0;
168 }
169
170 ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE,
171 fileno(ProfileFile), 0);
172 if (ProfileBuffer == MAP_FAILED) {
173 PROF_ERR("Unable to merge profile data, mmap failed: %s\n",
174 strerror(errno));
175 return -1;
176 }
177
178 if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) {
179 (void)munmap(ProfileBuffer, ProfileFileSize);
180 PROF_WARN("Unable to merge profile data: %s\n",
181 "source profile file is not compatible.");
182 return 0;
183 }
184
185 /* Now start merging */
186 __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize);
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000187
Rong Xu95ab7582018-04-02 16:57:00 +0000188 // Truncate the file in case merging of value profile did not happend to
189 // prevent from leaving garbage data at the end of the profile file.
Reid Kleckner963aba32018-04-23 17:05:47 +0000190 COMPILER_RT_FTRUNCATE(ProfileFile, __llvm_profile_get_size_for_buffer());
Rong Xu95ab7582018-04-02 16:57:00 +0000191
192 (void)munmap(ProfileBuffer, ProfileFileSize);
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000193 *MergeDone = 1;
194
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000195 return 0;
196}
197
Xinliang David Lif2d94812017-02-14 21:39:55 +0000198/* Create the directory holding the file, if needed. */
199static void createProfileDir(const char *Filename) {
200 size_t Length = strlen(Filename);
201 if (lprofFindFirstDirSeparator(Filename)) {
202 char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
203 strncpy(Copy, Filename, Length + 1);
204 __llvm_profile_recursive_mkdir(Copy);
205 }
206}
207
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000208/* Open the profile data for merging. It opens the file in r+b mode with
209 * file locking. If the file has content which is compatible with the
210 * current process, it also reads in the profile data in the file and merge
211 * it with in-memory counters. After the profile data is merged in memory,
212 * the original profile data is truncated and gets ready for the profile
213 * dumper. With profile merging enabled, each executable as well as any of
214 * its instrumented shared libraries dump profile data into their own data file.
215*/
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000216static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) {
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000217 FILE *ProfileFile;
218 int rc;
219
Xinliang David Lif2d94812017-02-14 21:39:55 +0000220 createProfileDir(ProfileFileName);
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000221 ProfileFile = lprofOpenFileEx(ProfileFileName);
222 if (!ProfileFile)
223 return NULL;
224
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000225 rc = doProfileMerging(ProfileFile, MergeDone);
226 if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) ||
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000227 fseek(ProfileFile, 0L, SEEK_SET) == -1) {
228 PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
229 strerror(errno));
230 fclose(ProfileFile);
231 return NULL;
232 }
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000233 return ProfileFile;
234}
235
Xinliang David Li315e49d2016-05-24 21:29:18 +0000236/* Write profile data to file \c OutputName. */
237static int writeFile(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000238 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000239 FILE *OutputFile;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000240
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000241 int MergeDone = 0;
Rong Xu95ab7582018-04-02 16:57:00 +0000242 VPMergeHook = &lprofMergeValueProfData;
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000243 if (!doMerging())
244 OutputFile = fopen(OutputName, "ab");
245 else
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000246 OutputFile = openFileForMerging(OutputName, &MergeDone);
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000247
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000248 if (!OutputFile)
249 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000250
Xinliang David Li315e49d2016-05-24 21:29:18 +0000251 FreeHook = &free;
252 setupIOBuffer();
Xinliang David Li967669f2017-06-27 17:28:01 +0000253 ProfDataWriter fileWriter;
254 initFileWriter(&fileWriter, OutputFile);
Xinliang David Lif50cc3e2017-06-28 16:46:06 +0000255 RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000256
257 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000258 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000259}
260
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000261static void truncateCurrentFile(void) {
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000262 const char *Filename;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000263 char *FilenameBuf;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000264 FILE *File;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000265 int Length;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000266
Xinliang David Li315e49d2016-05-24 21:29:18 +0000267 Length = getCurFilenameLength();
268 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
269 Filename = getCurFilename(FilenameBuf);
270 if (!Filename)
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000271 return;
272
Xinliang David Lie3fc4d02016-07-21 03:38:07 +0000273 /* By pass file truncation to allow online raw profile
274 * merging. */
275 if (lprofCurFilename.MergePoolSize)
276 return;
277
Xinliang David Lif2d94812017-02-14 21:39:55 +0000278 createProfileDir(Filename);
279
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000280 /* Truncate the file. Later we'll reopen and append. */
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000281 File = fopen(Filename, "w");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000282 if (!File)
283 return;
284 fclose(File);
285}
286
Xinliang David Li153e8b62016-06-10 20:35:01 +0000287static const char *DefaultProfileName = "default.profraw";
Xinliang David Li315e49d2016-05-24 21:29:18 +0000288static void resetFilenameToDefault(void) {
Xinliang David Li14c91c42016-08-02 19:34:00 +0000289 if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
290 free((void *)lprofCurFilename.FilenamePat);
291 }
Xinliang David Li7f08d122016-05-25 17:30:15 +0000292 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
Xinliang David Li153e8b62016-06-10 20:35:01 +0000293 lprofCurFilename.FilenamePat = DefaultProfileName;
294 lprofCurFilename.PNS = PNS_default;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000295}
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000296
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000297static int containsMergeSpecifier(const char *FilenamePat, int I) {
298 return (FilenamePat[I] == 'm' ||
299 (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' &&
300 /* If FilenamePat[I] is not '\0', the next byte is guaranteed
301 * to be in-bound as the string is null terminated. */
302 FilenamePat[I + 1] == 'm'));
303}
Xinliang David Li7f08d122016-05-25 17:30:15 +0000304
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000305/* Parses the pattern string \p FilenamePat and stores the result to
306 * lprofcurFilename structure. */
Xinliang David Li14c91c42016-08-02 19:34:00 +0000307static int parseFilenamePattern(const char *FilenamePat,
308 unsigned CopyFilenamePat) {
Xinliang David Li315e49d2016-05-24 21:29:18 +0000309 int NumPids = 0, NumHosts = 0, I;
Xinliang David Li7f08d122016-05-25 17:30:15 +0000310 char *PidChars = &lprofCurFilename.PidChars[0];
311 char *Hostname = &lprofCurFilename.Hostname[0];
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000312 int MergingEnabled = 0;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000313
Xinliang David Lib061cdb2016-07-20 05:10:56 +0000314 /* Clean up cached prefix. */
315 if (lprofCurFilename.ProfilePathPrefix)
316 free((void *)lprofCurFilename.ProfilePathPrefix);
317 memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
318
Xinliang David Li14c91c42016-08-02 19:34:00 +0000319 if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
320 free((void *)lprofCurFilename.FilenamePat);
321 }
322
323 if (!CopyFilenamePat)
324 lprofCurFilename.FilenamePat = FilenamePat;
325 else {
326 lprofCurFilename.FilenamePat = strdup(FilenamePat);
327 lprofCurFilename.OwnsFilenamePat = 1;
328 }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000329 /* Check the filename for "%p", which indicates a pid-substitution. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000330 for (I = 0; FilenamePat[I]; ++I)
331 if (FilenamePat[I] == '%') {
332 if (FilenamePat[++I] == 'p') {
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000333 if (!NumPids++) {
Vedant Kumard7c93362017-12-14 19:01:04 +0000334 if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) {
Bob Haarman9ee65ac2016-11-29 15:24:00 +0000335 PROF_WARN("Unable to get pid for filename pattern %s. Using the "
336 "default name.",
337 FilenamePat);
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000338 return -1;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000339 }
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000340 }
Xinliang David Li315e49d2016-05-24 21:29:18 +0000341 } else if (FilenamePat[I] == 'h') {
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000342 if (!NumHosts++)
Xinliang David Li315e49d2016-05-24 21:29:18 +0000343 if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {
Bob Haarman9ee65ac2016-11-29 15:24:00 +0000344 PROF_WARN("Unable to get hostname for filename pattern %s. Using "
345 "the default name.",
346 FilenamePat);
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000347 return -1;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000348 }
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000349 } else if (containsMergeSpecifier(FilenamePat, I)) {
350 if (MergingEnabled) {
Vedant Kumar8e2dd512016-06-14 17:23:13 +0000351 PROF_WARN("%%m specifier can only be specified once in %s.\n",
352 FilenamePat);
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000353 return -1;
354 }
355 MergingEnabled = 1;
356 if (FilenamePat[I] == 'm')
357 lprofCurFilename.MergePoolSize = 1;
358 else {
359 lprofCurFilename.MergePoolSize = FilenamePat[I] - '0';
360 I++; /* advance to 'm' */
361 }
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000362 }
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000363 }
364
Xinliang David Li7f08d122016-05-25 17:30:15 +0000365 lprofCurFilename.NumPids = NumPids;
366 lprofCurFilename.NumHosts = NumHosts;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000367 return 0;
368}
369
Xinliang David Li153e8b62016-06-10 20:35:01 +0000370static void parseAndSetFilename(const char *FilenamePat,
Xinliang David Li14c91c42016-08-02 19:34:00 +0000371 ProfileNameSpecifier PNS,
372 unsigned CopyFilenamePat) {
Xinliang David Li7f08d122016-05-25 17:30:15 +0000373
Xinliang David Li153e8b62016-06-10 20:35:01 +0000374 const char *OldFilenamePat = lprofCurFilename.FilenamePat;
375 ProfileNameSpecifier OldPNS = lprofCurFilename.PNS;
376
377 if (PNS < OldPNS)
378 return;
379
380 if (!FilenamePat)
381 FilenamePat = DefaultProfileName;
382
Xinliang David Li153e8b62016-06-10 20:35:01 +0000383 if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) {
384 lprofCurFilename.PNS = PNS;
385 return;
386 }
387
388 /* When PNS >= OldPNS, the last one wins. */
Xinliang David Li14c91c42016-08-02 19:34:00 +0000389 if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat))
Xinliang David Li7f08d122016-05-25 17:30:15 +0000390 resetFilenameToDefault();
Xinliang David Li153e8b62016-06-10 20:35:01 +0000391 lprofCurFilename.PNS = PNS;
Xinliang David Li7f08d122016-05-25 17:30:15 +0000392
Xinliang David Li153e8b62016-06-10 20:35:01 +0000393 if (!OldFilenamePat) {
Xinliang David Lie68df592016-09-22 21:00:29 +0000394 if (getenv("LLVM_PROFILE_VERBOSE"))
395 PROF_NOTE("Set profile file path to \"%s\" via %s.\n",
396 lprofCurFilename.FilenamePat, getPNSStr(PNS));
Xinliang David Li153e8b62016-06-10 20:35:01 +0000397 } else {
Xinliang David Lie68df592016-09-22 21:00:29 +0000398 if (getenv("LLVM_PROFILE_VERBOSE"))
399 PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",
400 OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat,
401 getPNSStr(PNS));
Xinliang David Li153e8b62016-06-10 20:35:01 +0000402 }
Xinliang David Li7f08d122016-05-25 17:30:15 +0000403
Xinliang David Lie3fc4d02016-07-21 03:38:07 +0000404 truncateCurrentFile();
Xinliang David Li7f08d122016-05-25 17:30:15 +0000405}
406
Xinliang David Li315e49d2016-05-24 21:29:18 +0000407/* Return buffer length that is required to store the current profile
408 * filename with PID and hostname substitutions. */
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000409/* The length to hold uint64_t followed by 2 digit pool id including '_' */
410#define SIGLEN 24
Xinliang David Li315e49d2016-05-24 21:29:18 +0000411static int getCurFilenameLength() {
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000412 int Len;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000413 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000414 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000415
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000416 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
417 lprofCurFilename.MergePoolSize))
Xinliang David Li315e49d2016-05-24 21:29:18 +0000418 return strlen(lprofCurFilename.FilenamePat);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000419
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000420 Len = strlen(lprofCurFilename.FilenamePat) +
421 lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
422 lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2);
423 if (lprofCurFilename.MergePoolSize)
424 Len += SIGLEN;
425 return Len;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000426}
427
428/* Return the pointer to the current profile file name (after substituting
429 * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
430 * to store the resulting filename. If no substitution is needed, the
431 * current filename pattern string is directly returned. */
432static const char *getCurFilename(char *FilenameBuf) {
433 int I, J, PidLength, HostNameLength;
434 const char *FilenamePat = lprofCurFilename.FilenamePat;
435
436 if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
437 return 0;
438
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000439 if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
440 lprofCurFilename.MergePoolSize))
Xinliang David Li315e49d2016-05-24 21:29:18 +0000441 return lprofCurFilename.FilenamePat;
442
443 PidLength = strlen(lprofCurFilename.PidChars);
444 HostNameLength = strlen(lprofCurFilename.Hostname);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000445 /* Construct the new filename. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000446 for (I = 0, J = 0; FilenamePat[I]; ++I)
447 if (FilenamePat[I] == '%') {
448 if (FilenamePat[++I] == 'p') {
449 memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000450 J += PidLength;
Xinliang David Li315e49d2016-05-24 21:29:18 +0000451 } else if (FilenamePat[I] == 'h') {
452 memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000453 J += HostNameLength;
Xinliang David Lie2ce2e02016-06-08 23:43:56 +0000454 } else if (containsMergeSpecifier(FilenamePat, I)) {
455 char LoadModuleSignature[SIGLEN];
456 int S;
457 int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize;
458 S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d",
459 lprofGetLoadModuleSignature(), ProfilePoolId);
460 if (S == -1 || S > SIGLEN)
461 S = SIGLEN;
462 memcpy(FilenameBuf + J, LoadModuleSignature, S);
463 J += S;
464 if (FilenamePat[I] != 'm')
465 I++;
Vedant Kumara06e8ca2016-01-29 23:52:11 +0000466 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000467 /* Drop any unknown substitutions. */
468 } else
Xinliang David Li315e49d2016-05-24 21:29:18 +0000469 FilenameBuf[J++] = FilenamePat[I];
470 FilenameBuf[J] = 0;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000471
Xinliang David Li315e49d2016-05-24 21:29:18 +0000472 return FilenameBuf;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000473}
474
Xinliang David Li315e49d2016-05-24 21:29:18 +0000475/* Returns the pointer to the environment variable
476 * string. Returns null if the env var is not set. */
477static const char *getFilenamePatFromEnv(void) {
Eric Christopherd641b532015-04-28 22:54:51 +0000478 const char *Filename = getenv("LLVM_PROFILE_FILE");
Eric Christopherd641b532015-04-28 22:54:51 +0000479 if (!Filename || !Filename[0])
Xinliang David Li51fe0022016-05-24 01:23:09 +0000480 return 0;
481 return Filename;
Eric Christopherd641b532015-04-28 22:54:51 +0000482}
483
Xinliang David Lieaf238d2016-07-20 04:26:09 +0000484COMPILER_RT_VISIBILITY
485const char *__llvm_profile_get_path_prefix(void) {
486 int Length;
487 char *FilenameBuf, *Prefix;
488 const char *Filename, *PrefixEnd;
489
490 if (lprofCurFilename.ProfilePathPrefix)
491 return lprofCurFilename.ProfilePathPrefix;
492
493 Length = getCurFilenameLength();
494 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
495 Filename = getCurFilename(FilenameBuf);
496 if (!Filename)
497 return "\0";
498
499 PrefixEnd = lprofFindLastDirSeparator(Filename);
500 if (!PrefixEnd)
501 return "\0";
502
503 Length = PrefixEnd - Filename + 1;
504 Prefix = (char *)malloc(Length + 1);
505 if (!Prefix) {
506 PROF_ERR("Failed to %s\n", "allocate memory.");
507 return "\0";
508 }
509 memcpy(Prefix, Filename, Length);
510 Prefix[Length] = '\0';
511 lprofCurFilename.ProfilePathPrefix = Prefix;
512 return Prefix;
513}
514
Xinliang David Li51fe0022016-05-24 01:23:09 +0000515/* This method is invoked by the runtime initialization hook
516 * InstrProfilingRuntime.o if it is linked in. Both user specified
517 * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
518 * environment variable can override this default value. */
Xinliang David Liabfd5532015-12-16 03:29:15 +0000519COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000520void __llvm_profile_initialize_file(void) {
Xinliang David Lie9539332016-07-21 23:19:18 +0000521 const char *EnvFilenamePat;
Xinliang David Li1c9320c2017-08-15 03:13:01 +0000522 const char *SelectedPat = NULL;
523 ProfileNameSpecifier PNS = PNS_unknown;
Xinliang David Lie9539332016-07-21 23:19:18 +0000524 int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000525
Xinliang David Lie9539332016-07-21 23:19:18 +0000526 EnvFilenamePat = getFilenamePatFromEnv();
Xinliang David Li1c9320c2017-08-15 03:13:01 +0000527 if (EnvFilenamePat) {
Xinliang David Lic7c53032017-08-23 21:39:33 +0000528 /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid
529 at the moment when __llvm_profile_write_file() gets executed. */
530 parseAndSetFilename(EnvFilenamePat, PNS_environment, 1);
531 return;
Xinliang David Li1c9320c2017-08-15 03:13:01 +0000532 } else if (hasCommandLineOverrider) {
533 SelectedPat = INSTR_PROF_PROFILE_NAME_VAR;
534 PNS = PNS_command_line;
Xinliang David Lie9539332016-07-21 23:19:18 +0000535 } else {
Xinliang David Li1c9320c2017-08-15 03:13:01 +0000536 SelectedPat = NULL;
537 PNS = PNS_default;
Xinliang David Lie9539332016-07-21 23:19:18 +0000538 }
539
Xinliang David Li1c9320c2017-08-15 03:13:01 +0000540 parseAndSetFilename(SelectedPat, PNS, 0);
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000541}
542
Xinliang David Li51fe0022016-05-24 01:23:09 +0000543/* This API is directly called by the user application code. It has the
544 * highest precedence compared with LLVM_PROFILE_FILE environment variable
Xinliang David Li41518942016-05-24 02:37:07 +0000545 * and command line option -fprofile-instr-generate=<profile_name>.
Xinliang David Li51fe0022016-05-24 01:23:09 +0000546 */
Xinliang David Liabfd5532015-12-16 03:29:15 +0000547COMPILER_RT_VISIBILITY
Xinliang David Li315e49d2016-05-24 21:29:18 +0000548void __llvm_profile_set_filename(const char *FilenamePat) {
Xinliang David Li14c91c42016-08-02 19:34:00 +0000549 parseAndSetFilename(FilenamePat, PNS_runtime_api, 1);
Eric Christopherd641b532015-04-28 22:54:51 +0000550}
551
Xinliang David Li315e49d2016-05-24 21:29:18 +0000552/* The public API for writing profile data into the file with name
553 * set by previous calls to __llvm_profile_set_filename or
554 * __llvm_profile_override_default_filename or
555 * __llvm_profile_initialize_file. */
Xinliang David Liabfd5532015-12-16 03:29:15 +0000556COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000557int __llvm_profile_write_file(void) {
Xinliang David Li315e49d2016-05-24 21:29:18 +0000558 int rc, Length;
559 const char *Filename;
560 char *FilenameBuf;
Rong Xucf1f6fb2017-03-17 18:41:33 +0000561 int PDeathSig = 0;
Vasileios Kalintirisc9c7a3e2015-02-25 13:50:18 +0000562
Xinliang David Li3b2c0022016-08-09 04:21:14 +0000563 if (lprofProfileDumped()) {
564 PROF_NOTE("Profile data not written to file: %s.\n",
565 "already written");
566 return 0;
567 }
568
Xinliang David Li315e49d2016-05-24 21:29:18 +0000569 Length = getCurFilenameLength();
570 FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
571 Filename = getCurFilename(FilenameBuf);
572
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000573 /* Check the filename. */
Xinliang David Li315e49d2016-05-24 21:29:18 +0000574 if (!Filename) {
Xinliang David Li690c31f2016-05-20 05:15:42 +0000575 PROF_ERR("Failed to write file : %s\n", "Filename not set");
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000576 return -1;
Xinliang David Li9ea30642015-12-03 18:31:59 +0000577 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000578
Xinliang David Lid85c32c2016-01-08 23:42:28 +0000579 /* Check if there is llvm/runtime version mismatch. */
Xinliang David Lia6924212016-01-08 23:31:57 +0000580 if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
Xinliang David Li690c31f2016-05-20 05:15:42 +0000581 PROF_ERR("Runtime and instrumentation version mismatch : "
Xinliang David Lia6924212016-01-08 23:31:57 +0000582 "expected %d, but get %d\n",
583 INSTR_PROF_RAW_VERSION,
584 (int)GET_VERSION(__llvm_profile_get_version()));
585 return -1;
586 }
587
Rong Xucf1f6fb2017-03-17 18:41:33 +0000588 // Temporarily suspend getting SIGKILL when the parent exits.
589 PDeathSig = lprofSuspendSigKill();
590
Xinliang David Li315e49d2016-05-24 21:29:18 +0000591 /* Write profile data to the file. */
592 rc = writeFile(Filename);
Xinliang David Li9ea30642015-12-03 18:31:59 +0000593 if (rc)
Xinliang David Li315e49d2016-05-24 21:29:18 +0000594 PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
Rong Xucf1f6fb2017-03-17 18:41:33 +0000595
596 // Restore SIGKILL.
597 if (PDeathSig == 1)
598 lprofRestoreSigKill();
599
Justin Bogner66fd5c92015-01-16 20:10:56 +0000600 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000601}
602
Xinliang David Li3b2c0022016-08-09 04:21:14 +0000603COMPILER_RT_VISIBILITY
604int __llvm_profile_dump(void) {
605 if (!doMerging())
606 PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering "
Nico Weber81291a02016-09-08 01:46:52 +0000607 " of previously dumped profile data : %s. Either use %%m "
Xinliang David Li3b2c0022016-08-09 04:21:14 +0000608 "in profile name or change profile name before dumping.\n",
609 "online profile merging is not on");
610 int rc = __llvm_profile_write_file();
611 lprofSetProfileDumped();
612 return rc;
613}
614
Xinliang David Li6fe18f42015-11-23 04:38:17 +0000615static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000616
Xinliang David Liabfd5532015-12-16 03:29:15 +0000617COMPILER_RT_VISIBILITY
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000618int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000619 static int HasBeenRegistered = 0;
620
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000621 if (HasBeenRegistered)
622 return 0;
623
Xinliang David Li4617aa72016-05-18 22:34:05 +0000624 lprofSetupValueProfiler();
625
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000626 HasBeenRegistered = 1;
627 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000628}