Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
emscripten-core
GitHub Repository: emscripten-core/emscripten
Path: blob/main/system/lib/compiler-rt/lib/profile/InstrProfilingFile.c
7088 views
1
/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
2
|*
3
|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
|* See https://llvm.org/LICENSE.txt for license information.
5
|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
|*
7
\*===----------------------------------------------------------------------===*/
8
9
#if !defined(__Fuchsia__)
10
11
#include <assert.h>
12
#include <errno.h>
13
#include <stdio.h>
14
#include <stdlib.h>
15
#include <string.h>
16
#ifdef _MSC_VER
17
/* For _alloca. */
18
#include <malloc.h>
19
#endif
20
#if defined(_WIN32)
21
#include "WindowsMMap.h"
22
/* For _chsize_s */
23
#include <io.h>
24
#include <process.h>
25
#else
26
#include <sys/file.h>
27
#include <sys/mman.h>
28
#include <unistd.h>
29
#if defined(__linux__)
30
#include <sys/types.h>
31
#endif
32
#endif
33
34
#include "InstrProfiling.h"
35
#include "InstrProfilingInternal.h"
36
#include "InstrProfilingPort.h"
37
#include "InstrProfilingUtil.h"
38
39
/* From where is profile name specified.
40
* The order the enumerators define their
41
* precedence. Re-order them may lead to
42
* runtime behavior change. */
43
typedef enum ProfileNameSpecifier {
44
PNS_unknown = 0,
45
PNS_default,
46
PNS_command_line,
47
PNS_environment,
48
PNS_runtime_api
49
} ProfileNameSpecifier;
50
51
static const char *getPNSStr(ProfileNameSpecifier PNS) {
52
switch (PNS) {
53
case PNS_default:
54
return "default setting";
55
case PNS_command_line:
56
return "command line";
57
case PNS_environment:
58
return "environment variable";
59
case PNS_runtime_api:
60
return "runtime API";
61
default:
62
return "Unknown";
63
}
64
}
65
66
#define MAX_PID_SIZE 16
67
/* Data structure holding the result of parsed filename pattern. */
68
typedef struct lprofFilename {
69
/* File name string possibly with %p or %h specifiers. */
70
const char *FilenamePat;
71
/* A flag indicating if FilenamePat's memory is allocated
72
* by runtime. */
73
unsigned OwnsFilenamePat;
74
const char *ProfilePathPrefix;
75
char PidChars[MAX_PID_SIZE];
76
char *TmpDir;
77
char Hostname[COMPILER_RT_MAX_HOSTLEN];
78
unsigned NumPids;
79
unsigned NumHosts;
80
unsigned NumBinaryIds;
81
/* When in-process merging is enabled, this parameter specifies
82
* the total number of profile data files shared by all the processes
83
* spawned from the same binary. By default the value is 1. If merging
84
* is not enabled, its value should be 0. This parameter is specified
85
* by the %[0-9]m specifier. For instance %2m enables merging using
86
* 2 profile data files. %1m is equivalent to %m. Also %m specifier
87
* can only appear once at the end of the name pattern. */
88
unsigned MergePoolSize;
89
ProfileNameSpecifier PNS;
90
} lprofFilename;
91
92
static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL, {0},
93
0, 0, 0, 0, PNS_unknown};
94
95
static int ProfileMergeRequested = 0;
96
static int getProfileFileSizeForMerging(FILE *ProfileFile,
97
uint64_t *ProfileFileSize);
98
99
#if defined(__APPLE__)
100
static const int ContinuousModeSupported = 1;
101
static const int UseBiasVar = 0;
102
static const char *FileOpenMode = "a+b";
103
static void *BiasAddr = NULL;
104
static void *BiasDefaultAddr = NULL;
105
static void *BitmapBiasAddr = NULL;
106
static void *BitmapBiasDefaultAddr = NULL;
107
static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
108
/* Get the sizes of various profile data sections. Taken from
109
* __llvm_profile_get_size_for_buffer(). */
110
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
111
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
112
const char *CountersBegin = __llvm_profile_begin_counters();
113
const char *CountersEnd = __llvm_profile_end_counters();
114
const char *BitmapBegin = __llvm_profile_begin_bitmap();
115
const char *BitmapEnd = __llvm_profile_end_bitmap();
116
const char *NamesBegin = __llvm_profile_begin_names();
117
const char *NamesEnd = __llvm_profile_end_names();
118
const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char);
119
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
120
uint64_t CountersSize =
121
__llvm_profile_get_counters_size(CountersBegin, CountersEnd);
122
uint64_t NumBitmapBytes =
123
__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
124
125
/* Check that the counter, bitmap, and data sections in this image are
126
* page-aligned. */
127
unsigned PageSize = getpagesize();
128
if ((intptr_t)CountersBegin % PageSize != 0) {
129
PROF_ERR("Counters section not page-aligned (start = %p, pagesz = %u).\n",
130
CountersBegin, PageSize);
131
return 1;
132
}
133
if ((intptr_t)BitmapBegin % PageSize != 0) {
134
PROF_ERR("Bitmap section not page-aligned (start = %p, pagesz = %u).\n",
135
BitmapBegin, PageSize);
136
return 1;
137
}
138
if ((intptr_t)DataBegin % PageSize != 0) {
139
PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n",
140
DataBegin, PageSize);
141
return 1;
142
}
143
144
int Fileno = fileno(File);
145
/* Determine how much padding is needed before/after the counters and
146
* after the names. */
147
uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters,
148
PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes,
149
PaddingBytesAfterVTable, PaddingBytesAfterVNames;
150
__llvm_profile_get_padding_sizes_for_counters(
151
DataSize, CountersSize, NumBitmapBytes, NamesSize, /*VTableSize=*/0,
152
/*VNameSize=*/0, &PaddingBytesBeforeCounters, &PaddingBytesAfterCounters,
153
&PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames,
154
&PaddingBytesAfterVTable, &PaddingBytesAfterVNames);
155
156
uint64_t PageAlignedCountersLength = CountersSize + PaddingBytesAfterCounters;
157
uint64_t FileOffsetToCounters = CurrentFileOffset +
158
sizeof(__llvm_profile_header) + DataSize +
159
PaddingBytesBeforeCounters;
160
void *CounterMmap = mmap((void *)CountersBegin, PageAlignedCountersLength,
161
PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
162
Fileno, FileOffsetToCounters);
163
if (CounterMmap != CountersBegin) {
164
PROF_ERR(
165
"Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
166
" - CountersBegin: %p\n"
167
" - PageAlignedCountersLength: %" PRIu64 "\n"
168
" - Fileno: %d\n"
169
" - FileOffsetToCounters: %" PRIu64 "\n",
170
strerror(errno), CountersBegin, PageAlignedCountersLength, Fileno,
171
FileOffsetToCounters);
172
return 1;
173
}
174
175
/* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()
176
* will fail with EINVAL. */
177
if (NumBitmapBytes == 0)
178
return 0;
179
180
uint64_t PageAlignedBitmapLength =
181
NumBitmapBytes + PaddingBytesAfterBitmapBytes;
182
uint64_t FileOffsetToBitmap =
183
FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters;
184
void *BitmapMmap =
185
mmap((void *)BitmapBegin, PageAlignedBitmapLength, PROT_READ | PROT_WRITE,
186
MAP_FIXED | MAP_SHARED, Fileno, FileOffsetToBitmap);
187
if (BitmapMmap != BitmapBegin) {
188
PROF_ERR(
189
"Continuous counter sync mode is enabled, but mmap() failed (%s).\n"
190
" - BitmapBegin: %p\n"
191
" - PageAlignedBitmapLength: %" PRIu64 "\n"
192
" - Fileno: %d\n"
193
" - FileOffsetToBitmap: %" PRIu64 "\n",
194
strerror(errno), BitmapBegin, PageAlignedBitmapLength, Fileno,
195
FileOffsetToBitmap);
196
return 1;
197
}
198
return 0;
199
}
200
#elif defined(__ELF__) || defined(_WIN32) || defined(_AIX)
201
202
#define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR \
203
INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR, _default)
204
COMPILER_RT_VISIBILITY int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR = 0;
205
#define INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR \
206
INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_BITMAP_BIAS_VAR, _default)
207
COMPILER_RT_VISIBILITY int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR = 0;
208
209
/* This variable is a weak external reference which could be used to detect
210
* whether or not the compiler defined this symbol. */
211
#if defined(_MSC_VER)
212
COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
213
COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR;
214
#if defined(_M_IX86) || defined(__i386__)
215
#define WIN_SYM_PREFIX "_"
216
#else
217
#define WIN_SYM_PREFIX
218
#endif
219
#pragma comment( \
220
linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \
221
INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \
222
INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))
223
#pragma comment( \
224
linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \
225
INSTR_PROF_PROFILE_BITMAP_BIAS_VAR) "=" WIN_SYM_PREFIX \
226
INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR))
227
#else
228
COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR
229
__attribute__((weak, alias(INSTR_PROF_QUOTE(
230
INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR))));
231
COMPILER_RT_VISIBILITY extern int64_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR
232
__attribute__((weak, alias(INSTR_PROF_QUOTE(
233
INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR))));
234
#endif
235
static const int ContinuousModeSupported = 1;
236
static const int UseBiasVar = 1;
237
/* TODO: If there are two DSOs, the second DSO initialization will truncate the
238
* first profile file. */
239
static const char *FileOpenMode = "w+b";
240
/* This symbol is defined by the compiler when runtime counter relocation is
241
* used and runtime provides a weak alias so we can check if it's defined. */
242
static void *BiasAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_VAR;
243
static void *BiasDefaultAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR;
244
static void *BitmapBiasAddr = &INSTR_PROF_PROFILE_BITMAP_BIAS_VAR;
245
static void *BitmapBiasDefaultAddr =
246
&INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR;
247
static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
248
/* Get the sizes of various profile data sections. Taken from
249
* __llvm_profile_get_size_for_buffer(). */
250
const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
251
const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
252
const char *CountersBegin = __llvm_profile_begin_counters();
253
const char *CountersEnd = __llvm_profile_end_counters();
254
const char *BitmapBegin = __llvm_profile_begin_bitmap();
255
const char *BitmapEnd = __llvm_profile_end_bitmap();
256
uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd);
257
uint64_t CountersSize =
258
__llvm_profile_get_counters_size(CountersBegin, CountersEnd);
259
uint64_t NumBitmapBytes =
260
__llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd);
261
/* Get the file size. */
262
uint64_t FileSize = 0;
263
if (getProfileFileSizeForMerging(File, &FileSize))
264
return 1;
265
266
int Fileno = fileno(File);
267
uint64_t PaddingBytesAfterCounters =
268
__llvm_profile_get_num_padding_bytes(CountersSize);
269
uint64_t FileOffsetToCounters =
270
sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) + DataSize;
271
272
/* Map the profile. */
273
char *Profile = (char *)mmap(NULL, FileSize, PROT_READ | PROT_WRITE,
274
MAP_SHARED, Fileno, 0);
275
if (Profile == MAP_FAILED) {
276
PROF_ERR("Unable to mmap profile: %s\n", strerror(errno));
277
return 1;
278
}
279
/* Update the profile fields based on the current mapping. */
280
INSTR_PROF_PROFILE_COUNTER_BIAS_VAR =
281
(intptr_t)Profile - (uintptr_t)CountersBegin + FileOffsetToCounters;
282
283
/* Return the memory allocated for counters to OS. */
284
lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd);
285
286
/* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap()
287
* will fail with EINVAL. */
288
if (NumBitmapBytes == 0)
289
return 0;
290
291
/* Update profbm_bias. */
292
uint64_t FileOffsetToBitmap =
293
FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters;
294
/* Update the profile fields based on the current mapping. */
295
INSTR_PROF_PROFILE_BITMAP_BIAS_VAR =
296
(uintptr_t)Profile - (uintptr_t)BitmapBegin + FileOffsetToBitmap;
297
298
/* Return the memory allocated for counters to OS. */
299
lprofReleaseMemoryPagesToOS((uintptr_t)BitmapBegin, (uintptr_t)BitmapEnd);
300
return 0;
301
}
302
#else
303
static const int ContinuousModeSupported = 0;
304
static const int UseBiasVar = 0;
305
static const char *FileOpenMode = "a+b";
306
static void *BiasAddr = NULL;
307
static void *BiasDefaultAddr = NULL;
308
static void *BitmapBiasAddr = NULL;
309
static void *BitmapBiasDefaultAddr = NULL;
310
static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) {
311
return 0;
312
}
313
#endif
314
315
static int isProfileMergeRequested(void) { return ProfileMergeRequested; }
316
static void setProfileMergeRequested(int EnableMerge) {
317
ProfileMergeRequested = EnableMerge;
318
}
319
320
static FILE *ProfileFile = NULL;
321
static FILE *getProfileFile(void) { return ProfileFile; }
322
static void setProfileFile(FILE *File) { ProfileFile = File; }
323
324
static int getCurFilenameLength(void);
325
static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf);
326
static unsigned doMerging(void) {
327
return lprofCurFilename.MergePoolSize || isProfileMergeRequested();
328
}
329
330
/* Return 1 if there is an error, otherwise return 0. */
331
static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
332
uint32_t NumIOVecs) {
333
uint32_t I;
334
FILE *File = (FILE *)This->WriterCtx;
335
char Zeroes[sizeof(uint64_t)] = {0};
336
for (I = 0; I < NumIOVecs; I++) {
337
if (IOVecs[I].Data) {
338
if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
339
IOVecs[I].NumElm)
340
return 1;
341
} else if (IOVecs[I].UseZeroPadding) {
342
size_t BytesToWrite = IOVecs[I].ElmSize * IOVecs[I].NumElm;
343
while (BytesToWrite > 0) {
344
size_t PartialWriteLen =
345
(sizeof(uint64_t) > BytesToWrite) ? BytesToWrite : sizeof(uint64_t);
346
if (fwrite(Zeroes, sizeof(uint8_t), PartialWriteLen, File) !=
347
PartialWriteLen) {
348
return 1;
349
}
350
BytesToWrite -= PartialWriteLen;
351
}
352
} else {
353
if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1)
354
return 1;
355
}
356
}
357
return 0;
358
}
359
360
static void initFileWriter(ProfDataWriter *This, FILE *File) {
361
This->Write = fileWriter;
362
This->WriterCtx = File;
363
}
364
365
COMPILER_RT_VISIBILITY ProfBufferIO *
366
lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) {
367
FreeHook = &free;
368
DynamicBufferIOBuffer = (uint8_t *)calloc(1, BufferSz);
369
VPBufferSize = BufferSz;
370
ProfDataWriter *fileWriter =
371
(ProfDataWriter *)calloc(1, sizeof(ProfDataWriter));
372
initFileWriter(fileWriter, File);
373
ProfBufferIO *IO = lprofCreateBufferIO(fileWriter);
374
IO->OwnFileWriter = 1;
375
return IO;
376
}
377
378
static void setupIOBuffer(void) {
379
const char *BufferSzStr = 0;
380
BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
381
if (BufferSzStr && BufferSzStr[0]) {
382
VPBufferSize = atoi(BufferSzStr);
383
DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1);
384
}
385
}
386
387
/* Get the size of the profile file. If there are any errors, print the
388
* message under the assumption that the profile is being read for merging
389
* purposes, and return -1. Otherwise return the file size in the inout param
390
* \p ProfileFileSize. */
391
static int getProfileFileSizeForMerging(FILE *ProfileFile,
392
uint64_t *ProfileFileSize) {
393
if (fseek(ProfileFile, 0L, SEEK_END) == -1) {
394
PROF_ERR("Unable to merge profile data, unable to get size: %s\n",
395
strerror(errno));
396
return -1;
397
}
398
*ProfileFileSize = ftell(ProfileFile);
399
400
/* Restore file offset. */
401
if (fseek(ProfileFile, 0L, SEEK_SET) == -1) {
402
PROF_ERR("Unable to merge profile data, unable to rewind: %s\n",
403
strerror(errno));
404
return -1;
405
}
406
407
if (*ProfileFileSize > 0 &&
408
*ProfileFileSize < sizeof(__llvm_profile_header)) {
409
PROF_WARN("Unable to merge profile data: %s\n",
410
"source profile file is too small.");
411
return -1;
412
}
413
return 0;
414
}
415
416
/* mmap() \p ProfileFile for profile merging purposes, assuming that an
417
* exclusive lock is held on the file and that \p ProfileFileSize is the
418
* length of the file. Return the mmap'd buffer in the inout variable
419
* \p ProfileBuffer. Returns -1 on failure. On success, the caller is
420
* responsible for unmapping the mmap'd buffer in \p ProfileBuffer. */
421
static int mmapProfileForMerging(FILE *ProfileFile, uint64_t ProfileFileSize,
422
ManagedMemory *ProfileBuffer) {
423
lprofGetFileContentBuffer(ProfileFile, ProfileFileSize, ProfileBuffer);
424
425
if (ProfileBuffer->Status == MS_INVALID) {
426
PROF_ERR("Unable to merge profile data: %s\n", "reading file failed");
427
return -1;
428
}
429
430
if (__llvm_profile_check_compatibility(ProfileBuffer->Addr,
431
ProfileFileSize)) {
432
(void)lprofReleaseBuffer(ProfileBuffer, ProfileFileSize);
433
PROF_WARN("Unable to merge profile data: %s\n",
434
"source profile file is not compatible.");
435
return -1;
436
}
437
return 0;
438
}
439
440
/* Read profile data in \c ProfileFile and merge with in-memory
441
profile counters. Returns -1 if there is fatal error, otherwise
442
0 is returned. Returning 0 does not mean merge is actually
443
performed. If merge is actually done, *MergeDone is set to 1.
444
*/
445
static int doProfileMerging(FILE *ProfileFile, int *MergeDone) {
446
uint64_t ProfileFileSize;
447
ManagedMemory ProfileBuffer;
448
449
/* Get the size of the profile on disk. */
450
if (getProfileFileSizeForMerging(ProfileFile, &ProfileFileSize) == -1)
451
return -1;
452
453
/* Nothing to merge. */
454
if (!ProfileFileSize)
455
return 0;
456
457
/* mmap() the profile and check that it is compatible with the data in
458
* the current image. */
459
if (mmapProfileForMerging(ProfileFile, ProfileFileSize, &ProfileBuffer) == -1)
460
return -1;
461
462
/* Now start merging */
463
if (__llvm_profile_merge_from_buffer(ProfileBuffer.Addr, ProfileFileSize)) {
464
PROF_ERR("%s\n", "Invalid profile data to merge");
465
(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);
466
return -1;
467
}
468
469
// Truncate the file in case merging of value profile did not happen to
470
// prevent from leaving garbage data at the end of the profile file.
471
(void)COMPILER_RT_FTRUNCATE(ProfileFile,
472
__llvm_profile_get_size_for_buffer());
473
474
(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);
475
*MergeDone = 1;
476
477
return 0;
478
}
479
480
/* Create the directory holding the file, if needed. */
481
static void createProfileDir(const char *Filename) {
482
size_t Length = strlen(Filename);
483
if (lprofFindFirstDirSeparator(Filename)) {
484
char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1);
485
strncpy(Copy, Filename, Length + 1);
486
__llvm_profile_recursive_mkdir(Copy);
487
}
488
}
489
490
/* Open the profile data for merging. It opens the file in r+b mode with
491
* file locking. If the file has content which is compatible with the
492
* current process, it also reads in the profile data in the file and merge
493
* it with in-memory counters. After the profile data is merged in memory,
494
* the original profile data is truncated and gets ready for the profile
495
* dumper. With profile merging enabled, each executable as well as any of
496
* its instrumented shared libraries dump profile data into their own data file.
497
*/
498
static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) {
499
FILE *ProfileFile = getProfileFile();
500
int rc;
501
// initializeProfileForContinuousMode will lock the profile, but if
502
// ProfileFile is set by user via __llvm_profile_set_file_object, it's assumed
503
// unlocked at this point.
504
if (ProfileFile && !__llvm_profile_is_continuous_mode_enabled()) {
505
lprofLockFileHandle(ProfileFile);
506
}
507
if (!ProfileFile) {
508
createProfileDir(ProfileFileName);
509
ProfileFile = lprofOpenFileEx(ProfileFileName);
510
}
511
if (!ProfileFile)
512
return NULL;
513
514
rc = doProfileMerging(ProfileFile, MergeDone);
515
if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) ||
516
fseek(ProfileFile, 0L, SEEK_SET) == -1) {
517
PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName,
518
strerror(errno));
519
fclose(ProfileFile);
520
return NULL;
521
}
522
return ProfileFile;
523
}
524
525
static FILE *getFileObject(const char *OutputName) {
526
FILE *File;
527
File = getProfileFile();
528
if (File != NULL) {
529
return File;
530
}
531
532
return fopen(OutputName, "ab");
533
}
534
535
static void closeFileObject(FILE *OutputFile) {
536
if (OutputFile == getProfileFile()) {
537
fflush(OutputFile);
538
if (doMerging() && !__llvm_profile_is_continuous_mode_enabled()) {
539
lprofUnlockFileHandle(OutputFile);
540
}
541
} else {
542
fclose(OutputFile);
543
}
544
}
545
546
/* Write profile data to file \c OutputName. */
547
static int writeFile(const char *OutputName) {
548
int RetVal;
549
FILE *OutputFile;
550
551
int MergeDone = 0;
552
VPMergeHook = &lprofMergeValueProfData;
553
if (doMerging())
554
OutputFile = openFileForMerging(OutputName, &MergeDone);
555
else
556
OutputFile = getFileObject(OutputName);
557
558
if (!OutputFile)
559
return -1;
560
561
FreeHook = &free;
562
setupIOBuffer();
563
ProfDataWriter fileWriter;
564
initFileWriter(&fileWriter, OutputFile);
565
RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone);
566
567
closeFileObject(OutputFile);
568
return RetVal;
569
}
570
571
#define LPROF_INIT_ONCE_ENV "__LLVM_PROFILE_RT_INIT_ONCE"
572
573
static void truncateCurrentFile(void) {
574
const char *Filename;
575
char *FilenameBuf;
576
FILE *File;
577
int Length;
578
579
Length = getCurFilenameLength();
580
FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
581
Filename = getCurFilename(FilenameBuf, 0);
582
if (!Filename)
583
return;
584
585
/* Only create the profile directory and truncate an existing profile once.
586
* In continuous mode, this is necessary, as the profile is written-to by the
587
* runtime initializer. */
588
int initialized = getenv(LPROF_INIT_ONCE_ENV) != NULL;
589
if (initialized)
590
return;
591
#if defined(_WIN32)
592
_putenv(LPROF_INIT_ONCE_ENV "=" LPROF_INIT_ONCE_ENV);
593
#else
594
setenv(LPROF_INIT_ONCE_ENV, LPROF_INIT_ONCE_ENV, 1);
595
#endif
596
597
/* Create the profile dir (even if online merging is enabled), so that
598
* the profile file can be set up if continuous mode is enabled. */
599
createProfileDir(Filename);
600
601
/* By pass file truncation to allow online raw profile merging. */
602
if (lprofCurFilename.MergePoolSize)
603
return;
604
605
/* Truncate the file. Later we'll reopen and append. */
606
File = fopen(Filename, "w");
607
if (!File)
608
return;
609
fclose(File);
610
}
611
612
/* Write a partial profile to \p Filename, which is required to be backed by
613
* the open file object \p File. */
614
static int writeProfileWithFileObject(const char *Filename, FILE *File) {
615
setProfileFile(File);
616
int rc = writeFile(Filename);
617
if (rc)
618
PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
619
setProfileFile(NULL);
620
return rc;
621
}
622
623
static void initializeProfileForContinuousMode(void) {
624
if (!__llvm_profile_is_continuous_mode_enabled())
625
return;
626
if (!ContinuousModeSupported) {
627
PROF_ERR("%s\n", "continuous mode is unsupported on this platform");
628
return;
629
}
630
if (UseBiasVar && BiasAddr == BiasDefaultAddr &&
631
BitmapBiasAddr == BitmapBiasDefaultAddr) {
632
PROF_ERR("%s\n", "Neither __llvm_profile_counter_bias nor "
633
"__llvm_profile_bitmap_bias is defined");
634
return;
635
}
636
637
/* Get the sizes of counter section. */
638
uint64_t CountersSize = __llvm_profile_get_counters_size(
639
__llvm_profile_begin_counters(), __llvm_profile_end_counters());
640
641
int Length = getCurFilenameLength();
642
char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
643
const char *Filename = getCurFilename(FilenameBuf, 0);
644
if (!Filename)
645
return;
646
647
FILE *File = NULL;
648
uint64_t CurrentFileOffset = 0;
649
if (doMerging()) {
650
/* We are merging profiles. Map the counter section as shared memory into
651
* the profile, i.e. into each participating process. An increment in one
652
* process should be visible to every other process with the same counter
653
* section mapped. */
654
File = lprofOpenFileEx(Filename);
655
if (!File)
656
return;
657
658
uint64_t ProfileFileSize = 0;
659
if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {
660
lprofUnlockFileHandle(File);
661
fclose(File);
662
return;
663
}
664
if (ProfileFileSize == 0) {
665
/* Grow the profile so that mmap() can succeed. Leak the file handle, as
666
* the file should stay open. */
667
if (writeProfileWithFileObject(Filename, File) != 0) {
668
lprofUnlockFileHandle(File);
669
fclose(File);
670
return;
671
}
672
} else {
673
/* The merged profile has a non-zero length. Check that it is compatible
674
* with the data in this process. */
675
ManagedMemory ProfileBuffer;
676
if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {
677
lprofUnlockFileHandle(File);
678
fclose(File);
679
return;
680
}
681
(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);
682
}
683
} else {
684
File = fopen(Filename, FileOpenMode);
685
if (!File)
686
return;
687
/* Check that the offset within the file is page-aligned. */
688
CurrentFileOffset = ftell(File);
689
unsigned PageSize = getpagesize();
690
if (CurrentFileOffset % PageSize != 0) {
691
PROF_ERR("Continuous counter sync mode is enabled, but raw profile is not"
692
"page-aligned. CurrentFileOffset = %" PRIu64 ", pagesz = %u.\n",
693
(uint64_t)CurrentFileOffset, PageSize);
694
fclose(File);
695
return;
696
}
697
if (writeProfileWithFileObject(Filename, File) != 0) {
698
fclose(File);
699
return;
700
}
701
}
702
703
/* mmap() the profile counters so long as there is at least one counter.
704
* If there aren't any counters, mmap() would fail with EINVAL. */
705
if (CountersSize > 0)
706
mmapForContinuousMode(CurrentFileOffset, File);
707
708
if (doMerging()) {
709
lprofUnlockFileHandle(File);
710
}
711
if (File != NULL) {
712
fclose(File);
713
}
714
}
715
716
static const char *DefaultProfileName = "default.profraw";
717
static void resetFilenameToDefault(void) {
718
if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
719
#ifdef __GNUC__
720
#pragma GCC diagnostic push
721
#pragma GCC diagnostic ignored "-Wcast-qual"
722
#elif defined(__clang__)
723
#pragma clang diagnostic push
724
#pragma clang diagnostic ignored "-Wcast-qual"
725
#endif
726
free((void *)lprofCurFilename.FilenamePat);
727
#ifdef __GNUC__
728
#pragma GCC diagnostic pop
729
#elif defined(__clang__)
730
#pragma clang diagnostic pop
731
#endif
732
}
733
memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
734
lprofCurFilename.FilenamePat = DefaultProfileName;
735
lprofCurFilename.PNS = PNS_default;
736
}
737
738
static unsigned getMergePoolSize(const char *FilenamePat, int *I) {
739
unsigned J = 0, Num = 0;
740
for (;; ++J) {
741
char C = FilenamePat[*I + J];
742
if (C == 'm') {
743
*I += J;
744
return Num ? Num : 1;
745
}
746
if (C < '0' || C > '9')
747
break;
748
Num = Num * 10 + C - '0';
749
750
/* If FilenamePat[*I+J] is between '0' and '9', the next byte is guaranteed
751
* to be in-bound as the string is null terminated. */
752
}
753
return 0;
754
}
755
756
/* Assert that Idx does index past a string null terminator. Return the
757
* result of the check. */
758
static int checkBounds(int Idx, int Strlen) {
759
assert(Idx <= Strlen && "Indexing past string null terminator");
760
return Idx <= Strlen;
761
}
762
763
/* Parses the pattern string \p FilenamePat and stores the result to
764
* lprofcurFilename structure. */
765
static int parseFilenamePattern(const char *FilenamePat,
766
unsigned CopyFilenamePat) {
767
int NumPids = 0, NumHosts = 0, NumBinaryIds = 0, I;
768
char *PidChars = &lprofCurFilename.PidChars[0];
769
char *Hostname = &lprofCurFilename.Hostname[0];
770
int MergingEnabled = 0;
771
int FilenamePatLen = strlen(FilenamePat);
772
773
#ifdef __GNUC__
774
#pragma GCC diagnostic push
775
#pragma GCC diagnostic ignored "-Wcast-qual"
776
#elif defined(__clang__)
777
#pragma clang diagnostic push
778
#pragma clang diagnostic ignored "-Wcast-qual"
779
#endif
780
/* Clean up cached prefix and filename. */
781
if (lprofCurFilename.ProfilePathPrefix)
782
free((void *)lprofCurFilename.ProfilePathPrefix);
783
784
if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) {
785
free((void *)lprofCurFilename.FilenamePat);
786
}
787
#ifdef __GNUC__
788
#pragma GCC diagnostic pop
789
#elif defined(__clang__)
790
#pragma clang diagnostic pop
791
#endif
792
793
memset(&lprofCurFilename, 0, sizeof(lprofCurFilename));
794
795
if (!CopyFilenamePat)
796
lprofCurFilename.FilenamePat = FilenamePat;
797
else {
798
lprofCurFilename.FilenamePat = strdup(FilenamePat);
799
lprofCurFilename.OwnsFilenamePat = 1;
800
}
801
/* Check the filename for "%p", which indicates a pid-substitution. */
802
for (I = 0; checkBounds(I, FilenamePatLen) && FilenamePat[I]; ++I) {
803
if (FilenamePat[I] == '%') {
804
++I; /* Advance to the next character. */
805
if (!checkBounds(I, FilenamePatLen))
806
break;
807
if (FilenamePat[I] == 'p') {
808
if (!NumPids++) {
809
if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) {
810
PROF_WARN("Unable to get pid for filename pattern %s. Using the "
811
"default name.",
812
FilenamePat);
813
return -1;
814
}
815
}
816
} else if (FilenamePat[I] == 'h') {
817
if (!NumHosts++)
818
if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) {
819
PROF_WARN("Unable to get hostname for filename pattern %s. Using "
820
"the default name.",
821
FilenamePat);
822
return -1;
823
}
824
} else if (FilenamePat[I] == 't') {
825
lprofCurFilename.TmpDir = getenv("TMPDIR");
826
if (!lprofCurFilename.TmpDir) {
827
PROF_WARN("Unable to get the TMPDIR environment variable, referenced "
828
"in %s. Using the default path.",
829
FilenamePat);
830
return -1;
831
}
832
} else if (FilenamePat[I] == 'b') {
833
if (!NumBinaryIds++) {
834
/* Check if binary ID does not exist or if its size is 0. */
835
if (__llvm_write_binary_ids(NULL) <= 0) {
836
PROF_WARN("Unable to get binary ID for filename pattern %s. Using "
837
"the default name.",
838
FilenamePat);
839
return -1;
840
}
841
}
842
} else if (FilenamePat[I] == 'c') {
843
if (__llvm_profile_is_continuous_mode_enabled()) {
844
PROF_WARN("%%c specifier can only be specified once in %s.\n",
845
FilenamePat);
846
__llvm_profile_disable_continuous_mode();
847
return -1;
848
}
849
#if defined(__APPLE__) || defined(__ELF__) || defined(_WIN32) || defined(_AIX)
850
__llvm_profile_set_page_size(getpagesize());
851
__llvm_profile_enable_continuous_mode();
852
#else
853
PROF_WARN("%s",
854
"Continuous mode is currently only supported for Mach-O,"
855
" ELF and COFF formats.");
856
return -1;
857
#endif
858
} else {
859
unsigned MergePoolSize = getMergePoolSize(FilenamePat, &I);
860
if (!MergePoolSize)
861
continue;
862
if (MergingEnabled) {
863
PROF_WARN("%%m specifier can only be specified once in %s.\n",
864
FilenamePat);
865
return -1;
866
}
867
MergingEnabled = 1;
868
lprofCurFilename.MergePoolSize = MergePoolSize;
869
}
870
}
871
}
872
873
lprofCurFilename.NumPids = NumPids;
874
lprofCurFilename.NumHosts = NumHosts;
875
lprofCurFilename.NumBinaryIds = NumBinaryIds;
876
return 0;
877
}
878
879
static void parseAndSetFilename(const char *FilenamePat,
880
ProfileNameSpecifier PNS,
881
unsigned CopyFilenamePat) {
882
883
const char *OldFilenamePat = lprofCurFilename.FilenamePat;
884
ProfileNameSpecifier OldPNS = lprofCurFilename.PNS;
885
886
/* The old profile name specifier takes precedence over the old one. */
887
if (PNS < OldPNS)
888
return;
889
890
if (!FilenamePat)
891
FilenamePat = DefaultProfileName;
892
893
if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) {
894
lprofCurFilename.PNS = PNS;
895
return;
896
}
897
898
/* When PNS >= OldPNS, the last one wins. */
899
if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat))
900
resetFilenameToDefault();
901
lprofCurFilename.PNS = PNS;
902
903
if (!OldFilenamePat) {
904
if (getenv("LLVM_PROFILE_VERBOSE"))
905
PROF_NOTE("Set profile file path to \"%s\" via %s.\n",
906
lprofCurFilename.FilenamePat, getPNSStr(PNS));
907
} else {
908
if (getenv("LLVM_PROFILE_VERBOSE"))
909
PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n",
910
OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat,
911
getPNSStr(PNS));
912
}
913
914
truncateCurrentFile();
915
if (__llvm_profile_is_continuous_mode_enabled())
916
initializeProfileForContinuousMode();
917
}
918
919
/* Return buffer length that is required to store the current profile
920
* filename with PID and hostname substitutions. */
921
/* The length to hold uint64_t followed by 3 digits pool id including '_' */
922
#define SIGLEN 24
923
/* The length to hold 160-bit hash in hexadecimal form */
924
#define BINARY_ID_LEN 40
925
static int getCurFilenameLength(void) {
926
int Len;
927
if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
928
return 0;
929
930
if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
931
lprofCurFilename.NumBinaryIds || lprofCurFilename.TmpDir ||
932
lprofCurFilename.MergePoolSize))
933
return strlen(lprofCurFilename.FilenamePat);
934
935
Len = strlen(lprofCurFilename.FilenamePat) +
936
lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) +
937
lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2) +
938
lprofCurFilename.NumBinaryIds * BINARY_ID_LEN +
939
(lprofCurFilename.TmpDir ? (strlen(lprofCurFilename.TmpDir) - 1) : 0);
940
if (lprofCurFilename.MergePoolSize)
941
Len += SIGLEN;
942
return Len;
943
}
944
945
typedef struct lprofBinaryIdsBuffer {
946
char String[BINARY_ID_LEN + 1];
947
int Length;
948
} lprofBinaryIdsBuffer;
949
950
/* Reads binary ID length and then its data, writes it into lprofBinaryIdsBuffer
951
* in hexadecimal form. */
952
static uint32_t binaryIdsStringWriter(ProfDataWriter *This,
953
ProfDataIOVec *IOVecs,
954
uint32_t NumIOVecs) {
955
if (NumIOVecs < 2 || IOVecs[0].ElmSize != sizeof(uint64_t))
956
return -1;
957
uint64_t BinaryIdLen = *(const uint64_t *)IOVecs[0].Data;
958
if (IOVecs[1].ElmSize != sizeof(uint8_t) || IOVecs[1].NumElm != BinaryIdLen)
959
return -1;
960
const uint8_t *BinaryIdData = (const uint8_t *)IOVecs[1].Data;
961
lprofBinaryIdsBuffer *Data = (lprofBinaryIdsBuffer *)This->WriterCtx;
962
for (uint64_t I = 0; I < BinaryIdLen; I++) {
963
Data->Length +=
964
snprintf(Data->String + Data->Length, BINARY_ID_LEN + 1 - Data->Length,
965
"%02hhx", BinaryIdData[I]);
966
}
967
return 0;
968
}
969
970
/* Return the pointer to the current profile file name (after substituting
971
* PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer
972
* to store the resulting filename. If no substitution is needed, the
973
* current filename pattern string is directly returned, unless ForceUseBuf
974
* is enabled. */
975
static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) {
976
int I, J, PidLength, HostNameLength, TmpDirLength, FilenamePatLength;
977
const char *FilenamePat = lprofCurFilename.FilenamePat;
978
979
if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0])
980
return 0;
981
982
if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts ||
983
lprofCurFilename.NumBinaryIds || lprofCurFilename.TmpDir ||
984
lprofCurFilename.MergePoolSize ||
985
__llvm_profile_is_continuous_mode_enabled())) {
986
if (!ForceUseBuf)
987
return lprofCurFilename.FilenamePat;
988
989
FilenamePatLength = strlen(lprofCurFilename.FilenamePat);
990
memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength);
991
FilenameBuf[FilenamePatLength] = '\0';
992
return FilenameBuf;
993
}
994
995
PidLength = strlen(lprofCurFilename.PidChars);
996
HostNameLength = strlen(lprofCurFilename.Hostname);
997
TmpDirLength = lprofCurFilename.TmpDir ? strlen(lprofCurFilename.TmpDir) : 0;
998
/* Construct the new filename. */
999
for (I = 0, J = 0; FilenamePat[I]; ++I)
1000
if (FilenamePat[I] == '%') {
1001
if (FilenamePat[++I] == 'p') {
1002
memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength);
1003
J += PidLength;
1004
} else if (FilenamePat[I] == 'h') {
1005
memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength);
1006
J += HostNameLength;
1007
} else if (FilenamePat[I] == 't') {
1008
memcpy(FilenameBuf + J, lprofCurFilename.TmpDir, TmpDirLength);
1009
FilenameBuf[J + TmpDirLength] = DIR_SEPARATOR;
1010
J += TmpDirLength + 1;
1011
} else if (FilenamePat[I] == 'b') {
1012
lprofBinaryIdsBuffer Data = {{0}, 0};
1013
ProfDataWriter Writer = {binaryIdsStringWriter, &Data};
1014
__llvm_write_binary_ids(&Writer);
1015
memcpy(FilenameBuf + J, Data.String, Data.Length);
1016
J += Data.Length;
1017
} else {
1018
if (!getMergePoolSize(FilenamePat, &I))
1019
continue;
1020
char LoadModuleSignature[SIGLEN + 1];
1021
int S;
1022
int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize;
1023
S = snprintf(LoadModuleSignature, SIGLEN + 1, "%" PRIu64 "_%d",
1024
lprofGetLoadModuleSignature(), ProfilePoolId);
1025
if (S == -1 || S > SIGLEN)
1026
S = SIGLEN;
1027
memcpy(FilenameBuf + J, LoadModuleSignature, S);
1028
J += S;
1029
}
1030
/* Drop any unknown substitutions. */
1031
} else
1032
FilenameBuf[J++] = FilenamePat[I];
1033
FilenameBuf[J] = 0;
1034
1035
return FilenameBuf;
1036
}
1037
1038
/* Returns the pointer to the environment variable
1039
* string. Returns null if the env var is not set. */
1040
static const char *getFilenamePatFromEnv(void) {
1041
const char *Filename = getenv("LLVM_PROFILE_FILE");
1042
if (!Filename || !Filename[0])
1043
return 0;
1044
return Filename;
1045
}
1046
1047
COMPILER_RT_VISIBILITY
1048
const char *__llvm_profile_get_path_prefix(void) {
1049
int Length;
1050
char *FilenameBuf, *Prefix;
1051
const char *Filename, *PrefixEnd;
1052
1053
if (lprofCurFilename.ProfilePathPrefix)
1054
return lprofCurFilename.ProfilePathPrefix;
1055
1056
Length = getCurFilenameLength();
1057
FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
1058
Filename = getCurFilename(FilenameBuf, 0);
1059
if (!Filename)
1060
return "\0";
1061
1062
PrefixEnd = lprofFindLastDirSeparator(Filename);
1063
if (!PrefixEnd)
1064
return "\0";
1065
1066
Length = PrefixEnd - Filename + 1;
1067
Prefix = (char *)malloc(Length + 1);
1068
if (!Prefix) {
1069
PROF_ERR("Failed to %s\n", "allocate memory.");
1070
return "\0";
1071
}
1072
memcpy(Prefix, Filename, Length);
1073
Prefix[Length] = '\0';
1074
lprofCurFilename.ProfilePathPrefix = Prefix;
1075
return Prefix;
1076
}
1077
1078
COMPILER_RT_VISIBILITY
1079
const char *__llvm_profile_get_filename(void) {
1080
int Length;
1081
char *FilenameBuf;
1082
const char *Filename;
1083
1084
Length = getCurFilenameLength();
1085
FilenameBuf = (char *)malloc(Length + 1);
1086
if (!FilenameBuf) {
1087
PROF_ERR("Failed to %s\n", "allocate memory.");
1088
return "\0";
1089
}
1090
Filename = getCurFilename(FilenameBuf, 1);
1091
if (!Filename) {
1092
free(FilenameBuf);
1093
return "\0";
1094
}
1095
1096
return FilenameBuf;
1097
}
1098
1099
/* This API initializes the file handling, both user specified
1100
* profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE
1101
* environment variable can override this default value.
1102
*/
1103
COMPILER_RT_VISIBILITY
1104
void __llvm_profile_initialize_file(void) {
1105
const char *EnvFilenamePat;
1106
const char *SelectedPat = NULL;
1107
ProfileNameSpecifier PNS = PNS_unknown;
1108
int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0);
1109
1110
EnvFilenamePat = getFilenamePatFromEnv();
1111
if (EnvFilenamePat) {
1112
/* Pass CopyFilenamePat = 1, to ensure that the filename would be valid
1113
at the moment when __llvm_profile_write_file() gets executed. */
1114
parseAndSetFilename(EnvFilenamePat, PNS_environment, 1);
1115
return;
1116
} else if (hasCommandLineOverrider) {
1117
SelectedPat = INSTR_PROF_PROFILE_NAME_VAR;
1118
PNS = PNS_command_line;
1119
} else {
1120
SelectedPat = NULL;
1121
PNS = PNS_default;
1122
}
1123
1124
parseAndSetFilename(SelectedPat, PNS, 0);
1125
}
1126
1127
/* This method is invoked by the runtime initialization hook
1128
* InstrProfilingRuntime.o if it is linked in.
1129
*/
1130
COMPILER_RT_VISIBILITY
1131
void __llvm_profile_initialize(void) {
1132
__llvm_profile_initialize_file();
1133
if (!__llvm_profile_is_continuous_mode_enabled())
1134
__llvm_profile_register_write_file_atexit();
1135
}
1136
1137
/* This API is directly called by the user application code. It has the
1138
* highest precedence compared with LLVM_PROFILE_FILE environment variable
1139
* and command line option -fprofile-instr-generate=<profile_name>.
1140
*/
1141
COMPILER_RT_VISIBILITY
1142
void __llvm_profile_set_filename(const char *FilenamePat) {
1143
if (__llvm_profile_is_continuous_mode_enabled())
1144
return;
1145
parseAndSetFilename(FilenamePat, PNS_runtime_api, 1);
1146
}
1147
1148
/* The public API for writing profile data into the file with name
1149
* set by previous calls to __llvm_profile_set_filename or
1150
* __llvm_profile_override_default_filename or
1151
* __llvm_profile_initialize_file. */
1152
COMPILER_RT_VISIBILITY
1153
int __llvm_profile_write_file(void) {
1154
int rc, Length;
1155
const char *Filename;
1156
char *FilenameBuf;
1157
1158
// Temporarily suspend getting SIGKILL when the parent exits.
1159
int PDeathSig = lprofSuspendSigKill();
1160
1161
if (lprofProfileDumped() || __llvm_profile_is_continuous_mode_enabled()) {
1162
PROF_NOTE("Profile data not written to file: %s.\n", "already written");
1163
if (PDeathSig == 1)
1164
lprofRestoreSigKill();
1165
return 0;
1166
}
1167
1168
Length = getCurFilenameLength();
1169
FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
1170
Filename = getCurFilename(FilenameBuf, 0);
1171
1172
/* Check the filename. */
1173
if (!Filename) {
1174
PROF_ERR("Failed to write file : %s\n", "Filename not set");
1175
if (PDeathSig == 1)
1176
lprofRestoreSigKill();
1177
return -1;
1178
}
1179
1180
/* Check if there is llvm/runtime version mismatch. */
1181
if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
1182
PROF_ERR("Runtime and instrumentation version mismatch : "
1183
"expected %d, but get %d\n",
1184
INSTR_PROF_RAW_VERSION,
1185
(int)GET_VERSION(__llvm_profile_get_version()));
1186
if (PDeathSig == 1)
1187
lprofRestoreSigKill();
1188
return -1;
1189
}
1190
1191
/* Write profile data to the file. */
1192
rc = writeFile(Filename);
1193
if (rc)
1194
PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
1195
1196
// Restore SIGKILL.
1197
if (PDeathSig == 1)
1198
lprofRestoreSigKill();
1199
1200
return rc;
1201
}
1202
1203
COMPILER_RT_VISIBILITY
1204
int __llvm_profile_dump(void) {
1205
if (!doMerging())
1206
PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering "
1207
" of previously dumped profile data : %s. Either use %%m "
1208
"in profile name or change profile name before dumping.\n",
1209
"online profile merging is not on");
1210
int rc = __llvm_profile_write_file();
1211
lprofSetProfileDumped(1);
1212
return rc;
1213
}
1214
1215
static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
1216
1217
COMPILER_RT_VISIBILITY
1218
int __llvm_profile_register_write_file_atexit(void) {
1219
static int HasBeenRegistered = 0;
1220
1221
if (HasBeenRegistered)
1222
return 0;
1223
1224
lprofSetupValueProfiler();
1225
1226
HasBeenRegistered = 1;
1227
return lprofAtExit(writeFileWithoutReturn);
1228
}
1229
1230
COMPILER_RT_VISIBILITY int __llvm_profile_set_file_object(FILE *File,
1231
int EnableMerge) {
1232
if (__llvm_profile_is_continuous_mode_enabled()) {
1233
if (!EnableMerge) {
1234
PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported in "
1235
"continuous sync mode when merging is disabled\n",
1236
fileno(File));
1237
return 1;
1238
}
1239
if (lprofLockFileHandle(File) != 0) {
1240
PROF_WARN("Data may be corrupted during profile merging : %s\n",
1241
"Fail to obtain file lock due to system limit.");
1242
}
1243
uint64_t ProfileFileSize = 0;
1244
if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) {
1245
lprofUnlockFileHandle(File);
1246
return 1;
1247
}
1248
if (ProfileFileSize == 0) {
1249
FreeHook = &free;
1250
setupIOBuffer();
1251
ProfDataWriter fileWriter;
1252
initFileWriter(&fileWriter, File);
1253
if (lprofWriteData(&fileWriter, 0, 0)) {
1254
lprofUnlockFileHandle(File);
1255
PROF_ERR("Failed to write file \"%d\": %s\n", fileno(File),
1256
strerror(errno));
1257
return 1;
1258
}
1259
fflush(File);
1260
} else {
1261
/* The merged profile has a non-zero length. Check that it is compatible
1262
* with the data in this process. */
1263
ManagedMemory ProfileBuffer;
1264
if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) {
1265
lprofUnlockFileHandle(File);
1266
return 1;
1267
}
1268
(void)lprofReleaseBuffer(&ProfileBuffer, ProfileFileSize);
1269
}
1270
mmapForContinuousMode(0, File);
1271
lprofUnlockFileHandle(File);
1272
} else {
1273
setProfileFile(File);
1274
setProfileMergeRequested(EnableMerge);
1275
}
1276
return 0;
1277
}
1278
1279
#ifndef __APPLE__
1280
int __llvm_write_custom_profile(const char *Target,
1281
const __llvm_profile_data *DataBegin,
1282
const __llvm_profile_data *DataEnd,
1283
const char *CountersBegin,
1284
const char *CountersEnd, const char *NamesBegin,
1285
const char *NamesEnd,
1286
const uint64_t *VersionOverride) {
1287
int ReturnValue = 0, FilenameLength, TargetLength;
1288
char *FilenameBuf, *TargetFilename;
1289
const char *Filename;
1290
1291
/* Save old profile data */
1292
FILE *oldFile = getProfileFile();
1293
1294
// Temporarily suspend getting SIGKILL when the parent exits.
1295
int PDeathSig = lprofSuspendSigKill();
1296
1297
if (lprofProfileDumped() || __llvm_profile_is_continuous_mode_enabled()) {
1298
PROF_NOTE("Profile data not written to file: %s.\n", "already written");
1299
if (PDeathSig == 1)
1300
lprofRestoreSigKill();
1301
return 0;
1302
}
1303
1304
/* Check if there is llvm/runtime version mismatch. */
1305
if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
1306
PROF_ERR("Runtime and instrumentation version mismatch : "
1307
"expected %d, but get %d\n",
1308
INSTR_PROF_RAW_VERSION,
1309
(int)GET_VERSION(__llvm_profile_get_version()));
1310
if (PDeathSig == 1)
1311
lprofRestoreSigKill();
1312
return -1;
1313
}
1314
1315
/* Get current filename */
1316
FilenameLength = getCurFilenameLength();
1317
FilenameBuf = (char *)COMPILER_RT_ALLOCA(FilenameLength + 1);
1318
Filename = getCurFilename(FilenameBuf, 0);
1319
1320
/* Check the filename. */
1321
if (!Filename) {
1322
PROF_ERR("Failed to write file : %s\n", "Filename not set");
1323
if (PDeathSig == 1)
1324
lprofRestoreSigKill();
1325
return -1;
1326
}
1327
1328
/* Allocate new space for our target-specific PGO filename */
1329
TargetLength = strlen(Target);
1330
TargetFilename =
1331
(char *)COMPILER_RT_ALLOCA(FilenameLength + TargetLength + 2);
1332
1333
/* Find file basename and path sizes */
1334
int32_t DirEnd = FilenameLength - 1;
1335
while (DirEnd >= 0 && !IS_DIR_SEPARATOR(Filename[DirEnd])) {
1336
DirEnd--;
1337
}
1338
uint32_t DirSize = DirEnd + 1, BaseSize = FilenameLength - DirSize;
1339
1340
/* Prepend "TARGET." to current filename */
1341
if (DirSize > 0) {
1342
memcpy(TargetFilename, Filename, DirSize);
1343
}
1344
memcpy(TargetFilename + DirSize, Target, TargetLength);
1345
TargetFilename[TargetLength + DirSize] = '.';
1346
memcpy(TargetFilename + DirSize + 1 + TargetLength, Filename + DirSize,
1347
BaseSize);
1348
TargetFilename[FilenameLength + 1 + TargetLength] = 0;
1349
1350
/* Open and truncate target-specific PGO file */
1351
FILE *OutputFile = fopen(TargetFilename, "w");
1352
setProfileFile(OutputFile);
1353
1354
if (!OutputFile) {
1355
PROF_ERR("Failed to open file : %s\n", TargetFilename);
1356
if (PDeathSig == 1)
1357
lprofRestoreSigKill();
1358
return -1;
1359
}
1360
1361
FreeHook = &free;
1362
setupIOBuffer();
1363
1364
/* Write custom data */
1365
ProfDataWriter fileWriter;
1366
initFileWriter(&fileWriter, OutputFile);
1367
1368
uint64_t Version = __llvm_profile_get_version();
1369
if (VersionOverride)
1370
Version = *VersionOverride;
1371
1372
/* Write custom data to the file */
1373
ReturnValue =
1374
lprofWriteDataImpl(&fileWriter, DataBegin, DataEnd, CountersBegin,
1375
CountersEnd, NULL, NULL, lprofGetVPDataReader(), NULL,
1376
NULL, NULL, NULL, NamesBegin, NamesEnd, 0, Version);
1377
closeFileObject(OutputFile);
1378
1379
// Restore SIGKILL.
1380
if (PDeathSig == 1)
1381
lprofRestoreSigKill();
1382
1383
/* Restore old profiling file */
1384
setProfileFile(oldFile);
1385
1386
return ReturnValue;
1387
}
1388
#endif
1389
1390
#endif
1391
1392