10b57cec5SDimitry Andric /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ 20b57cec5SDimitry Andric |* 30b57cec5SDimitry Andric |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric |* See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric |* 70b57cec5SDimitry Andric \*===----------------------------------------------------------------------===*/ 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #if !defined(__Fuchsia__) 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include <errno.h> 120b57cec5SDimitry Andric #include <stdio.h> 130b57cec5SDimitry Andric #include <stdlib.h> 140b57cec5SDimitry Andric #include <string.h> 150b57cec5SDimitry Andric #ifdef _MSC_VER 160b57cec5SDimitry Andric /* For _alloca. */ 170b57cec5SDimitry Andric #include <malloc.h> 180b57cec5SDimitry Andric #endif 190b57cec5SDimitry Andric #if defined(_WIN32) 200b57cec5SDimitry Andric #include "WindowsMMap.h" 210b57cec5SDimitry Andric /* For _chsize_s */ 220b57cec5SDimitry Andric #include <io.h> 230b57cec5SDimitry Andric #include <process.h> 240b57cec5SDimitry Andric #else 250b57cec5SDimitry Andric #include <sys/file.h> 260b57cec5SDimitry Andric #include <sys/mman.h> 270b57cec5SDimitry Andric #include <unistd.h> 280b57cec5SDimitry Andric #if defined(__linux__) 290b57cec5SDimitry Andric #include <sys/types.h> 300b57cec5SDimitry Andric #endif 310b57cec5SDimitry Andric #endif 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric #include "InstrProfiling.h" 340b57cec5SDimitry Andric #include "InstrProfilingInternal.h" 35480093f4SDimitry Andric #include "InstrProfilingPort.h" 360b57cec5SDimitry Andric #include "InstrProfilingUtil.h" 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric /* From where is profile name specified. 390b57cec5SDimitry Andric * The order the enumerators define their 400b57cec5SDimitry Andric * precedence. Re-order them may lead to 410b57cec5SDimitry Andric * runtime behavior change. */ 420b57cec5SDimitry Andric typedef enum ProfileNameSpecifier { 430b57cec5SDimitry Andric PNS_unknown = 0, 440b57cec5SDimitry Andric PNS_default, 450b57cec5SDimitry Andric PNS_command_line, 460b57cec5SDimitry Andric PNS_environment, 470b57cec5SDimitry Andric PNS_runtime_api 480b57cec5SDimitry Andric } ProfileNameSpecifier; 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric static const char *getPNSStr(ProfileNameSpecifier PNS) { 510b57cec5SDimitry Andric switch (PNS) { 520b57cec5SDimitry Andric case PNS_default: 530b57cec5SDimitry Andric return "default setting"; 540b57cec5SDimitry Andric case PNS_command_line: 550b57cec5SDimitry Andric return "command line"; 560b57cec5SDimitry Andric case PNS_environment: 570b57cec5SDimitry Andric return "environment variable"; 580b57cec5SDimitry Andric case PNS_runtime_api: 590b57cec5SDimitry Andric return "runtime API"; 600b57cec5SDimitry Andric default: 610b57cec5SDimitry Andric return "Unknown"; 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric #define MAX_PID_SIZE 16 660b57cec5SDimitry Andric /* Data structure holding the result of parsed filename pattern. */ 670b57cec5SDimitry Andric typedef struct lprofFilename { 680b57cec5SDimitry Andric /* File name string possibly with %p or %h specifiers. */ 690b57cec5SDimitry Andric const char *FilenamePat; 700b57cec5SDimitry Andric /* A flag indicating if FilenamePat's memory is allocated 710b57cec5SDimitry Andric * by runtime. */ 720b57cec5SDimitry Andric unsigned OwnsFilenamePat; 730b57cec5SDimitry Andric const char *ProfilePathPrefix; 740b57cec5SDimitry Andric char PidChars[MAX_PID_SIZE]; 75*e8d8bef9SDimitry Andric char *TmpDir; 760b57cec5SDimitry Andric char Hostname[COMPILER_RT_MAX_HOSTLEN]; 770b57cec5SDimitry Andric unsigned NumPids; 780b57cec5SDimitry Andric unsigned NumHosts; 790b57cec5SDimitry Andric /* When in-process merging is enabled, this parameter specifies 800b57cec5SDimitry Andric * the total number of profile data files shared by all the processes 810b57cec5SDimitry Andric * spawned from the same binary. By default the value is 1. If merging 820b57cec5SDimitry Andric * is not enabled, its value should be 0. This parameter is specified 830b57cec5SDimitry Andric * by the %[0-9]m specifier. For instance %2m enables merging using 840b57cec5SDimitry Andric * 2 profile data files. %1m is equivalent to %m. Also %m specifier 850b57cec5SDimitry Andric * can only appear once at the end of the name pattern. */ 860b57cec5SDimitry Andric unsigned MergePoolSize; 870b57cec5SDimitry Andric ProfileNameSpecifier PNS; 880b57cec5SDimitry Andric } lprofFilename; 890b57cec5SDimitry Andric 90*e8d8bef9SDimitry Andric static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL, 91*e8d8bef9SDimitry Andric {0}, 0, 0, 0, PNS_unknown}; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric static int ProfileMergeRequested = 0; 940b57cec5SDimitry Andric static int isProfileMergeRequested() { return ProfileMergeRequested; } 950b57cec5SDimitry Andric static void setProfileMergeRequested(int EnableMerge) { 960b57cec5SDimitry Andric ProfileMergeRequested = EnableMerge; 970b57cec5SDimitry Andric } 980b57cec5SDimitry Andric 990b57cec5SDimitry Andric static FILE *ProfileFile = NULL; 1000b57cec5SDimitry Andric static FILE *getProfileFile() { return ProfileFile; } 1010b57cec5SDimitry Andric static void setProfileFile(FILE *File) { ProfileFile = File; } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric COMPILER_RT_VISIBILITY void __llvm_profile_set_file_object(FILE *File, 1040b57cec5SDimitry Andric int EnableMerge) { 105480093f4SDimitry Andric if (__llvm_profile_is_continuous_mode_enabled()) { 106480093f4SDimitry Andric PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported, because " 107480093f4SDimitry Andric "continuous sync mode (%%c) is enabled", 108480093f4SDimitry Andric fileno(File)); 109480093f4SDimitry Andric return; 110480093f4SDimitry Andric } 1110b57cec5SDimitry Andric setProfileFile(File); 1120b57cec5SDimitry Andric setProfileMergeRequested(EnableMerge); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric static int getCurFilenameLength(); 1160b57cec5SDimitry Andric static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf); 1170b57cec5SDimitry Andric static unsigned doMerging() { 1180b57cec5SDimitry Andric return lprofCurFilename.MergePoolSize || isProfileMergeRequested(); 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric /* Return 1 if there is an error, otherwise return 0. */ 1220b57cec5SDimitry Andric static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, 1230b57cec5SDimitry Andric uint32_t NumIOVecs) { 1240b57cec5SDimitry Andric uint32_t I; 1250b57cec5SDimitry Andric FILE *File = (FILE *)This->WriterCtx; 126480093f4SDimitry Andric char Zeroes[sizeof(uint64_t)] = {0}; 1270b57cec5SDimitry Andric for (I = 0; I < NumIOVecs; I++) { 1280b57cec5SDimitry Andric if (IOVecs[I].Data) { 1290b57cec5SDimitry Andric if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != 1300b57cec5SDimitry Andric IOVecs[I].NumElm) 1310b57cec5SDimitry Andric return 1; 132480093f4SDimitry Andric } else if (IOVecs[I].UseZeroPadding) { 133480093f4SDimitry Andric size_t BytesToWrite = IOVecs[I].ElmSize * IOVecs[I].NumElm; 134480093f4SDimitry Andric while (BytesToWrite > 0) { 135480093f4SDimitry Andric size_t PartialWriteLen = 136480093f4SDimitry Andric (sizeof(uint64_t) > BytesToWrite) ? BytesToWrite : sizeof(uint64_t); 137480093f4SDimitry Andric if (fwrite(Zeroes, sizeof(uint8_t), PartialWriteLen, File) != 138480093f4SDimitry Andric PartialWriteLen) { 139480093f4SDimitry Andric return 1; 140480093f4SDimitry Andric } 141480093f4SDimitry Andric BytesToWrite -= PartialWriteLen; 142480093f4SDimitry Andric } 1430b57cec5SDimitry Andric } else { 1440b57cec5SDimitry Andric if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1) 1450b57cec5SDimitry Andric return 1; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric return 0; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric /* TODO: make buffer size controllable by an internal option, and compiler can pass the size 1520b57cec5SDimitry Andric to runtime via a variable. */ 1530b57cec5SDimitry Andric static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) { 1540b57cec5SDimitry Andric if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) != 1550b57cec5SDimitry Andric INSTR_ORDER_FILE_BUFFER_SIZE) 1560b57cec5SDimitry Andric return 1; 1570b57cec5SDimitry Andric return 0; 1580b57cec5SDimitry Andric } 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric static void initFileWriter(ProfDataWriter *This, FILE *File) { 1610b57cec5SDimitry Andric This->Write = fileWriter; 1620b57cec5SDimitry Andric This->WriterCtx = File; 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric COMPILER_RT_VISIBILITY ProfBufferIO * 1660b57cec5SDimitry Andric lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { 1670b57cec5SDimitry Andric FreeHook = &free; 1680b57cec5SDimitry Andric DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); 1690b57cec5SDimitry Andric VPBufferSize = BufferSz; 1700b57cec5SDimitry Andric ProfDataWriter *fileWriter = 1710b57cec5SDimitry Andric (ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1); 1720b57cec5SDimitry Andric initFileWriter(fileWriter, File); 1730b57cec5SDimitry Andric ProfBufferIO *IO = lprofCreateBufferIO(fileWriter); 1740b57cec5SDimitry Andric IO->OwnFileWriter = 1; 1750b57cec5SDimitry Andric return IO; 1760b57cec5SDimitry Andric } 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric static void setupIOBuffer() { 1790b57cec5SDimitry Andric const char *BufferSzStr = 0; 1800b57cec5SDimitry Andric BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); 1810b57cec5SDimitry Andric if (BufferSzStr && BufferSzStr[0]) { 1820b57cec5SDimitry Andric VPBufferSize = atoi(BufferSzStr); 1830b57cec5SDimitry Andric DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 187480093f4SDimitry Andric /* Get the size of the profile file. If there are any errors, print the 188480093f4SDimitry Andric * message under the assumption that the profile is being read for merging 189480093f4SDimitry Andric * purposes, and return -1. Otherwise return the file size in the inout param 190480093f4SDimitry Andric * \p ProfileFileSize. */ 191480093f4SDimitry Andric static int getProfileFileSizeForMerging(FILE *ProfileFile, 192480093f4SDimitry Andric uint64_t *ProfileFileSize) { 193480093f4SDimitry Andric if (fseek(ProfileFile, 0L, SEEK_END) == -1) { 194480093f4SDimitry Andric PROF_ERR("Unable to merge profile data, unable to get size: %s\n", 195480093f4SDimitry Andric strerror(errno)); 196480093f4SDimitry Andric return -1; 197480093f4SDimitry Andric } 198480093f4SDimitry Andric *ProfileFileSize = ftell(ProfileFile); 199480093f4SDimitry Andric 200480093f4SDimitry Andric /* Restore file offset. */ 201480093f4SDimitry Andric if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { 202480093f4SDimitry Andric PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", 203480093f4SDimitry Andric strerror(errno)); 204480093f4SDimitry Andric return -1; 205480093f4SDimitry Andric } 206480093f4SDimitry Andric 207480093f4SDimitry Andric if (*ProfileFileSize > 0 && 208480093f4SDimitry Andric *ProfileFileSize < sizeof(__llvm_profile_header)) { 209480093f4SDimitry Andric PROF_WARN("Unable to merge profile data: %s\n", 210480093f4SDimitry Andric "source profile file is too small."); 211480093f4SDimitry Andric return -1; 212480093f4SDimitry Andric } 213480093f4SDimitry Andric return 0; 214480093f4SDimitry Andric } 215480093f4SDimitry Andric 216480093f4SDimitry Andric /* mmap() \p ProfileFile for profile merging purposes, assuming that an 217480093f4SDimitry Andric * exclusive lock is held on the file and that \p ProfileFileSize is the 218480093f4SDimitry Andric * length of the file. Return the mmap'd buffer in the inout variable 219480093f4SDimitry Andric * \p ProfileBuffer. Returns -1 on failure. On success, the caller is 220480093f4SDimitry Andric * responsible for unmapping the mmap'd buffer in \p ProfileBuffer. */ 221480093f4SDimitry Andric static int mmapProfileForMerging(FILE *ProfileFile, uint64_t ProfileFileSize, 222480093f4SDimitry Andric char **ProfileBuffer) { 223480093f4SDimitry Andric *ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, 224480093f4SDimitry Andric fileno(ProfileFile), 0); 225480093f4SDimitry Andric if (*ProfileBuffer == MAP_FAILED) { 226480093f4SDimitry Andric PROF_ERR("Unable to merge profile data, mmap failed: %s\n", 227480093f4SDimitry Andric strerror(errno)); 228480093f4SDimitry Andric return -1; 229480093f4SDimitry Andric } 230480093f4SDimitry Andric 231480093f4SDimitry Andric if (__llvm_profile_check_compatibility(*ProfileBuffer, ProfileFileSize)) { 232480093f4SDimitry Andric (void)munmap(*ProfileBuffer, ProfileFileSize); 233480093f4SDimitry Andric PROF_WARN("Unable to merge profile data: %s\n", 234480093f4SDimitry Andric "source profile file is not compatible."); 235480093f4SDimitry Andric return -1; 236480093f4SDimitry Andric } 237480093f4SDimitry Andric return 0; 238480093f4SDimitry Andric } 239480093f4SDimitry Andric 2400b57cec5SDimitry Andric /* Read profile data in \c ProfileFile and merge with in-memory 2410b57cec5SDimitry Andric profile counters. Returns -1 if there is fatal error, otheriwse 2420b57cec5SDimitry Andric 0 is returned. Returning 0 does not mean merge is actually 2430b57cec5SDimitry Andric performed. If merge is actually done, *MergeDone is set to 1. 2440b57cec5SDimitry Andric */ 2450b57cec5SDimitry Andric static int doProfileMerging(FILE *ProfileFile, int *MergeDone) { 2460b57cec5SDimitry Andric uint64_t ProfileFileSize; 2470b57cec5SDimitry Andric char *ProfileBuffer; 2480b57cec5SDimitry Andric 249480093f4SDimitry Andric /* Get the size of the profile on disk. */ 250480093f4SDimitry Andric if (getProfileFileSizeForMerging(ProfileFile, &ProfileFileSize) == -1) 2510b57cec5SDimitry Andric return -1; 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric /* Nothing to merge. */ 254480093f4SDimitry Andric if (!ProfileFileSize) 2550b57cec5SDimitry Andric return 0; 2560b57cec5SDimitry Andric 257480093f4SDimitry Andric /* mmap() the profile and check that it is compatible with the data in 258480093f4SDimitry Andric * the current image. */ 259480093f4SDimitry Andric if (mmapProfileForMerging(ProfileFile, ProfileFileSize, &ProfileBuffer) == -1) 2600b57cec5SDimitry Andric return -1; 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric /* Now start merging */ 2630b57cec5SDimitry Andric __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric // Truncate the file in case merging of value profile did not happend to 2660b57cec5SDimitry Andric // prevent from leaving garbage data at the end of the profile file. 2670b57cec5SDimitry Andric COMPILER_RT_FTRUNCATE(ProfileFile, __llvm_profile_get_size_for_buffer()); 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 2700b57cec5SDimitry Andric *MergeDone = 1; 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric return 0; 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric /* Create the directory holding the file, if needed. */ 2760b57cec5SDimitry Andric static void createProfileDir(const char *Filename) { 2770b57cec5SDimitry Andric size_t Length = strlen(Filename); 2780b57cec5SDimitry Andric if (lprofFindFirstDirSeparator(Filename)) { 2790b57cec5SDimitry Andric char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 2800b57cec5SDimitry Andric strncpy(Copy, Filename, Length + 1); 2810b57cec5SDimitry Andric __llvm_profile_recursive_mkdir(Copy); 2820b57cec5SDimitry Andric } 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric /* Open the profile data for merging. It opens the file in r+b mode with 2860b57cec5SDimitry Andric * file locking. If the file has content which is compatible with the 2870b57cec5SDimitry Andric * current process, it also reads in the profile data in the file and merge 2880b57cec5SDimitry Andric * it with in-memory counters. After the profile data is merged in memory, 2890b57cec5SDimitry Andric * the original profile data is truncated and gets ready for the profile 2900b57cec5SDimitry Andric * dumper. With profile merging enabled, each executable as well as any of 2910b57cec5SDimitry Andric * its instrumented shared libraries dump profile data into their own data file. 2920b57cec5SDimitry Andric */ 2930b57cec5SDimitry Andric static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) { 2940b57cec5SDimitry Andric FILE *ProfileFile = NULL; 2950b57cec5SDimitry Andric int rc; 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric ProfileFile = getProfileFile(); 2980b57cec5SDimitry Andric if (ProfileFile) { 2990b57cec5SDimitry Andric lprofLockFileHandle(ProfileFile); 3000b57cec5SDimitry Andric } else { 3010b57cec5SDimitry Andric createProfileDir(ProfileFileName); 3020b57cec5SDimitry Andric ProfileFile = lprofOpenFileEx(ProfileFileName); 3030b57cec5SDimitry Andric } 3040b57cec5SDimitry Andric if (!ProfileFile) 3050b57cec5SDimitry Andric return NULL; 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric rc = doProfileMerging(ProfileFile, MergeDone); 3080b57cec5SDimitry Andric if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) || 3090b57cec5SDimitry Andric fseek(ProfileFile, 0L, SEEK_SET) == -1) { 3100b57cec5SDimitry Andric PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 3110b57cec5SDimitry Andric strerror(errno)); 3120b57cec5SDimitry Andric fclose(ProfileFile); 3130b57cec5SDimitry Andric return NULL; 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric return ProfileFile; 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric static FILE *getFileObject(const char *OutputName) { 3190b57cec5SDimitry Andric FILE *File; 3200b57cec5SDimitry Andric File = getProfileFile(); 3210b57cec5SDimitry Andric if (File != NULL) { 3220b57cec5SDimitry Andric return File; 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric return fopen(OutputName, "ab"); 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric /* Write profile data to file \c OutputName. */ 3290b57cec5SDimitry Andric static int writeFile(const char *OutputName) { 3300b57cec5SDimitry Andric int RetVal; 3310b57cec5SDimitry Andric FILE *OutputFile; 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric int MergeDone = 0; 3340b57cec5SDimitry Andric VPMergeHook = &lprofMergeValueProfData; 3350b57cec5SDimitry Andric if (doMerging()) 3360b57cec5SDimitry Andric OutputFile = openFileForMerging(OutputName, &MergeDone); 3370b57cec5SDimitry Andric else 3380b57cec5SDimitry Andric OutputFile = getFileObject(OutputName); 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric if (!OutputFile) 3410b57cec5SDimitry Andric return -1; 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric FreeHook = &free; 3440b57cec5SDimitry Andric setupIOBuffer(); 3450b57cec5SDimitry Andric ProfDataWriter fileWriter; 3460b57cec5SDimitry Andric initFileWriter(&fileWriter, OutputFile); 3470b57cec5SDimitry Andric RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone); 3480b57cec5SDimitry Andric 3490b57cec5SDimitry Andric if (OutputFile == getProfileFile()) { 3500b57cec5SDimitry Andric fflush(OutputFile); 3510b57cec5SDimitry Andric if (doMerging()) { 3520b57cec5SDimitry Andric lprofUnlockFileHandle(OutputFile); 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric } else { 3550b57cec5SDimitry Andric fclose(OutputFile); 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric 3580b57cec5SDimitry Andric return RetVal; 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric 3610b57cec5SDimitry Andric /* Write order data to file \c OutputName. */ 3620b57cec5SDimitry Andric static int writeOrderFile(const char *OutputName) { 3630b57cec5SDimitry Andric int RetVal; 3640b57cec5SDimitry Andric FILE *OutputFile; 3650b57cec5SDimitry Andric 3660b57cec5SDimitry Andric OutputFile = fopen(OutputName, "w"); 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric if (!OutputFile) { 3690b57cec5SDimitry Andric PROF_WARN("can't open file with mode ab: %s\n", OutputName); 3700b57cec5SDimitry Andric return -1; 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric 3730b57cec5SDimitry Andric FreeHook = &free; 3740b57cec5SDimitry Andric setupIOBuffer(); 3750b57cec5SDimitry Andric const uint32_t *DataBegin = __llvm_profile_begin_orderfile(); 3760b57cec5SDimitry Andric RetVal = orderFileWriter(OutputFile, DataBegin); 3770b57cec5SDimitry Andric 3780b57cec5SDimitry Andric fclose(OutputFile); 3790b57cec5SDimitry Andric return RetVal; 3800b57cec5SDimitry Andric } 3810b57cec5SDimitry Andric 382480093f4SDimitry Andric #define LPROF_INIT_ONCE_ENV "__LLVM_PROFILE_RT_INIT_ONCE" 383480093f4SDimitry Andric 3840b57cec5SDimitry Andric static void truncateCurrentFile(void) { 3850b57cec5SDimitry Andric const char *Filename; 3860b57cec5SDimitry Andric char *FilenameBuf; 3870b57cec5SDimitry Andric FILE *File; 3880b57cec5SDimitry Andric int Length; 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric Length = getCurFilenameLength(); 3910b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 3920b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 3930b57cec5SDimitry Andric if (!Filename) 3940b57cec5SDimitry Andric return; 3950b57cec5SDimitry Andric 396480093f4SDimitry Andric /* Only create the profile directory and truncate an existing profile once. 397480093f4SDimitry Andric * In continuous mode, this is necessary, as the profile is written-to by the 398480093f4SDimitry Andric * runtime initializer. */ 399480093f4SDimitry Andric int initialized = getenv(LPROF_INIT_ONCE_ENV) != NULL; 400480093f4SDimitry Andric if (initialized) 401480093f4SDimitry Andric return; 402480093f4SDimitry Andric #if defined(_WIN32) 403480093f4SDimitry Andric _putenv(LPROF_INIT_ONCE_ENV "=" LPROF_INIT_ONCE_ENV); 404480093f4SDimitry Andric #else 405480093f4SDimitry Andric setenv(LPROF_INIT_ONCE_ENV, LPROF_INIT_ONCE_ENV, 1); 406480093f4SDimitry Andric #endif 407480093f4SDimitry Andric 408480093f4SDimitry Andric /* Create the profile dir (even if online merging is enabled), so that 409480093f4SDimitry Andric * the profile file can be set up if continuous mode is enabled. */ 410480093f4SDimitry Andric createProfileDir(Filename); 411480093f4SDimitry Andric 412480093f4SDimitry Andric /* By pass file truncation to allow online raw profile merging. */ 4130b57cec5SDimitry Andric if (lprofCurFilename.MergePoolSize) 4140b57cec5SDimitry Andric return; 4150b57cec5SDimitry Andric 4160b57cec5SDimitry Andric /* Truncate the file. Later we'll reopen and append. */ 4170b57cec5SDimitry Andric File = fopen(Filename, "w"); 4180b57cec5SDimitry Andric if (!File) 4190b57cec5SDimitry Andric return; 4200b57cec5SDimitry Andric fclose(File); 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric 423*e8d8bef9SDimitry Andric #if !defined(__Fuchsia__) && !defined(_WIN32) 424480093f4SDimitry Andric static void assertIsZero(int *i) { 425480093f4SDimitry Andric if (*i) 426480093f4SDimitry Andric PROF_WARN("Expected flag to be 0, but got: %d\n", *i); 427480093f4SDimitry Andric } 428480093f4SDimitry Andric 429480093f4SDimitry Andric /* Write a partial profile to \p Filename, which is required to be backed by 430480093f4SDimitry Andric * the open file object \p File. */ 431480093f4SDimitry Andric static int writeProfileWithFileObject(const char *Filename, FILE *File) { 432480093f4SDimitry Andric setProfileFile(File); 433480093f4SDimitry Andric int rc = writeFile(Filename); 434480093f4SDimitry Andric if (rc) 435480093f4SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 436480093f4SDimitry Andric setProfileFile(NULL); 437480093f4SDimitry Andric return rc; 438480093f4SDimitry Andric } 439480093f4SDimitry Andric 440480093f4SDimitry Andric /* Unlock the profile \p File and clear the unlock flag. */ 441480093f4SDimitry Andric static void unlockProfile(int *ProfileRequiresUnlock, FILE *File) { 442480093f4SDimitry Andric if (!*ProfileRequiresUnlock) { 443480093f4SDimitry Andric PROF_WARN("%s", "Expected to require profile unlock\n"); 444480093f4SDimitry Andric } 445480093f4SDimitry Andric lprofUnlockFileHandle(File); 446480093f4SDimitry Andric *ProfileRequiresUnlock = 0; 447480093f4SDimitry Andric } 448480093f4SDimitry Andric #endif // !defined(__Fuchsia__) && !defined(_WIN32) 449480093f4SDimitry Andric 4505ffd83dbSDimitry Andric static int writeMMappedFile(FILE *OutputFile, char **Profile) { 4515ffd83dbSDimitry Andric if (!OutputFile) 4525ffd83dbSDimitry Andric return -1; 4535ffd83dbSDimitry Andric 4545ffd83dbSDimitry Andric /* Write the data into a file. */ 4555ffd83dbSDimitry Andric setupIOBuffer(); 4565ffd83dbSDimitry Andric ProfDataWriter fileWriter; 4575ffd83dbSDimitry Andric initFileWriter(&fileWriter, OutputFile); 4585ffd83dbSDimitry Andric if (lprofWriteData(&fileWriter, NULL, 0)) { 4595ffd83dbSDimitry Andric PROF_ERR("Failed to write profile: %s\n", strerror(errno)); 4605ffd83dbSDimitry Andric return -1; 4615ffd83dbSDimitry Andric } 4625ffd83dbSDimitry Andric fflush(OutputFile); 4635ffd83dbSDimitry Andric 4645ffd83dbSDimitry Andric /* Get the file size. */ 4655ffd83dbSDimitry Andric uint64_t FileSize = ftell(OutputFile); 4665ffd83dbSDimitry Andric 4675ffd83dbSDimitry Andric /* Map the profile. */ 4685ffd83dbSDimitry Andric *Profile = (char *)mmap( 4695ffd83dbSDimitry Andric NULL, FileSize, PROT_READ | PROT_WRITE, MAP_SHARED, fileno(OutputFile), 0); 4705ffd83dbSDimitry Andric if (*Profile == MAP_FAILED) { 4715ffd83dbSDimitry Andric PROF_ERR("Unable to mmap profile: %s\n", strerror(errno)); 4725ffd83dbSDimitry Andric return -1; 4735ffd83dbSDimitry Andric } 4745ffd83dbSDimitry Andric 4755ffd83dbSDimitry Andric return 0; 4765ffd83dbSDimitry Andric } 4775ffd83dbSDimitry Andric 4785ffd83dbSDimitry Andric static void relocateCounters(void) { 4795ffd83dbSDimitry Andric if (!__llvm_profile_is_continuous_mode_enabled() || 4805ffd83dbSDimitry Andric !lprofRuntimeCounterRelocation()) 4815ffd83dbSDimitry Andric return; 4825ffd83dbSDimitry Andric 4835ffd83dbSDimitry Andric /* Get the sizes of various profile data sections. Taken from 4845ffd83dbSDimitry Andric * __llvm_profile_get_size_for_buffer(). */ 4855ffd83dbSDimitry Andric const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); 4865ffd83dbSDimitry Andric const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); 4875ffd83dbSDimitry Andric uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); 4885ffd83dbSDimitry Andric const uint64_t CountersOffset = sizeof(__llvm_profile_header) + 4895ffd83dbSDimitry Andric (DataSize * sizeof(__llvm_profile_data)); 4905ffd83dbSDimitry Andric 4915ffd83dbSDimitry Andric int Length = getCurFilenameLength(); 4925ffd83dbSDimitry Andric char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 4935ffd83dbSDimitry Andric const char *Filename = getCurFilename(FilenameBuf, 0); 4945ffd83dbSDimitry Andric if (!Filename) 4955ffd83dbSDimitry Andric return; 4965ffd83dbSDimitry Andric 4975ffd83dbSDimitry Andric FILE *File = NULL; 4985ffd83dbSDimitry Andric char *Profile = NULL; 4995ffd83dbSDimitry Andric 5005ffd83dbSDimitry Andric if (!doMerging()) { 5015ffd83dbSDimitry Andric File = fopen(Filename, "w+b"); 5025ffd83dbSDimitry Andric if (!File) 5035ffd83dbSDimitry Andric return; 5045ffd83dbSDimitry Andric 5055ffd83dbSDimitry Andric if (writeMMappedFile(File, &Profile) == -1) { 5065ffd83dbSDimitry Andric fclose(File); 5075ffd83dbSDimitry Andric return; 5085ffd83dbSDimitry Andric } 5095ffd83dbSDimitry Andric } else { 5105ffd83dbSDimitry Andric File = lprofOpenFileEx(Filename); 5115ffd83dbSDimitry Andric if (!File) 5125ffd83dbSDimitry Andric return; 5135ffd83dbSDimitry Andric 5145ffd83dbSDimitry Andric uint64_t ProfileFileSize = 0; 5155ffd83dbSDimitry Andric if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) { 5165ffd83dbSDimitry Andric lprofUnlockFileHandle(File); 5175ffd83dbSDimitry Andric fclose(File); 5185ffd83dbSDimitry Andric return; 5195ffd83dbSDimitry Andric } 5205ffd83dbSDimitry Andric 5215ffd83dbSDimitry Andric if (!ProfileFileSize) { 5225ffd83dbSDimitry Andric if (writeMMappedFile(File, &Profile) == -1) { 5235ffd83dbSDimitry Andric fclose(File); 5245ffd83dbSDimitry Andric return; 5255ffd83dbSDimitry Andric } 5265ffd83dbSDimitry Andric } else { 5275ffd83dbSDimitry Andric /* The merged profile has a non-zero length. Check that it is compatible 5285ffd83dbSDimitry Andric * with the data in this process. */ 5295ffd83dbSDimitry Andric if (mmapProfileForMerging(File, ProfileFileSize, &Profile) == -1) { 5305ffd83dbSDimitry Andric fclose(File); 5315ffd83dbSDimitry Andric return; 5325ffd83dbSDimitry Andric } 5335ffd83dbSDimitry Andric } 5345ffd83dbSDimitry Andric 5355ffd83dbSDimitry Andric lprofUnlockFileHandle(File); 5365ffd83dbSDimitry Andric } 5375ffd83dbSDimitry Andric 5385ffd83dbSDimitry Andric /* Update the profile fields based on the current mapping. */ 5395ffd83dbSDimitry Andric __llvm_profile_counter_bias = (intptr_t)Profile - 5405ffd83dbSDimitry Andric (uintptr_t)__llvm_profile_begin_counters() + CountersOffset; 5415ffd83dbSDimitry Andric } 5425ffd83dbSDimitry Andric 543480093f4SDimitry Andric static void initializeProfileForContinuousMode(void) { 544480093f4SDimitry Andric if (!__llvm_profile_is_continuous_mode_enabled()) 545480093f4SDimitry Andric return; 546480093f4SDimitry Andric 547480093f4SDimitry Andric #if defined(__Fuchsia__) || defined(_WIN32) 548480093f4SDimitry Andric PROF_ERR("%s\n", "Continuous mode not yet supported on Fuchsia or Windows."); 549480093f4SDimitry Andric #else // defined(__Fuchsia__) || defined(_WIN32) 550480093f4SDimitry Andric /* Get the sizes of various profile data sections. Taken from 551480093f4SDimitry Andric * __llvm_profile_get_size_for_buffer(). */ 552480093f4SDimitry Andric const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); 553480093f4SDimitry Andric const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); 554480093f4SDimitry Andric const uint64_t *CountersBegin = __llvm_profile_begin_counters(); 555480093f4SDimitry Andric const uint64_t *CountersEnd = __llvm_profile_end_counters(); 556480093f4SDimitry Andric const char *NamesBegin = __llvm_profile_begin_names(); 557480093f4SDimitry Andric const char *NamesEnd = __llvm_profile_end_names(); 558480093f4SDimitry Andric const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char); 559480093f4SDimitry Andric uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); 560480093f4SDimitry Andric uint64_t CountersSize = CountersEnd - CountersBegin; 561480093f4SDimitry Andric 562480093f4SDimitry Andric /* Check that the counter and data sections in this image are page-aligned. */ 563480093f4SDimitry Andric unsigned PageSize = getpagesize(); 564480093f4SDimitry Andric if ((intptr_t)CountersBegin % PageSize != 0) { 565480093f4SDimitry Andric PROF_ERR("Counters section not page-aligned (start = %p, pagesz = %u).\n", 566480093f4SDimitry Andric CountersBegin, PageSize); 567480093f4SDimitry Andric return; 568480093f4SDimitry Andric } 569480093f4SDimitry Andric if ((intptr_t)DataBegin % PageSize != 0) { 570480093f4SDimitry Andric PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n", 571480093f4SDimitry Andric DataBegin, PageSize); 572480093f4SDimitry Andric return; 573480093f4SDimitry Andric } 574480093f4SDimitry Andric 575480093f4SDimitry Andric int Length = getCurFilenameLength(); 576480093f4SDimitry Andric char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 577480093f4SDimitry Andric const char *Filename = getCurFilename(FilenameBuf, 0); 578480093f4SDimitry Andric if (!Filename) 579480093f4SDimitry Andric return; 580480093f4SDimitry Andric 581480093f4SDimitry Andric FILE *File = NULL; 582480093f4SDimitry Andric off_t CurrentFileOffset = 0; 583480093f4SDimitry Andric off_t OffsetModPage = 0; 584480093f4SDimitry Andric 585480093f4SDimitry Andric /* Whether an exclusive lock on the profile must be dropped after init. 586480093f4SDimitry Andric * Use a cleanup to warn if the unlock does not occur. */ 587480093f4SDimitry Andric COMPILER_RT_CLEANUP(assertIsZero) int ProfileRequiresUnlock = 0; 588480093f4SDimitry Andric 589480093f4SDimitry Andric if (!doMerging()) { 590480093f4SDimitry Andric /* We are not merging profiles, so open the raw profile in append mode. */ 591480093f4SDimitry Andric File = fopen(Filename, "a+b"); 592480093f4SDimitry Andric if (!File) 593480093f4SDimitry Andric return; 594480093f4SDimitry Andric 595480093f4SDimitry Andric /* Check that the offset within the file is page-aligned. */ 596480093f4SDimitry Andric CurrentFileOffset = ftello(File); 597480093f4SDimitry Andric OffsetModPage = CurrentFileOffset % PageSize; 598480093f4SDimitry Andric if (OffsetModPage != 0) { 599480093f4SDimitry Andric PROF_ERR("Continuous counter sync mode is enabled, but raw profile is not" 600480093f4SDimitry Andric "page-aligned. CurrentFileOffset = %" PRIu64 ", pagesz = %u.\n", 601480093f4SDimitry Andric (uint64_t)CurrentFileOffset, PageSize); 602480093f4SDimitry Andric return; 603480093f4SDimitry Andric } 604480093f4SDimitry Andric 605480093f4SDimitry Andric /* Grow the profile so that mmap() can succeed. Leak the file handle, as 606480093f4SDimitry Andric * the file should stay open. */ 607480093f4SDimitry Andric if (writeProfileWithFileObject(Filename, File) != 0) 608480093f4SDimitry Andric return; 609480093f4SDimitry Andric } else { 610480093f4SDimitry Andric /* We are merging profiles. Map the counter section as shared memory into 611480093f4SDimitry Andric * the profile, i.e. into each participating process. An increment in one 612480093f4SDimitry Andric * process should be visible to every other process with the same counter 613480093f4SDimitry Andric * section mapped. */ 614480093f4SDimitry Andric File = lprofOpenFileEx(Filename); 615480093f4SDimitry Andric if (!File) 616480093f4SDimitry Andric return; 617480093f4SDimitry Andric 618480093f4SDimitry Andric ProfileRequiresUnlock = 1; 619480093f4SDimitry Andric 620480093f4SDimitry Andric uint64_t ProfileFileSize; 621480093f4SDimitry Andric if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) 622480093f4SDimitry Andric return unlockProfile(&ProfileRequiresUnlock, File); 623480093f4SDimitry Andric 624480093f4SDimitry Andric if (ProfileFileSize == 0) { 625480093f4SDimitry Andric /* Grow the profile so that mmap() can succeed. Leak the file handle, as 626480093f4SDimitry Andric * the file should stay open. */ 627480093f4SDimitry Andric if (writeProfileWithFileObject(Filename, File) != 0) 628480093f4SDimitry Andric return unlockProfile(&ProfileRequiresUnlock, File); 629480093f4SDimitry Andric } else { 630480093f4SDimitry Andric /* The merged profile has a non-zero length. Check that it is compatible 631480093f4SDimitry Andric * with the data in this process. */ 632480093f4SDimitry Andric char *ProfileBuffer; 633480093f4SDimitry Andric if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1 || 634480093f4SDimitry Andric munmap(ProfileBuffer, ProfileFileSize) == -1) 635480093f4SDimitry Andric return unlockProfile(&ProfileRequiresUnlock, File); 636480093f4SDimitry Andric } 637480093f4SDimitry Andric } 638480093f4SDimitry Andric 639480093f4SDimitry Andric int Fileno = fileno(File); 640480093f4SDimitry Andric 641480093f4SDimitry Andric /* Determine how much padding is needed before/after the counters and after 642480093f4SDimitry Andric * the names. */ 643480093f4SDimitry Andric uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters, 644480093f4SDimitry Andric PaddingBytesAfterNames; 645480093f4SDimitry Andric __llvm_profile_get_padding_sizes_for_counters( 646480093f4SDimitry Andric DataSize, CountersSize, NamesSize, &PaddingBytesBeforeCounters, 647480093f4SDimitry Andric &PaddingBytesAfterCounters, &PaddingBytesAfterNames); 648480093f4SDimitry Andric 649480093f4SDimitry Andric uint64_t PageAlignedCountersLength = 650480093f4SDimitry Andric (CountersSize * sizeof(uint64_t)) + PaddingBytesAfterCounters; 651480093f4SDimitry Andric uint64_t FileOffsetToCounters = 652480093f4SDimitry Andric CurrentFileOffset + sizeof(__llvm_profile_header) + 653480093f4SDimitry Andric (DataSize * sizeof(__llvm_profile_data)) + PaddingBytesBeforeCounters; 654480093f4SDimitry Andric 655480093f4SDimitry Andric uint64_t *CounterMmap = (uint64_t *)mmap( 656480093f4SDimitry Andric (void *)CountersBegin, PageAlignedCountersLength, PROT_READ | PROT_WRITE, 657480093f4SDimitry Andric MAP_FIXED | MAP_SHARED, Fileno, FileOffsetToCounters); 658480093f4SDimitry Andric if (CounterMmap != CountersBegin) { 659480093f4SDimitry Andric PROF_ERR( 660480093f4SDimitry Andric "Continuous counter sync mode is enabled, but mmap() failed (%s).\n" 661480093f4SDimitry Andric " - CountersBegin: %p\n" 662480093f4SDimitry Andric " - PageAlignedCountersLength: %" PRIu64 "\n" 663480093f4SDimitry Andric " - Fileno: %d\n" 664480093f4SDimitry Andric " - FileOffsetToCounters: %" PRIu64 "\n", 665480093f4SDimitry Andric strerror(errno), CountersBegin, PageAlignedCountersLength, Fileno, 666480093f4SDimitry Andric FileOffsetToCounters); 667480093f4SDimitry Andric } 668480093f4SDimitry Andric 669*e8d8bef9SDimitry Andric if (ProfileRequiresUnlock) 670480093f4SDimitry Andric unlockProfile(&ProfileRequiresUnlock, File); 671480093f4SDimitry Andric #endif // defined(__Fuchsia__) || defined(_WIN32) 672480093f4SDimitry Andric } 673480093f4SDimitry Andric 6740b57cec5SDimitry Andric static const char *DefaultProfileName = "default.profraw"; 6750b57cec5SDimitry Andric static void resetFilenameToDefault(void) { 6760b57cec5SDimitry Andric if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 6770b57cec5SDimitry Andric free((void *)lprofCurFilename.FilenamePat); 6780b57cec5SDimitry Andric } 6790b57cec5SDimitry Andric memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 6800b57cec5SDimitry Andric lprofCurFilename.FilenamePat = DefaultProfileName; 6810b57cec5SDimitry Andric lprofCurFilename.PNS = PNS_default; 6820b57cec5SDimitry Andric } 6830b57cec5SDimitry Andric 684480093f4SDimitry Andric static unsigned getMergePoolSize(const char *FilenamePat, int *I) { 685480093f4SDimitry Andric unsigned J = 0, Num = 0; 686480093f4SDimitry Andric for (;; ++J) { 687480093f4SDimitry Andric char C = FilenamePat[*I + J]; 688480093f4SDimitry Andric if (C == 'm') { 689480093f4SDimitry Andric *I += J; 690480093f4SDimitry Andric return Num ? Num : 1; 691480093f4SDimitry Andric } 692480093f4SDimitry Andric if (C < '0' || C > '9') 693480093f4SDimitry Andric break; 694480093f4SDimitry Andric Num = Num * 10 + C - '0'; 695480093f4SDimitry Andric 696480093f4SDimitry Andric /* If FilenamePat[*I+J] is between '0' and '9', the next byte is guaranteed 6970b57cec5SDimitry Andric * to be in-bound as the string is null terminated. */ 698480093f4SDimitry Andric } 699480093f4SDimitry Andric return 0; 7000b57cec5SDimitry Andric } 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric /* Parses the pattern string \p FilenamePat and stores the result to 7030b57cec5SDimitry Andric * lprofcurFilename structure. */ 7040b57cec5SDimitry Andric static int parseFilenamePattern(const char *FilenamePat, 7050b57cec5SDimitry Andric unsigned CopyFilenamePat) { 7060b57cec5SDimitry Andric int NumPids = 0, NumHosts = 0, I; 7070b57cec5SDimitry Andric char *PidChars = &lprofCurFilename.PidChars[0]; 7080b57cec5SDimitry Andric char *Hostname = &lprofCurFilename.Hostname[0]; 7090b57cec5SDimitry Andric int MergingEnabled = 0; 7100b57cec5SDimitry Andric 7110b57cec5SDimitry Andric /* Clean up cached prefix and filename. */ 7120b57cec5SDimitry Andric if (lprofCurFilename.ProfilePathPrefix) 7130b57cec5SDimitry Andric free((void *)lprofCurFilename.ProfilePathPrefix); 7140b57cec5SDimitry Andric 7150b57cec5SDimitry Andric if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 7160b57cec5SDimitry Andric free((void *)lprofCurFilename.FilenamePat); 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 7200b57cec5SDimitry Andric 7210b57cec5SDimitry Andric if (!CopyFilenamePat) 7220b57cec5SDimitry Andric lprofCurFilename.FilenamePat = FilenamePat; 7230b57cec5SDimitry Andric else { 7240b57cec5SDimitry Andric lprofCurFilename.FilenamePat = strdup(FilenamePat); 7250b57cec5SDimitry Andric lprofCurFilename.OwnsFilenamePat = 1; 7260b57cec5SDimitry Andric } 7270b57cec5SDimitry Andric /* Check the filename for "%p", which indicates a pid-substitution. */ 7280b57cec5SDimitry Andric for (I = 0; FilenamePat[I]; ++I) 7290b57cec5SDimitry Andric if (FilenamePat[I] == '%') { 7300b57cec5SDimitry Andric if (FilenamePat[++I] == 'p') { 7310b57cec5SDimitry Andric if (!NumPids++) { 7320b57cec5SDimitry Andric if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) { 7330b57cec5SDimitry Andric PROF_WARN("Unable to get pid for filename pattern %s. Using the " 7340b57cec5SDimitry Andric "default name.", 7350b57cec5SDimitry Andric FilenamePat); 7360b57cec5SDimitry Andric return -1; 7370b57cec5SDimitry Andric } 7380b57cec5SDimitry Andric } 7390b57cec5SDimitry Andric } else if (FilenamePat[I] == 'h') { 7400b57cec5SDimitry Andric if (!NumHosts++) 7410b57cec5SDimitry Andric if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 7420b57cec5SDimitry Andric PROF_WARN("Unable to get hostname for filename pattern %s. Using " 7430b57cec5SDimitry Andric "the default name.", 7440b57cec5SDimitry Andric FilenamePat); 7450b57cec5SDimitry Andric return -1; 7460b57cec5SDimitry Andric } 747*e8d8bef9SDimitry Andric } else if (FilenamePat[I] == 't') { 748*e8d8bef9SDimitry Andric lprofCurFilename.TmpDir = getenv("TMPDIR"); 749*e8d8bef9SDimitry Andric if (!lprofCurFilename.TmpDir) { 750*e8d8bef9SDimitry Andric PROF_WARN("Unable to get the TMPDIR environment variable, referenced " 751*e8d8bef9SDimitry Andric "in %s. Using the default path.", 752*e8d8bef9SDimitry Andric FilenamePat); 753*e8d8bef9SDimitry Andric return -1; 754*e8d8bef9SDimitry Andric } 755480093f4SDimitry Andric } else if (FilenamePat[I] == 'c') { 756480093f4SDimitry Andric if (__llvm_profile_is_continuous_mode_enabled()) { 757480093f4SDimitry Andric PROF_WARN("%%c specifier can only be specified once in %s.\n", 758480093f4SDimitry Andric FilenamePat); 759480093f4SDimitry Andric return -1; 760480093f4SDimitry Andric } 761480093f4SDimitry Andric 762*e8d8bef9SDimitry Andric __llvm_profile_set_page_size(getpagesize()); 763480093f4SDimitry Andric __llvm_profile_enable_continuous_mode(); 764480093f4SDimitry Andric I++; /* advance to 'c' */ 765480093f4SDimitry Andric } else { 766480093f4SDimitry Andric unsigned MergePoolSize = getMergePoolSize(FilenamePat, &I); 767480093f4SDimitry Andric if (!MergePoolSize) 768480093f4SDimitry Andric continue; 7690b57cec5SDimitry Andric if (MergingEnabled) { 7700b57cec5SDimitry Andric PROF_WARN("%%m specifier can only be specified once in %s.\n", 7710b57cec5SDimitry Andric FilenamePat); 7720b57cec5SDimitry Andric return -1; 7730b57cec5SDimitry Andric } 7740b57cec5SDimitry Andric MergingEnabled = 1; 775480093f4SDimitry Andric lprofCurFilename.MergePoolSize = MergePoolSize; 7760b57cec5SDimitry Andric } 7770b57cec5SDimitry Andric } 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric lprofCurFilename.NumPids = NumPids; 7800b57cec5SDimitry Andric lprofCurFilename.NumHosts = NumHosts; 7810b57cec5SDimitry Andric return 0; 7820b57cec5SDimitry Andric } 7830b57cec5SDimitry Andric 7840b57cec5SDimitry Andric static void parseAndSetFilename(const char *FilenamePat, 7850b57cec5SDimitry Andric ProfileNameSpecifier PNS, 7860b57cec5SDimitry Andric unsigned CopyFilenamePat) { 7870b57cec5SDimitry Andric 7880b57cec5SDimitry Andric const char *OldFilenamePat = lprofCurFilename.FilenamePat; 7890b57cec5SDimitry Andric ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 7900b57cec5SDimitry Andric 791480093f4SDimitry Andric /* The old profile name specifier takes precedence over the old one. */ 7920b57cec5SDimitry Andric if (PNS < OldPNS) 7930b57cec5SDimitry Andric return; 7940b57cec5SDimitry Andric 7950b57cec5SDimitry Andric if (!FilenamePat) 7960b57cec5SDimitry Andric FilenamePat = DefaultProfileName; 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 7990b57cec5SDimitry Andric lprofCurFilename.PNS = PNS; 8000b57cec5SDimitry Andric return; 8010b57cec5SDimitry Andric } 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric /* When PNS >= OldPNS, the last one wins. */ 8040b57cec5SDimitry Andric if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat)) 8050b57cec5SDimitry Andric resetFilenameToDefault(); 8060b57cec5SDimitry Andric lprofCurFilename.PNS = PNS; 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric if (!OldFilenamePat) { 8090b57cec5SDimitry Andric if (getenv("LLVM_PROFILE_VERBOSE")) 8100b57cec5SDimitry Andric PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 8110b57cec5SDimitry Andric lprofCurFilename.FilenamePat, getPNSStr(PNS)); 8120b57cec5SDimitry Andric } else { 8130b57cec5SDimitry Andric if (getenv("LLVM_PROFILE_VERBOSE")) 8140b57cec5SDimitry Andric PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 8150b57cec5SDimitry Andric OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 8160b57cec5SDimitry Andric getPNSStr(PNS)); 8170b57cec5SDimitry Andric } 8180b57cec5SDimitry Andric 8190b57cec5SDimitry Andric truncateCurrentFile(); 8205ffd83dbSDimitry Andric if (__llvm_profile_is_continuous_mode_enabled()) { 8215ffd83dbSDimitry Andric if (lprofRuntimeCounterRelocation()) 8225ffd83dbSDimitry Andric relocateCounters(); 8235ffd83dbSDimitry Andric else 824480093f4SDimitry Andric initializeProfileForContinuousMode(); 8250b57cec5SDimitry Andric } 8265ffd83dbSDimitry Andric } 8270b57cec5SDimitry Andric 8280b57cec5SDimitry Andric /* Return buffer length that is required to store the current profile 8290b57cec5SDimitry Andric * filename with PID and hostname substitutions. */ 830480093f4SDimitry Andric /* The length to hold uint64_t followed by 3 digits pool id including '_' */ 8310b57cec5SDimitry Andric #define SIGLEN 24 8320b57cec5SDimitry Andric static int getCurFilenameLength() { 8330b57cec5SDimitry Andric int Len; 8340b57cec5SDimitry Andric if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 8350b57cec5SDimitry Andric return 0; 8360b57cec5SDimitry Andric 8370b57cec5SDimitry Andric if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 838*e8d8bef9SDimitry Andric lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize)) 8390b57cec5SDimitry Andric return strlen(lprofCurFilename.FilenamePat); 8400b57cec5SDimitry Andric 8410b57cec5SDimitry Andric Len = strlen(lprofCurFilename.FilenamePat) + 8420b57cec5SDimitry Andric lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + 843*e8d8bef9SDimitry Andric lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2) + 844*e8d8bef9SDimitry Andric (lprofCurFilename.TmpDir ? (strlen(lprofCurFilename.TmpDir) - 1) : 0); 8450b57cec5SDimitry Andric if (lprofCurFilename.MergePoolSize) 8460b57cec5SDimitry Andric Len += SIGLEN; 8470b57cec5SDimitry Andric return Len; 8480b57cec5SDimitry Andric } 8490b57cec5SDimitry Andric 8500b57cec5SDimitry Andric /* Return the pointer to the current profile file name (after substituting 8510b57cec5SDimitry Andric * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer 8520b57cec5SDimitry Andric * to store the resulting filename. If no substitution is needed, the 8530b57cec5SDimitry Andric * current filename pattern string is directly returned, unless ForceUseBuf 8540b57cec5SDimitry Andric * is enabled. */ 8550b57cec5SDimitry Andric static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) { 856*e8d8bef9SDimitry Andric int I, J, PidLength, HostNameLength, TmpDirLength, FilenamePatLength; 8570b57cec5SDimitry Andric const char *FilenamePat = lprofCurFilename.FilenamePat; 8580b57cec5SDimitry Andric 8590b57cec5SDimitry Andric if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 8600b57cec5SDimitry Andric return 0; 8610b57cec5SDimitry Andric 8620b57cec5SDimitry Andric if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 863*e8d8bef9SDimitry Andric lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize || 864480093f4SDimitry Andric __llvm_profile_is_continuous_mode_enabled())) { 8650b57cec5SDimitry Andric if (!ForceUseBuf) 8660b57cec5SDimitry Andric return lprofCurFilename.FilenamePat; 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric FilenamePatLength = strlen(lprofCurFilename.FilenamePat); 8690b57cec5SDimitry Andric memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength); 8700b57cec5SDimitry Andric FilenameBuf[FilenamePatLength] = '\0'; 8710b57cec5SDimitry Andric return FilenameBuf; 8720b57cec5SDimitry Andric } 8730b57cec5SDimitry Andric 8740b57cec5SDimitry Andric PidLength = strlen(lprofCurFilename.PidChars); 8750b57cec5SDimitry Andric HostNameLength = strlen(lprofCurFilename.Hostname); 876*e8d8bef9SDimitry Andric TmpDirLength = lprofCurFilename.TmpDir ? strlen(lprofCurFilename.TmpDir) : 0; 8770b57cec5SDimitry Andric /* Construct the new filename. */ 8780b57cec5SDimitry Andric for (I = 0, J = 0; FilenamePat[I]; ++I) 8790b57cec5SDimitry Andric if (FilenamePat[I] == '%') { 8800b57cec5SDimitry Andric if (FilenamePat[++I] == 'p') { 8810b57cec5SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); 8820b57cec5SDimitry Andric J += PidLength; 8830b57cec5SDimitry Andric } else if (FilenamePat[I] == 'h') { 8840b57cec5SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); 8850b57cec5SDimitry Andric J += HostNameLength; 886*e8d8bef9SDimitry Andric } else if (FilenamePat[I] == 't') { 887*e8d8bef9SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.TmpDir, TmpDirLength); 888*e8d8bef9SDimitry Andric FilenameBuf[J + TmpDirLength] = DIR_SEPARATOR; 889*e8d8bef9SDimitry Andric J += TmpDirLength + 1; 890480093f4SDimitry Andric } else { 891480093f4SDimitry Andric if (!getMergePoolSize(FilenamePat, &I)) 892480093f4SDimitry Andric continue; 893480093f4SDimitry Andric char LoadModuleSignature[SIGLEN + 1]; 8940b57cec5SDimitry Andric int S; 8950b57cec5SDimitry Andric int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; 896480093f4SDimitry Andric S = snprintf(LoadModuleSignature, SIGLEN + 1, "%" PRIu64 "_%d", 8970b57cec5SDimitry Andric lprofGetLoadModuleSignature(), ProfilePoolId); 8980b57cec5SDimitry Andric if (S == -1 || S > SIGLEN) 8990b57cec5SDimitry Andric S = SIGLEN; 9000b57cec5SDimitry Andric memcpy(FilenameBuf + J, LoadModuleSignature, S); 9010b57cec5SDimitry Andric J += S; 9020b57cec5SDimitry Andric } 9030b57cec5SDimitry Andric /* Drop any unknown substitutions. */ 9040b57cec5SDimitry Andric } else 9050b57cec5SDimitry Andric FilenameBuf[J++] = FilenamePat[I]; 9060b57cec5SDimitry Andric FilenameBuf[J] = 0; 9070b57cec5SDimitry Andric 9080b57cec5SDimitry Andric return FilenameBuf; 9090b57cec5SDimitry Andric } 9100b57cec5SDimitry Andric 9110b57cec5SDimitry Andric /* Returns the pointer to the environment variable 9120b57cec5SDimitry Andric * string. Returns null if the env var is not set. */ 9130b57cec5SDimitry Andric static const char *getFilenamePatFromEnv(void) { 9140b57cec5SDimitry Andric const char *Filename = getenv("LLVM_PROFILE_FILE"); 9150b57cec5SDimitry Andric if (!Filename || !Filename[0]) 9160b57cec5SDimitry Andric return 0; 9170b57cec5SDimitry Andric return Filename; 9180b57cec5SDimitry Andric } 9190b57cec5SDimitry Andric 9200b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 9210b57cec5SDimitry Andric const char *__llvm_profile_get_path_prefix(void) { 9220b57cec5SDimitry Andric int Length; 9230b57cec5SDimitry Andric char *FilenameBuf, *Prefix; 9240b57cec5SDimitry Andric const char *Filename, *PrefixEnd; 9250b57cec5SDimitry Andric 9260b57cec5SDimitry Andric if (lprofCurFilename.ProfilePathPrefix) 9270b57cec5SDimitry Andric return lprofCurFilename.ProfilePathPrefix; 9280b57cec5SDimitry Andric 9290b57cec5SDimitry Andric Length = getCurFilenameLength(); 9300b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 9310b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 9320b57cec5SDimitry Andric if (!Filename) 9330b57cec5SDimitry Andric return "\0"; 9340b57cec5SDimitry Andric 9350b57cec5SDimitry Andric PrefixEnd = lprofFindLastDirSeparator(Filename); 9360b57cec5SDimitry Andric if (!PrefixEnd) 9370b57cec5SDimitry Andric return "\0"; 9380b57cec5SDimitry Andric 9390b57cec5SDimitry Andric Length = PrefixEnd - Filename + 1; 9400b57cec5SDimitry Andric Prefix = (char *)malloc(Length + 1); 9410b57cec5SDimitry Andric if (!Prefix) { 9420b57cec5SDimitry Andric PROF_ERR("Failed to %s\n", "allocate memory."); 9430b57cec5SDimitry Andric return "\0"; 9440b57cec5SDimitry Andric } 9450b57cec5SDimitry Andric memcpy(Prefix, Filename, Length); 9460b57cec5SDimitry Andric Prefix[Length] = '\0'; 9470b57cec5SDimitry Andric lprofCurFilename.ProfilePathPrefix = Prefix; 9480b57cec5SDimitry Andric return Prefix; 9490b57cec5SDimitry Andric } 9500b57cec5SDimitry Andric 9510b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 9520b57cec5SDimitry Andric const char *__llvm_profile_get_filename(void) { 9530b57cec5SDimitry Andric int Length; 9540b57cec5SDimitry Andric char *FilenameBuf; 9550b57cec5SDimitry Andric const char *Filename; 9560b57cec5SDimitry Andric 9570b57cec5SDimitry Andric Length = getCurFilenameLength(); 9580b57cec5SDimitry Andric FilenameBuf = (char *)malloc(Length + 1); 9590b57cec5SDimitry Andric if (!FilenameBuf) { 9600b57cec5SDimitry Andric PROF_ERR("Failed to %s\n", "allocate memory."); 9610b57cec5SDimitry Andric return "\0"; 9620b57cec5SDimitry Andric } 9630b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 1); 9640b57cec5SDimitry Andric if (!Filename) 9650b57cec5SDimitry Andric return "\0"; 9660b57cec5SDimitry Andric 9670b57cec5SDimitry Andric return FilenameBuf; 9680b57cec5SDimitry Andric } 9690b57cec5SDimitry Andric 9705ffd83dbSDimitry Andric /* This API initializes the file handling, both user specified 9710b57cec5SDimitry Andric * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 9725ffd83dbSDimitry Andric * environment variable can override this default value. 9735ffd83dbSDimitry Andric */ 9740b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 9750b57cec5SDimitry Andric void __llvm_profile_initialize_file(void) { 9760b57cec5SDimitry Andric const char *EnvFilenamePat; 9770b57cec5SDimitry Andric const char *SelectedPat = NULL; 9780b57cec5SDimitry Andric ProfileNameSpecifier PNS = PNS_unknown; 9790b57cec5SDimitry Andric int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); 9800b57cec5SDimitry Andric 9815ffd83dbSDimitry Andric if (__llvm_profile_counter_bias != -1) 9825ffd83dbSDimitry Andric lprofSetRuntimeCounterRelocation(1); 9835ffd83dbSDimitry Andric 9840b57cec5SDimitry Andric EnvFilenamePat = getFilenamePatFromEnv(); 9850b57cec5SDimitry Andric if (EnvFilenamePat) { 9860b57cec5SDimitry Andric /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid 9870b57cec5SDimitry Andric at the moment when __llvm_profile_write_file() gets executed. */ 9880b57cec5SDimitry Andric parseAndSetFilename(EnvFilenamePat, PNS_environment, 1); 9890b57cec5SDimitry Andric return; 9900b57cec5SDimitry Andric } else if (hasCommandLineOverrider) { 9910b57cec5SDimitry Andric SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; 9920b57cec5SDimitry Andric PNS = PNS_command_line; 9930b57cec5SDimitry Andric } else { 9940b57cec5SDimitry Andric SelectedPat = NULL; 9950b57cec5SDimitry Andric PNS = PNS_default; 9960b57cec5SDimitry Andric } 9970b57cec5SDimitry Andric 9980b57cec5SDimitry Andric parseAndSetFilename(SelectedPat, PNS, 0); 9990b57cec5SDimitry Andric } 10000b57cec5SDimitry Andric 10015ffd83dbSDimitry Andric /* This method is invoked by the runtime initialization hook 10025ffd83dbSDimitry Andric * InstrProfilingRuntime.o if it is linked in. 10035ffd83dbSDimitry Andric */ 10045ffd83dbSDimitry Andric COMPILER_RT_VISIBILITY 10055ffd83dbSDimitry Andric void __llvm_profile_initialize(void) { 10065ffd83dbSDimitry Andric __llvm_profile_initialize_file(); 10075ffd83dbSDimitry Andric if (!__llvm_profile_is_continuous_mode_enabled()) 10085ffd83dbSDimitry Andric __llvm_profile_register_write_file_atexit(); 10095ffd83dbSDimitry Andric } 10105ffd83dbSDimitry Andric 10110b57cec5SDimitry Andric /* This API is directly called by the user application code. It has the 10120b57cec5SDimitry Andric * highest precedence compared with LLVM_PROFILE_FILE environment variable 10130b57cec5SDimitry Andric * and command line option -fprofile-instr-generate=<profile_name>. 10140b57cec5SDimitry Andric */ 10150b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 10160b57cec5SDimitry Andric void __llvm_profile_set_filename(const char *FilenamePat) { 1017480093f4SDimitry Andric if (__llvm_profile_is_continuous_mode_enabled()) 1018480093f4SDimitry Andric return; 10190b57cec5SDimitry Andric parseAndSetFilename(FilenamePat, PNS_runtime_api, 1); 10200b57cec5SDimitry Andric } 10210b57cec5SDimitry Andric 10220b57cec5SDimitry Andric /* The public API for writing profile data into the file with name 10230b57cec5SDimitry Andric * set by previous calls to __llvm_profile_set_filename or 10240b57cec5SDimitry Andric * __llvm_profile_override_default_filename or 10250b57cec5SDimitry Andric * __llvm_profile_initialize_file. */ 10260b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 10270b57cec5SDimitry Andric int __llvm_profile_write_file(void) { 10280b57cec5SDimitry Andric int rc, Length; 10290b57cec5SDimitry Andric const char *Filename; 10300b57cec5SDimitry Andric char *FilenameBuf; 10310b57cec5SDimitry Andric int PDeathSig = 0; 10320b57cec5SDimitry Andric 1033480093f4SDimitry Andric if (lprofProfileDumped() || __llvm_profile_is_continuous_mode_enabled()) { 10340b57cec5SDimitry Andric PROF_NOTE("Profile data not written to file: %s.\n", "already written"); 10350b57cec5SDimitry Andric return 0; 10360b57cec5SDimitry Andric } 10370b57cec5SDimitry Andric 10380b57cec5SDimitry Andric Length = getCurFilenameLength(); 10390b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 10400b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 10410b57cec5SDimitry Andric 10420b57cec5SDimitry Andric /* Check the filename. */ 10430b57cec5SDimitry Andric if (!Filename) { 10440b57cec5SDimitry Andric PROF_ERR("Failed to write file : %s\n", "Filename not set"); 10450b57cec5SDimitry Andric return -1; 10460b57cec5SDimitry Andric } 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 10490b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 10500b57cec5SDimitry Andric PROF_ERR("Runtime and instrumentation version mismatch : " 10510b57cec5SDimitry Andric "expected %d, but get %d\n", 10520b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 10530b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 10540b57cec5SDimitry Andric return -1; 10550b57cec5SDimitry Andric } 10560b57cec5SDimitry Andric 10570b57cec5SDimitry Andric // Temporarily suspend getting SIGKILL when the parent exits. 10580b57cec5SDimitry Andric PDeathSig = lprofSuspendSigKill(); 10590b57cec5SDimitry Andric 10600b57cec5SDimitry Andric /* Write profile data to the file. */ 10610b57cec5SDimitry Andric rc = writeFile(Filename); 10620b57cec5SDimitry Andric if (rc) 10630b57cec5SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 10640b57cec5SDimitry Andric 10650b57cec5SDimitry Andric // Restore SIGKILL. 10660b57cec5SDimitry Andric if (PDeathSig == 1) 10670b57cec5SDimitry Andric lprofRestoreSigKill(); 10680b57cec5SDimitry Andric 10690b57cec5SDimitry Andric return rc; 10700b57cec5SDimitry Andric } 10710b57cec5SDimitry Andric 10720b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 10730b57cec5SDimitry Andric int __llvm_profile_dump(void) { 10740b57cec5SDimitry Andric if (!doMerging()) 10750b57cec5SDimitry Andric PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering " 10760b57cec5SDimitry Andric " of previously dumped profile data : %s. Either use %%m " 10770b57cec5SDimitry Andric "in profile name or change profile name before dumping.\n", 10780b57cec5SDimitry Andric "online profile merging is not on"); 10790b57cec5SDimitry Andric int rc = __llvm_profile_write_file(); 10805ffd83dbSDimitry Andric lprofSetProfileDumped(1); 10810b57cec5SDimitry Andric return rc; 10820b57cec5SDimitry Andric } 10830b57cec5SDimitry Andric 10840b57cec5SDimitry Andric /* Order file data will be saved in a file with suffx .order. */ 10850b57cec5SDimitry Andric static const char *OrderFileSuffix = ".order"; 10860b57cec5SDimitry Andric 10870b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 10880b57cec5SDimitry Andric int __llvm_orderfile_write_file(void) { 10890b57cec5SDimitry Andric int rc, Length, LengthBeforeAppend, SuffixLength; 10900b57cec5SDimitry Andric const char *Filename; 10910b57cec5SDimitry Andric char *FilenameBuf; 10920b57cec5SDimitry Andric int PDeathSig = 0; 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric SuffixLength = strlen(OrderFileSuffix); 10950b57cec5SDimitry Andric Length = getCurFilenameLength() + SuffixLength; 10960b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 10970b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 1); 10980b57cec5SDimitry Andric 10990b57cec5SDimitry Andric /* Check the filename. */ 11000b57cec5SDimitry Andric if (!Filename) { 11010b57cec5SDimitry Andric PROF_ERR("Failed to write file : %s\n", "Filename not set"); 11020b57cec5SDimitry Andric return -1; 11030b57cec5SDimitry Andric } 11040b57cec5SDimitry Andric 11050b57cec5SDimitry Andric /* Append order file suffix */ 11060b57cec5SDimitry Andric LengthBeforeAppend = strlen(Filename); 11070b57cec5SDimitry Andric memcpy(FilenameBuf + LengthBeforeAppend, OrderFileSuffix, SuffixLength); 11080b57cec5SDimitry Andric FilenameBuf[LengthBeforeAppend + SuffixLength] = '\0'; 11090b57cec5SDimitry Andric 11100b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 11110b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 11120b57cec5SDimitry Andric PROF_ERR("Runtime and instrumentation version mismatch : " 11130b57cec5SDimitry Andric "expected %d, but get %d\n", 11140b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 11150b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 11160b57cec5SDimitry Andric return -1; 11170b57cec5SDimitry Andric } 11180b57cec5SDimitry Andric 11190b57cec5SDimitry Andric // Temporarily suspend getting SIGKILL when the parent exits. 11200b57cec5SDimitry Andric PDeathSig = lprofSuspendSigKill(); 11210b57cec5SDimitry Andric 11220b57cec5SDimitry Andric /* Write order data to the file. */ 11230b57cec5SDimitry Andric rc = writeOrderFile(Filename); 11240b57cec5SDimitry Andric if (rc) 11250b57cec5SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 11260b57cec5SDimitry Andric 11270b57cec5SDimitry Andric // Restore SIGKILL. 11280b57cec5SDimitry Andric if (PDeathSig == 1) 11290b57cec5SDimitry Andric lprofRestoreSigKill(); 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric return rc; 11320b57cec5SDimitry Andric } 11330b57cec5SDimitry Andric 11340b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 11350b57cec5SDimitry Andric int __llvm_orderfile_dump(void) { 11360b57cec5SDimitry Andric int rc = __llvm_orderfile_write_file(); 11370b57cec5SDimitry Andric return rc; 11380b57cec5SDimitry Andric } 11390b57cec5SDimitry Andric 11400b57cec5SDimitry Andric static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 11410b57cec5SDimitry Andric 11420b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 11430b57cec5SDimitry Andric int __llvm_profile_register_write_file_atexit(void) { 11440b57cec5SDimitry Andric static int HasBeenRegistered = 0; 11450b57cec5SDimitry Andric 11460b57cec5SDimitry Andric if (HasBeenRegistered) 11470b57cec5SDimitry Andric return 0; 11480b57cec5SDimitry Andric 11490b57cec5SDimitry Andric lprofSetupValueProfiler(); 11500b57cec5SDimitry Andric 11510b57cec5SDimitry Andric HasBeenRegistered = 1; 11520b57cec5SDimitry Andric return atexit(writeFileWithoutReturn); 11530b57cec5SDimitry Andric } 11540b57cec5SDimitry Andric 11550b57cec5SDimitry Andric #endif 1156