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