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" 350b57cec5SDimitry Andric #include "InstrProfilingUtil.h" 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric /* From where is profile name specified. 380b57cec5SDimitry Andric * The order the enumerators define their 390b57cec5SDimitry Andric * precedence. Re-order them may lead to 400b57cec5SDimitry Andric * runtime behavior change. */ 410b57cec5SDimitry Andric typedef enum ProfileNameSpecifier { 420b57cec5SDimitry Andric PNS_unknown = 0, 430b57cec5SDimitry Andric PNS_default, 440b57cec5SDimitry Andric PNS_command_line, 450b57cec5SDimitry Andric PNS_environment, 460b57cec5SDimitry Andric PNS_runtime_api 470b57cec5SDimitry Andric } ProfileNameSpecifier; 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric static const char *getPNSStr(ProfileNameSpecifier PNS) { 500b57cec5SDimitry Andric switch (PNS) { 510b57cec5SDimitry Andric case PNS_default: 520b57cec5SDimitry Andric return "default setting"; 530b57cec5SDimitry Andric case PNS_command_line: 540b57cec5SDimitry Andric return "command line"; 550b57cec5SDimitry Andric case PNS_environment: 560b57cec5SDimitry Andric return "environment variable"; 570b57cec5SDimitry Andric case PNS_runtime_api: 580b57cec5SDimitry Andric return "runtime API"; 590b57cec5SDimitry Andric default: 600b57cec5SDimitry Andric return "Unknown"; 610b57cec5SDimitry Andric } 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric #define MAX_PID_SIZE 16 650b57cec5SDimitry Andric /* Data structure holding the result of parsed filename pattern. */ 660b57cec5SDimitry Andric typedef struct lprofFilename { 670b57cec5SDimitry Andric /* File name string possibly with %p or %h specifiers. */ 680b57cec5SDimitry Andric const char *FilenamePat; 690b57cec5SDimitry Andric /* A flag indicating if FilenamePat's memory is allocated 700b57cec5SDimitry Andric * by runtime. */ 710b57cec5SDimitry Andric unsigned OwnsFilenamePat; 720b57cec5SDimitry Andric const char *ProfilePathPrefix; 730b57cec5SDimitry Andric char PidChars[MAX_PID_SIZE]; 740b57cec5SDimitry Andric char Hostname[COMPILER_RT_MAX_HOSTLEN]; 750b57cec5SDimitry Andric unsigned NumPids; 760b57cec5SDimitry Andric unsigned NumHosts; 770b57cec5SDimitry Andric /* When in-process merging is enabled, this parameter specifies 780b57cec5SDimitry Andric * the total number of profile data files shared by all the processes 790b57cec5SDimitry Andric * spawned from the same binary. By default the value is 1. If merging 800b57cec5SDimitry Andric * is not enabled, its value should be 0. This parameter is specified 810b57cec5SDimitry Andric * by the %[0-9]m specifier. For instance %2m enables merging using 820b57cec5SDimitry Andric * 2 profile data files. %1m is equivalent to %m. Also %m specifier 830b57cec5SDimitry Andric * can only appear once at the end of the name pattern. */ 840b57cec5SDimitry Andric unsigned MergePoolSize; 850b57cec5SDimitry Andric ProfileNameSpecifier PNS; 860b57cec5SDimitry Andric } lprofFilename; 870b57cec5SDimitry Andric 88*68d75effSDimitry Andric static lprofFilename lprofCurFilename = {0, 0, 0, {0}, {0}, 89*68d75effSDimitry Andric 0, 0, 0, PNS_unknown}; 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric static int ProfileMergeRequested = 0; 920b57cec5SDimitry Andric static int isProfileMergeRequested() { return ProfileMergeRequested; } 930b57cec5SDimitry Andric static void setProfileMergeRequested(int EnableMerge) { 940b57cec5SDimitry Andric ProfileMergeRequested = EnableMerge; 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric static FILE *ProfileFile = NULL; 980b57cec5SDimitry Andric static FILE *getProfileFile() { return ProfileFile; } 990b57cec5SDimitry Andric static void setProfileFile(FILE *File) { ProfileFile = File; } 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric COMPILER_RT_VISIBILITY void __llvm_profile_set_file_object(FILE *File, 1020b57cec5SDimitry Andric int EnableMerge) { 1030b57cec5SDimitry Andric setProfileFile(File); 1040b57cec5SDimitry Andric setProfileMergeRequested(EnableMerge); 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric static int getCurFilenameLength(); 1080b57cec5SDimitry Andric static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf); 1090b57cec5SDimitry Andric static unsigned doMerging() { 1100b57cec5SDimitry Andric return lprofCurFilename.MergePoolSize || isProfileMergeRequested(); 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric /* Return 1 if there is an error, otherwise return 0. */ 1140b57cec5SDimitry Andric static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, 1150b57cec5SDimitry Andric uint32_t NumIOVecs) { 1160b57cec5SDimitry Andric uint32_t I; 1170b57cec5SDimitry Andric FILE *File = (FILE *)This->WriterCtx; 1180b57cec5SDimitry Andric for (I = 0; I < NumIOVecs; I++) { 1190b57cec5SDimitry Andric if (IOVecs[I].Data) { 1200b57cec5SDimitry Andric if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != 1210b57cec5SDimitry Andric IOVecs[I].NumElm) 1220b57cec5SDimitry Andric return 1; 1230b57cec5SDimitry Andric } else { 1240b57cec5SDimitry Andric if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1) 1250b57cec5SDimitry Andric return 1; 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric return 0; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric /* TODO: make buffer size controllable by an internal option, and compiler can pass the size 1320b57cec5SDimitry Andric to runtime via a variable. */ 1330b57cec5SDimitry Andric static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) { 1340b57cec5SDimitry Andric if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) != 1350b57cec5SDimitry Andric INSTR_ORDER_FILE_BUFFER_SIZE) 1360b57cec5SDimitry Andric return 1; 1370b57cec5SDimitry Andric return 0; 1380b57cec5SDimitry Andric } 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric static void initFileWriter(ProfDataWriter *This, FILE *File) { 1410b57cec5SDimitry Andric This->Write = fileWriter; 1420b57cec5SDimitry Andric This->WriterCtx = File; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric COMPILER_RT_VISIBILITY ProfBufferIO * 1460b57cec5SDimitry Andric lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { 1470b57cec5SDimitry Andric FreeHook = &free; 1480b57cec5SDimitry Andric DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); 1490b57cec5SDimitry Andric VPBufferSize = BufferSz; 1500b57cec5SDimitry Andric ProfDataWriter *fileWriter = 1510b57cec5SDimitry Andric (ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1); 1520b57cec5SDimitry Andric initFileWriter(fileWriter, File); 1530b57cec5SDimitry Andric ProfBufferIO *IO = lprofCreateBufferIO(fileWriter); 1540b57cec5SDimitry Andric IO->OwnFileWriter = 1; 1550b57cec5SDimitry Andric return IO; 1560b57cec5SDimitry Andric } 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric static void setupIOBuffer() { 1590b57cec5SDimitry Andric const char *BufferSzStr = 0; 1600b57cec5SDimitry Andric BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); 1610b57cec5SDimitry Andric if (BufferSzStr && BufferSzStr[0]) { 1620b57cec5SDimitry Andric VPBufferSize = atoi(BufferSzStr); 1630b57cec5SDimitry Andric DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric /* Read profile data in \c ProfileFile and merge with in-memory 1680b57cec5SDimitry Andric profile counters. Returns -1 if there is fatal error, otheriwse 1690b57cec5SDimitry Andric 0 is returned. Returning 0 does not mean merge is actually 1700b57cec5SDimitry Andric performed. If merge is actually done, *MergeDone is set to 1. 1710b57cec5SDimitry Andric */ 1720b57cec5SDimitry Andric static int doProfileMerging(FILE *ProfileFile, int *MergeDone) { 1730b57cec5SDimitry Andric uint64_t ProfileFileSize; 1740b57cec5SDimitry Andric char *ProfileBuffer; 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric if (fseek(ProfileFile, 0L, SEEK_END) == -1) { 1770b57cec5SDimitry Andric PROF_ERR("Unable to merge profile data, unable to get size: %s\n", 1780b57cec5SDimitry Andric strerror(errno)); 1790b57cec5SDimitry Andric return -1; 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric ProfileFileSize = ftell(ProfileFile); 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric /* Restore file offset. */ 1840b57cec5SDimitry Andric if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { 1850b57cec5SDimitry Andric PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", 1860b57cec5SDimitry Andric strerror(errno)); 1870b57cec5SDimitry Andric return -1; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric /* Nothing to merge. */ 1910b57cec5SDimitry Andric if (ProfileFileSize < sizeof(__llvm_profile_header)) { 1920b57cec5SDimitry Andric if (ProfileFileSize) 1930b57cec5SDimitry Andric PROF_WARN("Unable to merge profile data: %s\n", 1940b57cec5SDimitry Andric "source profile file is too small."); 1950b57cec5SDimitry Andric return 0; 1960b57cec5SDimitry Andric } 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, 1990b57cec5SDimitry Andric fileno(ProfileFile), 0); 2000b57cec5SDimitry Andric if (ProfileBuffer == MAP_FAILED) { 2010b57cec5SDimitry Andric PROF_ERR("Unable to merge profile data, mmap failed: %s\n", 2020b57cec5SDimitry Andric strerror(errno)); 2030b57cec5SDimitry Andric return -1; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) { 2070b57cec5SDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 2080b57cec5SDimitry Andric PROF_WARN("Unable to merge profile data: %s\n", 2090b57cec5SDimitry Andric "source profile file is not compatible."); 2100b57cec5SDimitry Andric return 0; 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric /* Now start merging */ 2140b57cec5SDimitry Andric __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // Truncate the file in case merging of value profile did not happend to 2170b57cec5SDimitry Andric // prevent from leaving garbage data at the end of the profile file. 2180b57cec5SDimitry Andric COMPILER_RT_FTRUNCATE(ProfileFile, __llvm_profile_get_size_for_buffer()); 2190b57cec5SDimitry Andric 2200b57cec5SDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 2210b57cec5SDimitry Andric *MergeDone = 1; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric return 0; 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric 2260b57cec5SDimitry Andric /* Create the directory holding the file, if needed. */ 2270b57cec5SDimitry Andric static void createProfileDir(const char *Filename) { 2280b57cec5SDimitry Andric size_t Length = strlen(Filename); 2290b57cec5SDimitry Andric if (lprofFindFirstDirSeparator(Filename)) { 2300b57cec5SDimitry Andric char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 2310b57cec5SDimitry Andric strncpy(Copy, Filename, Length + 1); 2320b57cec5SDimitry Andric __llvm_profile_recursive_mkdir(Copy); 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric /* Open the profile data for merging. It opens the file in r+b mode with 2370b57cec5SDimitry Andric * file locking. If the file has content which is compatible with the 2380b57cec5SDimitry Andric * current process, it also reads in the profile data in the file and merge 2390b57cec5SDimitry Andric * it with in-memory counters. After the profile data is merged in memory, 2400b57cec5SDimitry Andric * the original profile data is truncated and gets ready for the profile 2410b57cec5SDimitry Andric * dumper. With profile merging enabled, each executable as well as any of 2420b57cec5SDimitry Andric * its instrumented shared libraries dump profile data into their own data file. 2430b57cec5SDimitry Andric */ 2440b57cec5SDimitry Andric static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) { 2450b57cec5SDimitry Andric FILE *ProfileFile = NULL; 2460b57cec5SDimitry Andric int rc; 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric ProfileFile = getProfileFile(); 2490b57cec5SDimitry Andric if (ProfileFile) { 2500b57cec5SDimitry Andric lprofLockFileHandle(ProfileFile); 2510b57cec5SDimitry Andric } else { 2520b57cec5SDimitry Andric createProfileDir(ProfileFileName); 2530b57cec5SDimitry Andric ProfileFile = lprofOpenFileEx(ProfileFileName); 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric if (!ProfileFile) 2560b57cec5SDimitry Andric return NULL; 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric rc = doProfileMerging(ProfileFile, MergeDone); 2590b57cec5SDimitry Andric if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) || 2600b57cec5SDimitry Andric fseek(ProfileFile, 0L, SEEK_SET) == -1) { 2610b57cec5SDimitry Andric PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 2620b57cec5SDimitry Andric strerror(errno)); 2630b57cec5SDimitry Andric fclose(ProfileFile); 2640b57cec5SDimitry Andric return NULL; 2650b57cec5SDimitry Andric } 2660b57cec5SDimitry Andric return ProfileFile; 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric static FILE *getFileObject(const char *OutputName) { 2700b57cec5SDimitry Andric FILE *File; 2710b57cec5SDimitry Andric File = getProfileFile(); 2720b57cec5SDimitry Andric if (File != NULL) { 2730b57cec5SDimitry Andric return File; 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric return fopen(OutputName, "ab"); 2770b57cec5SDimitry Andric } 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric /* Write profile data to file \c OutputName. */ 2800b57cec5SDimitry Andric static int writeFile(const char *OutputName) { 2810b57cec5SDimitry Andric int RetVal; 2820b57cec5SDimitry Andric FILE *OutputFile; 2830b57cec5SDimitry Andric 2840b57cec5SDimitry Andric int MergeDone = 0; 2850b57cec5SDimitry Andric VPMergeHook = &lprofMergeValueProfData; 2860b57cec5SDimitry Andric if (doMerging()) 2870b57cec5SDimitry Andric OutputFile = openFileForMerging(OutputName, &MergeDone); 2880b57cec5SDimitry Andric else 2890b57cec5SDimitry Andric OutputFile = getFileObject(OutputName); 2900b57cec5SDimitry Andric 2910b57cec5SDimitry Andric if (!OutputFile) 2920b57cec5SDimitry Andric return -1; 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric FreeHook = &free; 2950b57cec5SDimitry Andric setupIOBuffer(); 2960b57cec5SDimitry Andric ProfDataWriter fileWriter; 2970b57cec5SDimitry Andric initFileWriter(&fileWriter, OutputFile); 2980b57cec5SDimitry Andric RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone); 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric if (OutputFile == getProfileFile()) { 3010b57cec5SDimitry Andric fflush(OutputFile); 3020b57cec5SDimitry Andric if (doMerging()) { 3030b57cec5SDimitry Andric lprofUnlockFileHandle(OutputFile); 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric } else { 3060b57cec5SDimitry Andric fclose(OutputFile); 3070b57cec5SDimitry Andric } 3080b57cec5SDimitry Andric 3090b57cec5SDimitry Andric return RetVal; 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric 3120b57cec5SDimitry Andric /* Write order data to file \c OutputName. */ 3130b57cec5SDimitry Andric static int writeOrderFile(const char *OutputName) { 3140b57cec5SDimitry Andric int RetVal; 3150b57cec5SDimitry Andric FILE *OutputFile; 3160b57cec5SDimitry Andric 3170b57cec5SDimitry Andric OutputFile = fopen(OutputName, "w"); 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric if (!OutputFile) { 3200b57cec5SDimitry Andric PROF_WARN("can't open file with mode ab: %s\n", OutputName); 3210b57cec5SDimitry Andric return -1; 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric FreeHook = &free; 3250b57cec5SDimitry Andric setupIOBuffer(); 3260b57cec5SDimitry Andric const uint32_t *DataBegin = __llvm_profile_begin_orderfile(); 3270b57cec5SDimitry Andric RetVal = orderFileWriter(OutputFile, DataBegin); 3280b57cec5SDimitry Andric 3290b57cec5SDimitry Andric fclose(OutputFile); 3300b57cec5SDimitry Andric return RetVal; 3310b57cec5SDimitry Andric } 3320b57cec5SDimitry Andric 3330b57cec5SDimitry Andric static void truncateCurrentFile(void) { 3340b57cec5SDimitry Andric const char *Filename; 3350b57cec5SDimitry Andric char *FilenameBuf; 3360b57cec5SDimitry Andric FILE *File; 3370b57cec5SDimitry Andric int Length; 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric Length = getCurFilenameLength(); 3400b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 3410b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 3420b57cec5SDimitry Andric if (!Filename) 3430b57cec5SDimitry Andric return; 3440b57cec5SDimitry Andric 3450b57cec5SDimitry Andric /* By pass file truncation to allow online raw profile 3460b57cec5SDimitry Andric * merging. */ 3470b57cec5SDimitry Andric if (lprofCurFilename.MergePoolSize) 3480b57cec5SDimitry Andric return; 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric createProfileDir(Filename); 3510b57cec5SDimitry Andric 3520b57cec5SDimitry Andric /* Truncate the file. Later we'll reopen and append. */ 3530b57cec5SDimitry Andric File = fopen(Filename, "w"); 3540b57cec5SDimitry Andric if (!File) 3550b57cec5SDimitry Andric return; 3560b57cec5SDimitry Andric fclose(File); 3570b57cec5SDimitry Andric } 3580b57cec5SDimitry Andric 3590b57cec5SDimitry Andric static const char *DefaultProfileName = "default.profraw"; 3600b57cec5SDimitry Andric static void resetFilenameToDefault(void) { 3610b57cec5SDimitry Andric if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 3620b57cec5SDimitry Andric free((void *)lprofCurFilename.FilenamePat); 3630b57cec5SDimitry Andric } 3640b57cec5SDimitry Andric memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 3650b57cec5SDimitry Andric lprofCurFilename.FilenamePat = DefaultProfileName; 3660b57cec5SDimitry Andric lprofCurFilename.PNS = PNS_default; 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric static int containsMergeSpecifier(const char *FilenamePat, int I) { 3700b57cec5SDimitry Andric return (FilenamePat[I] == 'm' || 3710b57cec5SDimitry Andric (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && 3720b57cec5SDimitry Andric /* If FilenamePat[I] is not '\0', the next byte is guaranteed 3730b57cec5SDimitry Andric * to be in-bound as the string is null terminated. */ 3740b57cec5SDimitry Andric FilenamePat[I + 1] == 'm')); 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric /* Parses the pattern string \p FilenamePat and stores the result to 3780b57cec5SDimitry Andric * lprofcurFilename structure. */ 3790b57cec5SDimitry Andric static int parseFilenamePattern(const char *FilenamePat, 3800b57cec5SDimitry Andric unsigned CopyFilenamePat) { 3810b57cec5SDimitry Andric int NumPids = 0, NumHosts = 0, I; 3820b57cec5SDimitry Andric char *PidChars = &lprofCurFilename.PidChars[0]; 3830b57cec5SDimitry Andric char *Hostname = &lprofCurFilename.Hostname[0]; 3840b57cec5SDimitry Andric int MergingEnabled = 0; 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric /* Clean up cached prefix and filename. */ 3870b57cec5SDimitry Andric if (lprofCurFilename.ProfilePathPrefix) 3880b57cec5SDimitry Andric free((void *)lprofCurFilename.ProfilePathPrefix); 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 3910b57cec5SDimitry Andric free((void *)lprofCurFilename.FilenamePat); 3920b57cec5SDimitry Andric } 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 3950b57cec5SDimitry Andric 3960b57cec5SDimitry Andric if (!CopyFilenamePat) 3970b57cec5SDimitry Andric lprofCurFilename.FilenamePat = FilenamePat; 3980b57cec5SDimitry Andric else { 3990b57cec5SDimitry Andric lprofCurFilename.FilenamePat = strdup(FilenamePat); 4000b57cec5SDimitry Andric lprofCurFilename.OwnsFilenamePat = 1; 4010b57cec5SDimitry Andric } 4020b57cec5SDimitry Andric /* Check the filename for "%p", which indicates a pid-substitution. */ 4030b57cec5SDimitry Andric for (I = 0; FilenamePat[I]; ++I) 4040b57cec5SDimitry Andric if (FilenamePat[I] == '%') { 4050b57cec5SDimitry Andric if (FilenamePat[++I] == 'p') { 4060b57cec5SDimitry Andric if (!NumPids++) { 4070b57cec5SDimitry Andric if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) { 4080b57cec5SDimitry Andric PROF_WARN("Unable to get pid for filename pattern %s. Using the " 4090b57cec5SDimitry Andric "default name.", 4100b57cec5SDimitry Andric FilenamePat); 4110b57cec5SDimitry Andric return -1; 4120b57cec5SDimitry Andric } 4130b57cec5SDimitry Andric } 4140b57cec5SDimitry Andric } else if (FilenamePat[I] == 'h') { 4150b57cec5SDimitry Andric if (!NumHosts++) 4160b57cec5SDimitry Andric if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 4170b57cec5SDimitry Andric PROF_WARN("Unable to get hostname for filename pattern %s. Using " 4180b57cec5SDimitry Andric "the default name.", 4190b57cec5SDimitry Andric FilenamePat); 4200b57cec5SDimitry Andric return -1; 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric } else if (containsMergeSpecifier(FilenamePat, I)) { 4230b57cec5SDimitry Andric if (MergingEnabled) { 4240b57cec5SDimitry Andric PROF_WARN("%%m specifier can only be specified once in %s.\n", 4250b57cec5SDimitry Andric FilenamePat); 4260b57cec5SDimitry Andric return -1; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric MergingEnabled = 1; 4290b57cec5SDimitry Andric if (FilenamePat[I] == 'm') 4300b57cec5SDimitry Andric lprofCurFilename.MergePoolSize = 1; 4310b57cec5SDimitry Andric else { 4320b57cec5SDimitry Andric lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; 4330b57cec5SDimitry Andric I++; /* advance to 'm' */ 4340b57cec5SDimitry Andric } 4350b57cec5SDimitry Andric } 4360b57cec5SDimitry Andric } 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric lprofCurFilename.NumPids = NumPids; 4390b57cec5SDimitry Andric lprofCurFilename.NumHosts = NumHosts; 4400b57cec5SDimitry Andric return 0; 4410b57cec5SDimitry Andric } 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric static void parseAndSetFilename(const char *FilenamePat, 4440b57cec5SDimitry Andric ProfileNameSpecifier PNS, 4450b57cec5SDimitry Andric unsigned CopyFilenamePat) { 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric const char *OldFilenamePat = lprofCurFilename.FilenamePat; 4480b57cec5SDimitry Andric ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 4490b57cec5SDimitry Andric 4500b57cec5SDimitry Andric if (PNS < OldPNS) 4510b57cec5SDimitry Andric return; 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric if (!FilenamePat) 4540b57cec5SDimitry Andric FilenamePat = DefaultProfileName; 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 4570b57cec5SDimitry Andric lprofCurFilename.PNS = PNS; 4580b57cec5SDimitry Andric return; 4590b57cec5SDimitry Andric } 4600b57cec5SDimitry Andric 4610b57cec5SDimitry Andric /* When PNS >= OldPNS, the last one wins. */ 4620b57cec5SDimitry Andric if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat)) 4630b57cec5SDimitry Andric resetFilenameToDefault(); 4640b57cec5SDimitry Andric lprofCurFilename.PNS = PNS; 4650b57cec5SDimitry Andric 4660b57cec5SDimitry Andric if (!OldFilenamePat) { 4670b57cec5SDimitry Andric if (getenv("LLVM_PROFILE_VERBOSE")) 4680b57cec5SDimitry Andric PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 4690b57cec5SDimitry Andric lprofCurFilename.FilenamePat, getPNSStr(PNS)); 4700b57cec5SDimitry Andric } else { 4710b57cec5SDimitry Andric if (getenv("LLVM_PROFILE_VERBOSE")) 4720b57cec5SDimitry Andric PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 4730b57cec5SDimitry Andric OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 4740b57cec5SDimitry Andric getPNSStr(PNS)); 4750b57cec5SDimitry Andric } 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric truncateCurrentFile(); 4780b57cec5SDimitry Andric } 4790b57cec5SDimitry Andric 4800b57cec5SDimitry Andric /* Return buffer length that is required to store the current profile 4810b57cec5SDimitry Andric * filename with PID and hostname substitutions. */ 4820b57cec5SDimitry Andric /* The length to hold uint64_t followed by 2 digit pool id including '_' */ 4830b57cec5SDimitry Andric #define SIGLEN 24 4840b57cec5SDimitry Andric static int getCurFilenameLength() { 4850b57cec5SDimitry Andric int Len; 4860b57cec5SDimitry Andric if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 4870b57cec5SDimitry Andric return 0; 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 4900b57cec5SDimitry Andric lprofCurFilename.MergePoolSize)) 4910b57cec5SDimitry Andric return strlen(lprofCurFilename.FilenamePat); 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric Len = strlen(lprofCurFilename.FilenamePat) + 4940b57cec5SDimitry Andric lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + 4950b57cec5SDimitry Andric lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); 4960b57cec5SDimitry Andric if (lprofCurFilename.MergePoolSize) 4970b57cec5SDimitry Andric Len += SIGLEN; 4980b57cec5SDimitry Andric return Len; 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric 5010b57cec5SDimitry Andric /* Return the pointer to the current profile file name (after substituting 5020b57cec5SDimitry Andric * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer 5030b57cec5SDimitry Andric * to store the resulting filename. If no substitution is needed, the 5040b57cec5SDimitry Andric * current filename pattern string is directly returned, unless ForceUseBuf 5050b57cec5SDimitry Andric * is enabled. */ 5060b57cec5SDimitry Andric static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) { 5070b57cec5SDimitry Andric int I, J, PidLength, HostNameLength, FilenamePatLength; 5080b57cec5SDimitry Andric const char *FilenamePat = lprofCurFilename.FilenamePat; 5090b57cec5SDimitry Andric 5100b57cec5SDimitry Andric if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 5110b57cec5SDimitry Andric return 0; 5120b57cec5SDimitry Andric 5130b57cec5SDimitry Andric if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 5140b57cec5SDimitry Andric lprofCurFilename.MergePoolSize)) { 5150b57cec5SDimitry Andric if (!ForceUseBuf) 5160b57cec5SDimitry Andric return lprofCurFilename.FilenamePat; 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric FilenamePatLength = strlen(lprofCurFilename.FilenamePat); 5190b57cec5SDimitry Andric memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength); 5200b57cec5SDimitry Andric FilenameBuf[FilenamePatLength] = '\0'; 5210b57cec5SDimitry Andric return FilenameBuf; 5220b57cec5SDimitry Andric } 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric PidLength = strlen(lprofCurFilename.PidChars); 5250b57cec5SDimitry Andric HostNameLength = strlen(lprofCurFilename.Hostname); 5260b57cec5SDimitry Andric /* Construct the new filename. */ 5270b57cec5SDimitry Andric for (I = 0, J = 0; FilenamePat[I]; ++I) 5280b57cec5SDimitry Andric if (FilenamePat[I] == '%') { 5290b57cec5SDimitry Andric if (FilenamePat[++I] == 'p') { 5300b57cec5SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); 5310b57cec5SDimitry Andric J += PidLength; 5320b57cec5SDimitry Andric } else if (FilenamePat[I] == 'h') { 5330b57cec5SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); 5340b57cec5SDimitry Andric J += HostNameLength; 5350b57cec5SDimitry Andric } else if (containsMergeSpecifier(FilenamePat, I)) { 5360b57cec5SDimitry Andric char LoadModuleSignature[SIGLEN]; 5370b57cec5SDimitry Andric int S; 5380b57cec5SDimitry Andric int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; 5390b57cec5SDimitry Andric S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d", 5400b57cec5SDimitry Andric lprofGetLoadModuleSignature(), ProfilePoolId); 5410b57cec5SDimitry Andric if (S == -1 || S > SIGLEN) 5420b57cec5SDimitry Andric S = SIGLEN; 5430b57cec5SDimitry Andric memcpy(FilenameBuf + J, LoadModuleSignature, S); 5440b57cec5SDimitry Andric J += S; 5450b57cec5SDimitry Andric if (FilenamePat[I] != 'm') 5460b57cec5SDimitry Andric I++; 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric /* Drop any unknown substitutions. */ 5490b57cec5SDimitry Andric } else 5500b57cec5SDimitry Andric FilenameBuf[J++] = FilenamePat[I]; 5510b57cec5SDimitry Andric FilenameBuf[J] = 0; 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric return FilenameBuf; 5540b57cec5SDimitry Andric } 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric /* Returns the pointer to the environment variable 5570b57cec5SDimitry Andric * string. Returns null if the env var is not set. */ 5580b57cec5SDimitry Andric static const char *getFilenamePatFromEnv(void) { 5590b57cec5SDimitry Andric const char *Filename = getenv("LLVM_PROFILE_FILE"); 5600b57cec5SDimitry Andric if (!Filename || !Filename[0]) 5610b57cec5SDimitry Andric return 0; 5620b57cec5SDimitry Andric return Filename; 5630b57cec5SDimitry Andric } 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 5660b57cec5SDimitry Andric const char *__llvm_profile_get_path_prefix(void) { 5670b57cec5SDimitry Andric int Length; 5680b57cec5SDimitry Andric char *FilenameBuf, *Prefix; 5690b57cec5SDimitry Andric const char *Filename, *PrefixEnd; 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric if (lprofCurFilename.ProfilePathPrefix) 5720b57cec5SDimitry Andric return lprofCurFilename.ProfilePathPrefix; 5730b57cec5SDimitry Andric 5740b57cec5SDimitry Andric Length = getCurFilenameLength(); 5750b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 5760b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 5770b57cec5SDimitry Andric if (!Filename) 5780b57cec5SDimitry Andric return "\0"; 5790b57cec5SDimitry Andric 5800b57cec5SDimitry Andric PrefixEnd = lprofFindLastDirSeparator(Filename); 5810b57cec5SDimitry Andric if (!PrefixEnd) 5820b57cec5SDimitry Andric return "\0"; 5830b57cec5SDimitry Andric 5840b57cec5SDimitry Andric Length = PrefixEnd - Filename + 1; 5850b57cec5SDimitry Andric Prefix = (char *)malloc(Length + 1); 5860b57cec5SDimitry Andric if (!Prefix) { 5870b57cec5SDimitry Andric PROF_ERR("Failed to %s\n", "allocate memory."); 5880b57cec5SDimitry Andric return "\0"; 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric memcpy(Prefix, Filename, Length); 5910b57cec5SDimitry Andric Prefix[Length] = '\0'; 5920b57cec5SDimitry Andric lprofCurFilename.ProfilePathPrefix = Prefix; 5930b57cec5SDimitry Andric return Prefix; 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 5970b57cec5SDimitry Andric const char *__llvm_profile_get_filename(void) { 5980b57cec5SDimitry Andric int Length; 5990b57cec5SDimitry Andric char *FilenameBuf; 6000b57cec5SDimitry Andric const char *Filename; 6010b57cec5SDimitry Andric 6020b57cec5SDimitry Andric Length = getCurFilenameLength(); 6030b57cec5SDimitry Andric FilenameBuf = (char *)malloc(Length + 1); 6040b57cec5SDimitry Andric if (!FilenameBuf) { 6050b57cec5SDimitry Andric PROF_ERR("Failed to %s\n", "allocate memory."); 6060b57cec5SDimitry Andric return "\0"; 6070b57cec5SDimitry Andric } 6080b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 1); 6090b57cec5SDimitry Andric if (!Filename) 6100b57cec5SDimitry Andric return "\0"; 6110b57cec5SDimitry Andric 6120b57cec5SDimitry Andric return FilenameBuf; 6130b57cec5SDimitry Andric } 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric /* This method is invoked by the runtime initialization hook 6160b57cec5SDimitry Andric * InstrProfilingRuntime.o if it is linked in. Both user specified 6170b57cec5SDimitry Andric * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 6180b57cec5SDimitry Andric * environment variable can override this default value. */ 6190b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 6200b57cec5SDimitry Andric void __llvm_profile_initialize_file(void) { 6210b57cec5SDimitry Andric const char *EnvFilenamePat; 6220b57cec5SDimitry Andric const char *SelectedPat = NULL; 6230b57cec5SDimitry Andric ProfileNameSpecifier PNS = PNS_unknown; 6240b57cec5SDimitry Andric int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); 6250b57cec5SDimitry Andric 6260b57cec5SDimitry Andric EnvFilenamePat = getFilenamePatFromEnv(); 6270b57cec5SDimitry Andric if (EnvFilenamePat) { 6280b57cec5SDimitry Andric /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid 6290b57cec5SDimitry Andric at the moment when __llvm_profile_write_file() gets executed. */ 6300b57cec5SDimitry Andric parseAndSetFilename(EnvFilenamePat, PNS_environment, 1); 6310b57cec5SDimitry Andric return; 6320b57cec5SDimitry Andric } else if (hasCommandLineOverrider) { 6330b57cec5SDimitry Andric SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; 6340b57cec5SDimitry Andric PNS = PNS_command_line; 6350b57cec5SDimitry Andric } else { 6360b57cec5SDimitry Andric SelectedPat = NULL; 6370b57cec5SDimitry Andric PNS = PNS_default; 6380b57cec5SDimitry Andric } 6390b57cec5SDimitry Andric 6400b57cec5SDimitry Andric parseAndSetFilename(SelectedPat, PNS, 0); 6410b57cec5SDimitry Andric } 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric /* This API is directly called by the user application code. It has the 6440b57cec5SDimitry Andric * highest precedence compared with LLVM_PROFILE_FILE environment variable 6450b57cec5SDimitry Andric * and command line option -fprofile-instr-generate=<profile_name>. 6460b57cec5SDimitry Andric */ 6470b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 6480b57cec5SDimitry Andric void __llvm_profile_set_filename(const char *FilenamePat) { 6490b57cec5SDimitry Andric parseAndSetFilename(FilenamePat, PNS_runtime_api, 1); 6500b57cec5SDimitry Andric } 6510b57cec5SDimitry Andric 6520b57cec5SDimitry Andric /* The public API for writing profile data into the file with name 6530b57cec5SDimitry Andric * set by previous calls to __llvm_profile_set_filename or 6540b57cec5SDimitry Andric * __llvm_profile_override_default_filename or 6550b57cec5SDimitry Andric * __llvm_profile_initialize_file. */ 6560b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 6570b57cec5SDimitry Andric int __llvm_profile_write_file(void) { 6580b57cec5SDimitry Andric int rc, Length; 6590b57cec5SDimitry Andric const char *Filename; 6600b57cec5SDimitry Andric char *FilenameBuf; 6610b57cec5SDimitry Andric int PDeathSig = 0; 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric if (lprofProfileDumped()) { 6640b57cec5SDimitry Andric PROF_NOTE("Profile data not written to file: %s.\n", "already written"); 6650b57cec5SDimitry Andric return 0; 6660b57cec5SDimitry Andric } 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric Length = getCurFilenameLength(); 6690b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 6700b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 6710b57cec5SDimitry Andric 6720b57cec5SDimitry Andric /* Check the filename. */ 6730b57cec5SDimitry Andric if (!Filename) { 6740b57cec5SDimitry Andric PROF_ERR("Failed to write file : %s\n", "Filename not set"); 6750b57cec5SDimitry Andric return -1; 6760b57cec5SDimitry Andric } 6770b57cec5SDimitry Andric 6780b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 6790b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 6800b57cec5SDimitry Andric PROF_ERR("Runtime and instrumentation version mismatch : " 6810b57cec5SDimitry Andric "expected %d, but get %d\n", 6820b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 6830b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 6840b57cec5SDimitry Andric return -1; 6850b57cec5SDimitry Andric } 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric // Temporarily suspend getting SIGKILL when the parent exits. 6880b57cec5SDimitry Andric PDeathSig = lprofSuspendSigKill(); 6890b57cec5SDimitry Andric 6900b57cec5SDimitry Andric /* Write profile data to the file. */ 6910b57cec5SDimitry Andric rc = writeFile(Filename); 6920b57cec5SDimitry Andric if (rc) 6930b57cec5SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 6940b57cec5SDimitry Andric 6950b57cec5SDimitry Andric // Restore SIGKILL. 6960b57cec5SDimitry Andric if (PDeathSig == 1) 6970b57cec5SDimitry Andric lprofRestoreSigKill(); 6980b57cec5SDimitry Andric 6990b57cec5SDimitry Andric return rc; 7000b57cec5SDimitry Andric } 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 7030b57cec5SDimitry Andric int __llvm_profile_dump(void) { 7040b57cec5SDimitry Andric if (!doMerging()) 7050b57cec5SDimitry Andric PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering " 7060b57cec5SDimitry Andric " of previously dumped profile data : %s. Either use %%m " 7070b57cec5SDimitry Andric "in profile name or change profile name before dumping.\n", 7080b57cec5SDimitry Andric "online profile merging is not on"); 7090b57cec5SDimitry Andric int rc = __llvm_profile_write_file(); 7100b57cec5SDimitry Andric lprofSetProfileDumped(); 7110b57cec5SDimitry Andric return rc; 7120b57cec5SDimitry Andric } 7130b57cec5SDimitry Andric 7140b57cec5SDimitry Andric /* Order file data will be saved in a file with suffx .order. */ 7150b57cec5SDimitry Andric static const char *OrderFileSuffix = ".order"; 7160b57cec5SDimitry Andric 7170b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 7180b57cec5SDimitry Andric int __llvm_orderfile_write_file(void) { 7190b57cec5SDimitry Andric int rc, Length, LengthBeforeAppend, SuffixLength; 7200b57cec5SDimitry Andric const char *Filename; 7210b57cec5SDimitry Andric char *FilenameBuf; 7220b57cec5SDimitry Andric int PDeathSig = 0; 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric SuffixLength = strlen(OrderFileSuffix); 7250b57cec5SDimitry Andric Length = getCurFilenameLength() + SuffixLength; 7260b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 7270b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 1); 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric /* Check the filename. */ 7300b57cec5SDimitry Andric if (!Filename) { 7310b57cec5SDimitry Andric PROF_ERR("Failed to write file : %s\n", "Filename not set"); 7320b57cec5SDimitry Andric return -1; 7330b57cec5SDimitry Andric } 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric /* Append order file suffix */ 7360b57cec5SDimitry Andric LengthBeforeAppend = strlen(Filename); 7370b57cec5SDimitry Andric memcpy(FilenameBuf + LengthBeforeAppend, OrderFileSuffix, SuffixLength); 7380b57cec5SDimitry Andric FilenameBuf[LengthBeforeAppend + SuffixLength] = '\0'; 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 7410b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 7420b57cec5SDimitry Andric PROF_ERR("Runtime and instrumentation version mismatch : " 7430b57cec5SDimitry Andric "expected %d, but get %d\n", 7440b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 7450b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 7460b57cec5SDimitry Andric return -1; 7470b57cec5SDimitry Andric } 7480b57cec5SDimitry Andric 7490b57cec5SDimitry Andric // Temporarily suspend getting SIGKILL when the parent exits. 7500b57cec5SDimitry Andric PDeathSig = lprofSuspendSigKill(); 7510b57cec5SDimitry Andric 7520b57cec5SDimitry Andric /* Write order data to the file. */ 7530b57cec5SDimitry Andric rc = writeOrderFile(Filename); 7540b57cec5SDimitry Andric if (rc) 7550b57cec5SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 7560b57cec5SDimitry Andric 7570b57cec5SDimitry Andric // Restore SIGKILL. 7580b57cec5SDimitry Andric if (PDeathSig == 1) 7590b57cec5SDimitry Andric lprofRestoreSigKill(); 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric return rc; 7620b57cec5SDimitry Andric } 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 7650b57cec5SDimitry Andric int __llvm_orderfile_dump(void) { 7660b57cec5SDimitry Andric int rc = __llvm_orderfile_write_file(); 7670b57cec5SDimitry Andric return rc; 7680b57cec5SDimitry Andric } 7690b57cec5SDimitry Andric 7700b57cec5SDimitry Andric static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 7730b57cec5SDimitry Andric int __llvm_profile_register_write_file_atexit(void) { 7740b57cec5SDimitry Andric static int HasBeenRegistered = 0; 7750b57cec5SDimitry Andric 7760b57cec5SDimitry Andric if (HasBeenRegistered) 7770b57cec5SDimitry Andric return 0; 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric lprofSetupValueProfiler(); 7800b57cec5SDimitry Andric 7810b57cec5SDimitry Andric HasBeenRegistered = 1; 7820b57cec5SDimitry Andric return atexit(writeFileWithoutReturn); 7830b57cec5SDimitry Andric } 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric #endif 786