1*0b57cec5SDimitry Andric /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\ 2*0b57cec5SDimitry Andric |* 3*0b57cec5SDimitry Andric |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric |* See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric |* 7*0b57cec5SDimitry Andric \*===----------------------------------------------------------------------===*/ 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #if !defined(__Fuchsia__) 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include <errno.h> 12*0b57cec5SDimitry Andric #include <stdio.h> 13*0b57cec5SDimitry Andric #include <stdlib.h> 14*0b57cec5SDimitry Andric #include <string.h> 15*0b57cec5SDimitry Andric #ifdef _MSC_VER 16*0b57cec5SDimitry Andric /* For _alloca. */ 17*0b57cec5SDimitry Andric #include <malloc.h> 18*0b57cec5SDimitry Andric #endif 19*0b57cec5SDimitry Andric #if defined(_WIN32) 20*0b57cec5SDimitry Andric #include "WindowsMMap.h" 21*0b57cec5SDimitry Andric /* For _chsize_s */ 22*0b57cec5SDimitry Andric #include <io.h> 23*0b57cec5SDimitry Andric #include <process.h> 24*0b57cec5SDimitry Andric #else 25*0b57cec5SDimitry Andric #include <sys/file.h> 26*0b57cec5SDimitry Andric #include <sys/mman.h> 27*0b57cec5SDimitry Andric #include <unistd.h> 28*0b57cec5SDimitry Andric #if defined(__linux__) 29*0b57cec5SDimitry Andric #include <sys/types.h> 30*0b57cec5SDimitry Andric #endif 31*0b57cec5SDimitry Andric #endif 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric #include "InstrProfiling.h" 34*0b57cec5SDimitry Andric #include "InstrProfilingInternal.h" 35*0b57cec5SDimitry Andric #include "InstrProfilingUtil.h" 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric /* From where is profile name specified. 38*0b57cec5SDimitry Andric * The order the enumerators define their 39*0b57cec5SDimitry Andric * precedence. Re-order them may lead to 40*0b57cec5SDimitry Andric * runtime behavior change. */ 41*0b57cec5SDimitry Andric typedef enum ProfileNameSpecifier { 42*0b57cec5SDimitry Andric PNS_unknown = 0, 43*0b57cec5SDimitry Andric PNS_default, 44*0b57cec5SDimitry Andric PNS_command_line, 45*0b57cec5SDimitry Andric PNS_environment, 46*0b57cec5SDimitry Andric PNS_runtime_api 47*0b57cec5SDimitry Andric } ProfileNameSpecifier; 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric static const char *getPNSStr(ProfileNameSpecifier PNS) { 50*0b57cec5SDimitry Andric switch (PNS) { 51*0b57cec5SDimitry Andric case PNS_default: 52*0b57cec5SDimitry Andric return "default setting"; 53*0b57cec5SDimitry Andric case PNS_command_line: 54*0b57cec5SDimitry Andric return "command line"; 55*0b57cec5SDimitry Andric case PNS_environment: 56*0b57cec5SDimitry Andric return "environment variable"; 57*0b57cec5SDimitry Andric case PNS_runtime_api: 58*0b57cec5SDimitry Andric return "runtime API"; 59*0b57cec5SDimitry Andric default: 60*0b57cec5SDimitry Andric return "Unknown"; 61*0b57cec5SDimitry Andric } 62*0b57cec5SDimitry Andric } 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric #define MAX_PID_SIZE 16 65*0b57cec5SDimitry Andric /* Data structure holding the result of parsed filename pattern. */ 66*0b57cec5SDimitry Andric typedef struct lprofFilename { 67*0b57cec5SDimitry Andric /* File name string possibly with %p or %h specifiers. */ 68*0b57cec5SDimitry Andric const char *FilenamePat; 69*0b57cec5SDimitry Andric /* A flag indicating if FilenamePat's memory is allocated 70*0b57cec5SDimitry Andric * by runtime. */ 71*0b57cec5SDimitry Andric unsigned OwnsFilenamePat; 72*0b57cec5SDimitry Andric const char *ProfilePathPrefix; 73*0b57cec5SDimitry Andric const char *Filename; 74*0b57cec5SDimitry Andric char PidChars[MAX_PID_SIZE]; 75*0b57cec5SDimitry Andric char Hostname[COMPILER_RT_MAX_HOSTLEN]; 76*0b57cec5SDimitry Andric unsigned NumPids; 77*0b57cec5SDimitry Andric unsigned NumHosts; 78*0b57cec5SDimitry Andric /* When in-process merging is enabled, this parameter specifies 79*0b57cec5SDimitry Andric * the total number of profile data files shared by all the processes 80*0b57cec5SDimitry Andric * spawned from the same binary. By default the value is 1. If merging 81*0b57cec5SDimitry Andric * is not enabled, its value should be 0. This parameter is specified 82*0b57cec5SDimitry Andric * by the %[0-9]m specifier. For instance %2m enables merging using 83*0b57cec5SDimitry Andric * 2 profile data files. %1m is equivalent to %m. Also %m specifier 84*0b57cec5SDimitry Andric * can only appear once at the end of the name pattern. */ 85*0b57cec5SDimitry Andric unsigned MergePoolSize; 86*0b57cec5SDimitry Andric ProfileNameSpecifier PNS; 87*0b57cec5SDimitry Andric } lprofFilename; 88*0b57cec5SDimitry Andric 89*0b57cec5SDimitry Andric COMPILER_RT_WEAK lprofFilename lprofCurFilename = {0, 0, 0, 0, {0}, 90*0b57cec5SDimitry Andric {0}, 0, 0, 0, PNS_unknown}; 91*0b57cec5SDimitry Andric 92*0b57cec5SDimitry Andric static int ProfileMergeRequested = 0; 93*0b57cec5SDimitry Andric static int isProfileMergeRequested() { return ProfileMergeRequested; } 94*0b57cec5SDimitry Andric static void setProfileMergeRequested(int EnableMerge) { 95*0b57cec5SDimitry Andric ProfileMergeRequested = EnableMerge; 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric static FILE *ProfileFile = NULL; 99*0b57cec5SDimitry Andric static FILE *getProfileFile() { return ProfileFile; } 100*0b57cec5SDimitry Andric static void setProfileFile(FILE *File) { ProfileFile = File; } 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY void __llvm_profile_set_file_object(FILE *File, 103*0b57cec5SDimitry Andric int EnableMerge) { 104*0b57cec5SDimitry Andric setProfileFile(File); 105*0b57cec5SDimitry Andric setProfileMergeRequested(EnableMerge); 106*0b57cec5SDimitry Andric } 107*0b57cec5SDimitry Andric 108*0b57cec5SDimitry Andric static int getCurFilenameLength(); 109*0b57cec5SDimitry Andric static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf); 110*0b57cec5SDimitry Andric static unsigned doMerging() { 111*0b57cec5SDimitry Andric return lprofCurFilename.MergePoolSize || isProfileMergeRequested(); 112*0b57cec5SDimitry Andric } 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric /* Return 1 if there is an error, otherwise return 0. */ 115*0b57cec5SDimitry Andric static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, 116*0b57cec5SDimitry Andric uint32_t NumIOVecs) { 117*0b57cec5SDimitry Andric uint32_t I; 118*0b57cec5SDimitry Andric FILE *File = (FILE *)This->WriterCtx; 119*0b57cec5SDimitry Andric for (I = 0; I < NumIOVecs; I++) { 120*0b57cec5SDimitry Andric if (IOVecs[I].Data) { 121*0b57cec5SDimitry Andric if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != 122*0b57cec5SDimitry Andric IOVecs[I].NumElm) 123*0b57cec5SDimitry Andric return 1; 124*0b57cec5SDimitry Andric } else { 125*0b57cec5SDimitry Andric if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1) 126*0b57cec5SDimitry Andric return 1; 127*0b57cec5SDimitry Andric } 128*0b57cec5SDimitry Andric } 129*0b57cec5SDimitry Andric return 0; 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric 132*0b57cec5SDimitry Andric /* TODO: make buffer size controllable by an internal option, and compiler can pass the size 133*0b57cec5SDimitry Andric to runtime via a variable. */ 134*0b57cec5SDimitry Andric static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) { 135*0b57cec5SDimitry Andric if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) != 136*0b57cec5SDimitry Andric INSTR_ORDER_FILE_BUFFER_SIZE) 137*0b57cec5SDimitry Andric return 1; 138*0b57cec5SDimitry Andric return 0; 139*0b57cec5SDimitry Andric } 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric static void initFileWriter(ProfDataWriter *This, FILE *File) { 142*0b57cec5SDimitry Andric This->Write = fileWriter; 143*0b57cec5SDimitry Andric This->WriterCtx = File; 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric 146*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY ProfBufferIO * 147*0b57cec5SDimitry Andric lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { 148*0b57cec5SDimitry Andric FreeHook = &free; 149*0b57cec5SDimitry Andric DynamicBufferIOBuffer = (uint8_t *)calloc(BufferSz, 1); 150*0b57cec5SDimitry Andric VPBufferSize = BufferSz; 151*0b57cec5SDimitry Andric ProfDataWriter *fileWriter = 152*0b57cec5SDimitry Andric (ProfDataWriter *)calloc(sizeof(ProfDataWriter), 1); 153*0b57cec5SDimitry Andric initFileWriter(fileWriter, File); 154*0b57cec5SDimitry Andric ProfBufferIO *IO = lprofCreateBufferIO(fileWriter); 155*0b57cec5SDimitry Andric IO->OwnFileWriter = 1; 156*0b57cec5SDimitry Andric return IO; 157*0b57cec5SDimitry Andric } 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric static void setupIOBuffer() { 160*0b57cec5SDimitry Andric const char *BufferSzStr = 0; 161*0b57cec5SDimitry Andric BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); 162*0b57cec5SDimitry Andric if (BufferSzStr && BufferSzStr[0]) { 163*0b57cec5SDimitry Andric VPBufferSize = atoi(BufferSzStr); 164*0b57cec5SDimitry Andric DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); 165*0b57cec5SDimitry Andric } 166*0b57cec5SDimitry Andric } 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric /* Read profile data in \c ProfileFile and merge with in-memory 169*0b57cec5SDimitry Andric profile counters. Returns -1 if there is fatal error, otheriwse 170*0b57cec5SDimitry Andric 0 is returned. Returning 0 does not mean merge is actually 171*0b57cec5SDimitry Andric performed. If merge is actually done, *MergeDone is set to 1. 172*0b57cec5SDimitry Andric */ 173*0b57cec5SDimitry Andric static int doProfileMerging(FILE *ProfileFile, int *MergeDone) { 174*0b57cec5SDimitry Andric uint64_t ProfileFileSize; 175*0b57cec5SDimitry Andric char *ProfileBuffer; 176*0b57cec5SDimitry Andric 177*0b57cec5SDimitry Andric if (fseek(ProfileFile, 0L, SEEK_END) == -1) { 178*0b57cec5SDimitry Andric PROF_ERR("Unable to merge profile data, unable to get size: %s\n", 179*0b57cec5SDimitry Andric strerror(errno)); 180*0b57cec5SDimitry Andric return -1; 181*0b57cec5SDimitry Andric } 182*0b57cec5SDimitry Andric ProfileFileSize = ftell(ProfileFile); 183*0b57cec5SDimitry Andric 184*0b57cec5SDimitry Andric /* Restore file offset. */ 185*0b57cec5SDimitry Andric if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { 186*0b57cec5SDimitry Andric PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", 187*0b57cec5SDimitry Andric strerror(errno)); 188*0b57cec5SDimitry Andric return -1; 189*0b57cec5SDimitry Andric } 190*0b57cec5SDimitry Andric 191*0b57cec5SDimitry Andric /* Nothing to merge. */ 192*0b57cec5SDimitry Andric if (ProfileFileSize < sizeof(__llvm_profile_header)) { 193*0b57cec5SDimitry Andric if (ProfileFileSize) 194*0b57cec5SDimitry Andric PROF_WARN("Unable to merge profile data: %s\n", 195*0b57cec5SDimitry Andric "source profile file is too small."); 196*0b57cec5SDimitry Andric return 0; 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, 200*0b57cec5SDimitry Andric fileno(ProfileFile), 0); 201*0b57cec5SDimitry Andric if (ProfileBuffer == MAP_FAILED) { 202*0b57cec5SDimitry Andric PROF_ERR("Unable to merge profile data, mmap failed: %s\n", 203*0b57cec5SDimitry Andric strerror(errno)); 204*0b57cec5SDimitry Andric return -1; 205*0b57cec5SDimitry Andric } 206*0b57cec5SDimitry Andric 207*0b57cec5SDimitry Andric if (__llvm_profile_check_compatibility(ProfileBuffer, ProfileFileSize)) { 208*0b57cec5SDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 209*0b57cec5SDimitry Andric PROF_WARN("Unable to merge profile data: %s\n", 210*0b57cec5SDimitry Andric "source profile file is not compatible."); 211*0b57cec5SDimitry Andric return 0; 212*0b57cec5SDimitry Andric } 213*0b57cec5SDimitry Andric 214*0b57cec5SDimitry Andric /* Now start merging */ 215*0b57cec5SDimitry Andric __llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize); 216*0b57cec5SDimitry Andric 217*0b57cec5SDimitry Andric // Truncate the file in case merging of value profile did not happend to 218*0b57cec5SDimitry Andric // prevent from leaving garbage data at the end of the profile file. 219*0b57cec5SDimitry Andric COMPILER_RT_FTRUNCATE(ProfileFile, __llvm_profile_get_size_for_buffer()); 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 222*0b57cec5SDimitry Andric *MergeDone = 1; 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric return 0; 225*0b57cec5SDimitry Andric } 226*0b57cec5SDimitry Andric 227*0b57cec5SDimitry Andric /* Create the directory holding the file, if needed. */ 228*0b57cec5SDimitry Andric static void createProfileDir(const char *Filename) { 229*0b57cec5SDimitry Andric size_t Length = strlen(Filename); 230*0b57cec5SDimitry Andric if (lprofFindFirstDirSeparator(Filename)) { 231*0b57cec5SDimitry Andric char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 232*0b57cec5SDimitry Andric strncpy(Copy, Filename, Length + 1); 233*0b57cec5SDimitry Andric __llvm_profile_recursive_mkdir(Copy); 234*0b57cec5SDimitry Andric } 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric /* Open the profile data for merging. It opens the file in r+b mode with 238*0b57cec5SDimitry Andric * file locking. If the file has content which is compatible with the 239*0b57cec5SDimitry Andric * current process, it also reads in the profile data in the file and merge 240*0b57cec5SDimitry Andric * it with in-memory counters. After the profile data is merged in memory, 241*0b57cec5SDimitry Andric * the original profile data is truncated and gets ready for the profile 242*0b57cec5SDimitry Andric * dumper. With profile merging enabled, each executable as well as any of 243*0b57cec5SDimitry Andric * its instrumented shared libraries dump profile data into their own data file. 244*0b57cec5SDimitry Andric */ 245*0b57cec5SDimitry Andric static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) { 246*0b57cec5SDimitry Andric FILE *ProfileFile = NULL; 247*0b57cec5SDimitry Andric int rc; 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric ProfileFile = getProfileFile(); 250*0b57cec5SDimitry Andric if (ProfileFile) { 251*0b57cec5SDimitry Andric lprofLockFileHandle(ProfileFile); 252*0b57cec5SDimitry Andric } else { 253*0b57cec5SDimitry Andric createProfileDir(ProfileFileName); 254*0b57cec5SDimitry Andric ProfileFile = lprofOpenFileEx(ProfileFileName); 255*0b57cec5SDimitry Andric } 256*0b57cec5SDimitry Andric if (!ProfileFile) 257*0b57cec5SDimitry Andric return NULL; 258*0b57cec5SDimitry Andric 259*0b57cec5SDimitry Andric rc = doProfileMerging(ProfileFile, MergeDone); 260*0b57cec5SDimitry Andric if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) || 261*0b57cec5SDimitry Andric fseek(ProfileFile, 0L, SEEK_SET) == -1) { 262*0b57cec5SDimitry Andric PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 263*0b57cec5SDimitry Andric strerror(errno)); 264*0b57cec5SDimitry Andric fclose(ProfileFile); 265*0b57cec5SDimitry Andric return NULL; 266*0b57cec5SDimitry Andric } 267*0b57cec5SDimitry Andric return ProfileFile; 268*0b57cec5SDimitry Andric } 269*0b57cec5SDimitry Andric 270*0b57cec5SDimitry Andric static FILE *getFileObject(const char *OutputName) { 271*0b57cec5SDimitry Andric FILE *File; 272*0b57cec5SDimitry Andric File = getProfileFile(); 273*0b57cec5SDimitry Andric if (File != NULL) { 274*0b57cec5SDimitry Andric return File; 275*0b57cec5SDimitry Andric } 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric return fopen(OutputName, "ab"); 278*0b57cec5SDimitry Andric } 279*0b57cec5SDimitry Andric 280*0b57cec5SDimitry Andric /* Write profile data to file \c OutputName. */ 281*0b57cec5SDimitry Andric static int writeFile(const char *OutputName) { 282*0b57cec5SDimitry Andric int RetVal; 283*0b57cec5SDimitry Andric FILE *OutputFile; 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric int MergeDone = 0; 286*0b57cec5SDimitry Andric VPMergeHook = &lprofMergeValueProfData; 287*0b57cec5SDimitry Andric if (doMerging()) 288*0b57cec5SDimitry Andric OutputFile = openFileForMerging(OutputName, &MergeDone); 289*0b57cec5SDimitry Andric else 290*0b57cec5SDimitry Andric OutputFile = getFileObject(OutputName); 291*0b57cec5SDimitry Andric 292*0b57cec5SDimitry Andric if (!OutputFile) 293*0b57cec5SDimitry Andric return -1; 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric FreeHook = &free; 296*0b57cec5SDimitry Andric setupIOBuffer(); 297*0b57cec5SDimitry Andric ProfDataWriter fileWriter; 298*0b57cec5SDimitry Andric initFileWriter(&fileWriter, OutputFile); 299*0b57cec5SDimitry Andric RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone); 300*0b57cec5SDimitry Andric 301*0b57cec5SDimitry Andric if (OutputFile == getProfileFile()) { 302*0b57cec5SDimitry Andric fflush(OutputFile); 303*0b57cec5SDimitry Andric if (doMerging()) { 304*0b57cec5SDimitry Andric lprofUnlockFileHandle(OutputFile); 305*0b57cec5SDimitry Andric } 306*0b57cec5SDimitry Andric } else { 307*0b57cec5SDimitry Andric fclose(OutputFile); 308*0b57cec5SDimitry Andric } 309*0b57cec5SDimitry Andric 310*0b57cec5SDimitry Andric return RetVal; 311*0b57cec5SDimitry Andric } 312*0b57cec5SDimitry Andric 313*0b57cec5SDimitry Andric /* Write order data to file \c OutputName. */ 314*0b57cec5SDimitry Andric static int writeOrderFile(const char *OutputName) { 315*0b57cec5SDimitry Andric int RetVal; 316*0b57cec5SDimitry Andric FILE *OutputFile; 317*0b57cec5SDimitry Andric 318*0b57cec5SDimitry Andric OutputFile = fopen(OutputName, "w"); 319*0b57cec5SDimitry Andric 320*0b57cec5SDimitry Andric if (!OutputFile) { 321*0b57cec5SDimitry Andric PROF_WARN("can't open file with mode ab: %s\n", OutputName); 322*0b57cec5SDimitry Andric return -1; 323*0b57cec5SDimitry Andric } 324*0b57cec5SDimitry Andric 325*0b57cec5SDimitry Andric FreeHook = &free; 326*0b57cec5SDimitry Andric setupIOBuffer(); 327*0b57cec5SDimitry Andric const uint32_t *DataBegin = __llvm_profile_begin_orderfile(); 328*0b57cec5SDimitry Andric RetVal = orderFileWriter(OutputFile, DataBegin); 329*0b57cec5SDimitry Andric 330*0b57cec5SDimitry Andric fclose(OutputFile); 331*0b57cec5SDimitry Andric return RetVal; 332*0b57cec5SDimitry Andric } 333*0b57cec5SDimitry Andric 334*0b57cec5SDimitry Andric static void truncateCurrentFile(void) { 335*0b57cec5SDimitry Andric const char *Filename; 336*0b57cec5SDimitry Andric char *FilenameBuf; 337*0b57cec5SDimitry Andric FILE *File; 338*0b57cec5SDimitry Andric int Length; 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric Length = getCurFilenameLength(); 341*0b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 342*0b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 343*0b57cec5SDimitry Andric if (!Filename) 344*0b57cec5SDimitry Andric return; 345*0b57cec5SDimitry Andric 346*0b57cec5SDimitry Andric /* By pass file truncation to allow online raw profile 347*0b57cec5SDimitry Andric * merging. */ 348*0b57cec5SDimitry Andric if (lprofCurFilename.MergePoolSize) 349*0b57cec5SDimitry Andric return; 350*0b57cec5SDimitry Andric 351*0b57cec5SDimitry Andric createProfileDir(Filename); 352*0b57cec5SDimitry Andric 353*0b57cec5SDimitry Andric /* Truncate the file. Later we'll reopen and append. */ 354*0b57cec5SDimitry Andric File = fopen(Filename, "w"); 355*0b57cec5SDimitry Andric if (!File) 356*0b57cec5SDimitry Andric return; 357*0b57cec5SDimitry Andric fclose(File); 358*0b57cec5SDimitry Andric } 359*0b57cec5SDimitry Andric 360*0b57cec5SDimitry Andric static const char *DefaultProfileName = "default.profraw"; 361*0b57cec5SDimitry Andric static void resetFilenameToDefault(void) { 362*0b57cec5SDimitry Andric if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 363*0b57cec5SDimitry Andric free((void *)lprofCurFilename.FilenamePat); 364*0b57cec5SDimitry Andric } 365*0b57cec5SDimitry Andric memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 366*0b57cec5SDimitry Andric lprofCurFilename.FilenamePat = DefaultProfileName; 367*0b57cec5SDimitry Andric lprofCurFilename.PNS = PNS_default; 368*0b57cec5SDimitry Andric } 369*0b57cec5SDimitry Andric 370*0b57cec5SDimitry Andric static int containsMergeSpecifier(const char *FilenamePat, int I) { 371*0b57cec5SDimitry Andric return (FilenamePat[I] == 'm' || 372*0b57cec5SDimitry Andric (FilenamePat[I] >= '1' && FilenamePat[I] <= '9' && 373*0b57cec5SDimitry Andric /* If FilenamePat[I] is not '\0', the next byte is guaranteed 374*0b57cec5SDimitry Andric * to be in-bound as the string is null terminated. */ 375*0b57cec5SDimitry Andric FilenamePat[I + 1] == 'm')); 376*0b57cec5SDimitry Andric } 377*0b57cec5SDimitry Andric 378*0b57cec5SDimitry Andric /* Parses the pattern string \p FilenamePat and stores the result to 379*0b57cec5SDimitry Andric * lprofcurFilename structure. */ 380*0b57cec5SDimitry Andric static int parseFilenamePattern(const char *FilenamePat, 381*0b57cec5SDimitry Andric unsigned CopyFilenamePat) { 382*0b57cec5SDimitry Andric int NumPids = 0, NumHosts = 0, I; 383*0b57cec5SDimitry Andric char *PidChars = &lprofCurFilename.PidChars[0]; 384*0b57cec5SDimitry Andric char *Hostname = &lprofCurFilename.Hostname[0]; 385*0b57cec5SDimitry Andric int MergingEnabled = 0; 386*0b57cec5SDimitry Andric 387*0b57cec5SDimitry Andric /* Clean up cached prefix and filename. */ 388*0b57cec5SDimitry Andric if (lprofCurFilename.ProfilePathPrefix) 389*0b57cec5SDimitry Andric free((void *)lprofCurFilename.ProfilePathPrefix); 390*0b57cec5SDimitry Andric if (lprofCurFilename.Filename) 391*0b57cec5SDimitry Andric free((void *)lprofCurFilename.Filename); 392*0b57cec5SDimitry Andric 393*0b57cec5SDimitry Andric if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 394*0b57cec5SDimitry Andric free((void *)lprofCurFilename.FilenamePat); 395*0b57cec5SDimitry Andric } 396*0b57cec5SDimitry Andric 397*0b57cec5SDimitry Andric memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 398*0b57cec5SDimitry Andric 399*0b57cec5SDimitry Andric if (!CopyFilenamePat) 400*0b57cec5SDimitry Andric lprofCurFilename.FilenamePat = FilenamePat; 401*0b57cec5SDimitry Andric else { 402*0b57cec5SDimitry Andric lprofCurFilename.FilenamePat = strdup(FilenamePat); 403*0b57cec5SDimitry Andric lprofCurFilename.OwnsFilenamePat = 1; 404*0b57cec5SDimitry Andric } 405*0b57cec5SDimitry Andric /* Check the filename for "%p", which indicates a pid-substitution. */ 406*0b57cec5SDimitry Andric for (I = 0; FilenamePat[I]; ++I) 407*0b57cec5SDimitry Andric if (FilenamePat[I] == '%') { 408*0b57cec5SDimitry Andric if (FilenamePat[++I] == 'p') { 409*0b57cec5SDimitry Andric if (!NumPids++) { 410*0b57cec5SDimitry Andric if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) { 411*0b57cec5SDimitry Andric PROF_WARN("Unable to get pid for filename pattern %s. Using the " 412*0b57cec5SDimitry Andric "default name.", 413*0b57cec5SDimitry Andric FilenamePat); 414*0b57cec5SDimitry Andric return -1; 415*0b57cec5SDimitry Andric } 416*0b57cec5SDimitry Andric } 417*0b57cec5SDimitry Andric } else if (FilenamePat[I] == 'h') { 418*0b57cec5SDimitry Andric if (!NumHosts++) 419*0b57cec5SDimitry Andric if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 420*0b57cec5SDimitry Andric PROF_WARN("Unable to get hostname for filename pattern %s. Using " 421*0b57cec5SDimitry Andric "the default name.", 422*0b57cec5SDimitry Andric FilenamePat); 423*0b57cec5SDimitry Andric return -1; 424*0b57cec5SDimitry Andric } 425*0b57cec5SDimitry Andric } else if (containsMergeSpecifier(FilenamePat, I)) { 426*0b57cec5SDimitry Andric if (MergingEnabled) { 427*0b57cec5SDimitry Andric PROF_WARN("%%m specifier can only be specified once in %s.\n", 428*0b57cec5SDimitry Andric FilenamePat); 429*0b57cec5SDimitry Andric return -1; 430*0b57cec5SDimitry Andric } 431*0b57cec5SDimitry Andric MergingEnabled = 1; 432*0b57cec5SDimitry Andric if (FilenamePat[I] == 'm') 433*0b57cec5SDimitry Andric lprofCurFilename.MergePoolSize = 1; 434*0b57cec5SDimitry Andric else { 435*0b57cec5SDimitry Andric lprofCurFilename.MergePoolSize = FilenamePat[I] - '0'; 436*0b57cec5SDimitry Andric I++; /* advance to 'm' */ 437*0b57cec5SDimitry Andric } 438*0b57cec5SDimitry Andric } 439*0b57cec5SDimitry Andric } 440*0b57cec5SDimitry Andric 441*0b57cec5SDimitry Andric lprofCurFilename.NumPids = NumPids; 442*0b57cec5SDimitry Andric lprofCurFilename.NumHosts = NumHosts; 443*0b57cec5SDimitry Andric return 0; 444*0b57cec5SDimitry Andric } 445*0b57cec5SDimitry Andric 446*0b57cec5SDimitry Andric static void parseAndSetFilename(const char *FilenamePat, 447*0b57cec5SDimitry Andric ProfileNameSpecifier PNS, 448*0b57cec5SDimitry Andric unsigned CopyFilenamePat) { 449*0b57cec5SDimitry Andric 450*0b57cec5SDimitry Andric const char *OldFilenamePat = lprofCurFilename.FilenamePat; 451*0b57cec5SDimitry Andric ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 452*0b57cec5SDimitry Andric 453*0b57cec5SDimitry Andric if (PNS < OldPNS) 454*0b57cec5SDimitry Andric return; 455*0b57cec5SDimitry Andric 456*0b57cec5SDimitry Andric if (!FilenamePat) 457*0b57cec5SDimitry Andric FilenamePat = DefaultProfileName; 458*0b57cec5SDimitry Andric 459*0b57cec5SDimitry Andric if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 460*0b57cec5SDimitry Andric lprofCurFilename.PNS = PNS; 461*0b57cec5SDimitry Andric return; 462*0b57cec5SDimitry Andric } 463*0b57cec5SDimitry Andric 464*0b57cec5SDimitry Andric /* When PNS >= OldPNS, the last one wins. */ 465*0b57cec5SDimitry Andric if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat)) 466*0b57cec5SDimitry Andric resetFilenameToDefault(); 467*0b57cec5SDimitry Andric lprofCurFilename.PNS = PNS; 468*0b57cec5SDimitry Andric 469*0b57cec5SDimitry Andric if (!OldFilenamePat) { 470*0b57cec5SDimitry Andric if (getenv("LLVM_PROFILE_VERBOSE")) 471*0b57cec5SDimitry Andric PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 472*0b57cec5SDimitry Andric lprofCurFilename.FilenamePat, getPNSStr(PNS)); 473*0b57cec5SDimitry Andric } else { 474*0b57cec5SDimitry Andric if (getenv("LLVM_PROFILE_VERBOSE")) 475*0b57cec5SDimitry Andric PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 476*0b57cec5SDimitry Andric OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 477*0b57cec5SDimitry Andric getPNSStr(PNS)); 478*0b57cec5SDimitry Andric } 479*0b57cec5SDimitry Andric 480*0b57cec5SDimitry Andric truncateCurrentFile(); 481*0b57cec5SDimitry Andric } 482*0b57cec5SDimitry Andric 483*0b57cec5SDimitry Andric /* Return buffer length that is required to store the current profile 484*0b57cec5SDimitry Andric * filename with PID and hostname substitutions. */ 485*0b57cec5SDimitry Andric /* The length to hold uint64_t followed by 2 digit pool id including '_' */ 486*0b57cec5SDimitry Andric #define SIGLEN 24 487*0b57cec5SDimitry Andric static int getCurFilenameLength() { 488*0b57cec5SDimitry Andric int Len; 489*0b57cec5SDimitry Andric if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 490*0b57cec5SDimitry Andric return 0; 491*0b57cec5SDimitry Andric 492*0b57cec5SDimitry Andric if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 493*0b57cec5SDimitry Andric lprofCurFilename.MergePoolSize)) 494*0b57cec5SDimitry Andric return strlen(lprofCurFilename.FilenamePat); 495*0b57cec5SDimitry Andric 496*0b57cec5SDimitry Andric Len = strlen(lprofCurFilename.FilenamePat) + 497*0b57cec5SDimitry Andric lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + 498*0b57cec5SDimitry Andric lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2); 499*0b57cec5SDimitry Andric if (lprofCurFilename.MergePoolSize) 500*0b57cec5SDimitry Andric Len += SIGLEN; 501*0b57cec5SDimitry Andric return Len; 502*0b57cec5SDimitry Andric } 503*0b57cec5SDimitry Andric 504*0b57cec5SDimitry Andric /* Return the pointer to the current profile file name (after substituting 505*0b57cec5SDimitry Andric * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer 506*0b57cec5SDimitry Andric * to store the resulting filename. If no substitution is needed, the 507*0b57cec5SDimitry Andric * current filename pattern string is directly returned, unless ForceUseBuf 508*0b57cec5SDimitry Andric * is enabled. */ 509*0b57cec5SDimitry Andric static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) { 510*0b57cec5SDimitry Andric int I, J, PidLength, HostNameLength, FilenamePatLength; 511*0b57cec5SDimitry Andric const char *FilenamePat = lprofCurFilename.FilenamePat; 512*0b57cec5SDimitry Andric 513*0b57cec5SDimitry Andric if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 514*0b57cec5SDimitry Andric return 0; 515*0b57cec5SDimitry Andric 516*0b57cec5SDimitry Andric if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 517*0b57cec5SDimitry Andric lprofCurFilename.MergePoolSize)) { 518*0b57cec5SDimitry Andric if (!ForceUseBuf) 519*0b57cec5SDimitry Andric return lprofCurFilename.FilenamePat; 520*0b57cec5SDimitry Andric 521*0b57cec5SDimitry Andric FilenamePatLength = strlen(lprofCurFilename.FilenamePat); 522*0b57cec5SDimitry Andric memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength); 523*0b57cec5SDimitry Andric FilenameBuf[FilenamePatLength] = '\0'; 524*0b57cec5SDimitry Andric return FilenameBuf; 525*0b57cec5SDimitry Andric } 526*0b57cec5SDimitry Andric 527*0b57cec5SDimitry Andric PidLength = strlen(lprofCurFilename.PidChars); 528*0b57cec5SDimitry Andric HostNameLength = strlen(lprofCurFilename.Hostname); 529*0b57cec5SDimitry Andric /* Construct the new filename. */ 530*0b57cec5SDimitry Andric for (I = 0, J = 0; FilenamePat[I]; ++I) 531*0b57cec5SDimitry Andric if (FilenamePat[I] == '%') { 532*0b57cec5SDimitry Andric if (FilenamePat[++I] == 'p') { 533*0b57cec5SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); 534*0b57cec5SDimitry Andric J += PidLength; 535*0b57cec5SDimitry Andric } else if (FilenamePat[I] == 'h') { 536*0b57cec5SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); 537*0b57cec5SDimitry Andric J += HostNameLength; 538*0b57cec5SDimitry Andric } else if (containsMergeSpecifier(FilenamePat, I)) { 539*0b57cec5SDimitry Andric char LoadModuleSignature[SIGLEN]; 540*0b57cec5SDimitry Andric int S; 541*0b57cec5SDimitry Andric int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; 542*0b57cec5SDimitry Andric S = snprintf(LoadModuleSignature, SIGLEN, "%" PRIu64 "_%d", 543*0b57cec5SDimitry Andric lprofGetLoadModuleSignature(), ProfilePoolId); 544*0b57cec5SDimitry Andric if (S == -1 || S > SIGLEN) 545*0b57cec5SDimitry Andric S = SIGLEN; 546*0b57cec5SDimitry Andric memcpy(FilenameBuf + J, LoadModuleSignature, S); 547*0b57cec5SDimitry Andric J += S; 548*0b57cec5SDimitry Andric if (FilenamePat[I] != 'm') 549*0b57cec5SDimitry Andric I++; 550*0b57cec5SDimitry Andric } 551*0b57cec5SDimitry Andric /* Drop any unknown substitutions. */ 552*0b57cec5SDimitry Andric } else 553*0b57cec5SDimitry Andric FilenameBuf[J++] = FilenamePat[I]; 554*0b57cec5SDimitry Andric FilenameBuf[J] = 0; 555*0b57cec5SDimitry Andric 556*0b57cec5SDimitry Andric return FilenameBuf; 557*0b57cec5SDimitry Andric } 558*0b57cec5SDimitry Andric 559*0b57cec5SDimitry Andric /* Returns the pointer to the environment variable 560*0b57cec5SDimitry Andric * string. Returns null if the env var is not set. */ 561*0b57cec5SDimitry Andric static const char *getFilenamePatFromEnv(void) { 562*0b57cec5SDimitry Andric const char *Filename = getenv("LLVM_PROFILE_FILE"); 563*0b57cec5SDimitry Andric if (!Filename || !Filename[0]) 564*0b57cec5SDimitry Andric return 0; 565*0b57cec5SDimitry Andric return Filename; 566*0b57cec5SDimitry Andric } 567*0b57cec5SDimitry Andric 568*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 569*0b57cec5SDimitry Andric const char *__llvm_profile_get_path_prefix(void) { 570*0b57cec5SDimitry Andric int Length; 571*0b57cec5SDimitry Andric char *FilenameBuf, *Prefix; 572*0b57cec5SDimitry Andric const char *Filename, *PrefixEnd; 573*0b57cec5SDimitry Andric 574*0b57cec5SDimitry Andric if (lprofCurFilename.ProfilePathPrefix) 575*0b57cec5SDimitry Andric return lprofCurFilename.ProfilePathPrefix; 576*0b57cec5SDimitry Andric 577*0b57cec5SDimitry Andric Length = getCurFilenameLength(); 578*0b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 579*0b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 580*0b57cec5SDimitry Andric if (!Filename) 581*0b57cec5SDimitry Andric return "\0"; 582*0b57cec5SDimitry Andric 583*0b57cec5SDimitry Andric PrefixEnd = lprofFindLastDirSeparator(Filename); 584*0b57cec5SDimitry Andric if (!PrefixEnd) 585*0b57cec5SDimitry Andric return "\0"; 586*0b57cec5SDimitry Andric 587*0b57cec5SDimitry Andric Length = PrefixEnd - Filename + 1; 588*0b57cec5SDimitry Andric Prefix = (char *)malloc(Length + 1); 589*0b57cec5SDimitry Andric if (!Prefix) { 590*0b57cec5SDimitry Andric PROF_ERR("Failed to %s\n", "allocate memory."); 591*0b57cec5SDimitry Andric return "\0"; 592*0b57cec5SDimitry Andric } 593*0b57cec5SDimitry Andric memcpy(Prefix, Filename, Length); 594*0b57cec5SDimitry Andric Prefix[Length] = '\0'; 595*0b57cec5SDimitry Andric lprofCurFilename.ProfilePathPrefix = Prefix; 596*0b57cec5SDimitry Andric return Prefix; 597*0b57cec5SDimitry Andric } 598*0b57cec5SDimitry Andric 599*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 600*0b57cec5SDimitry Andric const char *__llvm_profile_get_filename(void) { 601*0b57cec5SDimitry Andric int Length; 602*0b57cec5SDimitry Andric char *FilenameBuf; 603*0b57cec5SDimitry Andric const char *Filename; 604*0b57cec5SDimitry Andric 605*0b57cec5SDimitry Andric if (lprofCurFilename.Filename) 606*0b57cec5SDimitry Andric return lprofCurFilename.Filename; 607*0b57cec5SDimitry Andric 608*0b57cec5SDimitry Andric Length = getCurFilenameLength(); 609*0b57cec5SDimitry Andric FilenameBuf = (char *)malloc(Length + 1); 610*0b57cec5SDimitry Andric if (!FilenameBuf) { 611*0b57cec5SDimitry Andric PROF_ERR("Failed to %s\n", "allocate memory."); 612*0b57cec5SDimitry Andric return "\0"; 613*0b57cec5SDimitry Andric } 614*0b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 1); 615*0b57cec5SDimitry Andric if (!Filename) 616*0b57cec5SDimitry Andric return "\0"; 617*0b57cec5SDimitry Andric 618*0b57cec5SDimitry Andric lprofCurFilename.Filename = FilenameBuf; 619*0b57cec5SDimitry Andric return FilenameBuf; 620*0b57cec5SDimitry Andric } 621*0b57cec5SDimitry Andric 622*0b57cec5SDimitry Andric /* This method is invoked by the runtime initialization hook 623*0b57cec5SDimitry Andric * InstrProfilingRuntime.o if it is linked in. Both user specified 624*0b57cec5SDimitry Andric * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 625*0b57cec5SDimitry Andric * environment variable can override this default value. */ 626*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 627*0b57cec5SDimitry Andric void __llvm_profile_initialize_file(void) { 628*0b57cec5SDimitry Andric const char *EnvFilenamePat; 629*0b57cec5SDimitry Andric const char *SelectedPat = NULL; 630*0b57cec5SDimitry Andric ProfileNameSpecifier PNS = PNS_unknown; 631*0b57cec5SDimitry Andric int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); 632*0b57cec5SDimitry Andric 633*0b57cec5SDimitry Andric EnvFilenamePat = getFilenamePatFromEnv(); 634*0b57cec5SDimitry Andric if (EnvFilenamePat) { 635*0b57cec5SDimitry Andric /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid 636*0b57cec5SDimitry Andric at the moment when __llvm_profile_write_file() gets executed. */ 637*0b57cec5SDimitry Andric parseAndSetFilename(EnvFilenamePat, PNS_environment, 1); 638*0b57cec5SDimitry Andric return; 639*0b57cec5SDimitry Andric } else if (hasCommandLineOverrider) { 640*0b57cec5SDimitry Andric SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; 641*0b57cec5SDimitry Andric PNS = PNS_command_line; 642*0b57cec5SDimitry Andric } else { 643*0b57cec5SDimitry Andric SelectedPat = NULL; 644*0b57cec5SDimitry Andric PNS = PNS_default; 645*0b57cec5SDimitry Andric } 646*0b57cec5SDimitry Andric 647*0b57cec5SDimitry Andric parseAndSetFilename(SelectedPat, PNS, 0); 648*0b57cec5SDimitry Andric } 649*0b57cec5SDimitry Andric 650*0b57cec5SDimitry Andric /* This API is directly called by the user application code. It has the 651*0b57cec5SDimitry Andric * highest precedence compared with LLVM_PROFILE_FILE environment variable 652*0b57cec5SDimitry Andric * and command line option -fprofile-instr-generate=<profile_name>. 653*0b57cec5SDimitry Andric */ 654*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 655*0b57cec5SDimitry Andric void __llvm_profile_set_filename(const char *FilenamePat) { 656*0b57cec5SDimitry Andric parseAndSetFilename(FilenamePat, PNS_runtime_api, 1); 657*0b57cec5SDimitry Andric } 658*0b57cec5SDimitry Andric 659*0b57cec5SDimitry Andric /* The public API for writing profile data into the file with name 660*0b57cec5SDimitry Andric * set by previous calls to __llvm_profile_set_filename or 661*0b57cec5SDimitry Andric * __llvm_profile_override_default_filename or 662*0b57cec5SDimitry Andric * __llvm_profile_initialize_file. */ 663*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 664*0b57cec5SDimitry Andric int __llvm_profile_write_file(void) { 665*0b57cec5SDimitry Andric int rc, Length; 666*0b57cec5SDimitry Andric const char *Filename; 667*0b57cec5SDimitry Andric char *FilenameBuf; 668*0b57cec5SDimitry Andric int PDeathSig = 0; 669*0b57cec5SDimitry Andric 670*0b57cec5SDimitry Andric if (lprofProfileDumped()) { 671*0b57cec5SDimitry Andric PROF_NOTE("Profile data not written to file: %s.\n", "already written"); 672*0b57cec5SDimitry Andric return 0; 673*0b57cec5SDimitry Andric } 674*0b57cec5SDimitry Andric 675*0b57cec5SDimitry Andric Length = getCurFilenameLength(); 676*0b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 677*0b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 678*0b57cec5SDimitry Andric 679*0b57cec5SDimitry Andric /* Check the filename. */ 680*0b57cec5SDimitry Andric if (!Filename) { 681*0b57cec5SDimitry Andric PROF_ERR("Failed to write file : %s\n", "Filename not set"); 682*0b57cec5SDimitry Andric return -1; 683*0b57cec5SDimitry Andric } 684*0b57cec5SDimitry Andric 685*0b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 686*0b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 687*0b57cec5SDimitry Andric PROF_ERR("Runtime and instrumentation version mismatch : " 688*0b57cec5SDimitry Andric "expected %d, but get %d\n", 689*0b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 690*0b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 691*0b57cec5SDimitry Andric return -1; 692*0b57cec5SDimitry Andric } 693*0b57cec5SDimitry Andric 694*0b57cec5SDimitry Andric // Temporarily suspend getting SIGKILL when the parent exits. 695*0b57cec5SDimitry Andric PDeathSig = lprofSuspendSigKill(); 696*0b57cec5SDimitry Andric 697*0b57cec5SDimitry Andric /* Write profile data to the file. */ 698*0b57cec5SDimitry Andric rc = writeFile(Filename); 699*0b57cec5SDimitry Andric if (rc) 700*0b57cec5SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 701*0b57cec5SDimitry Andric 702*0b57cec5SDimitry Andric // Restore SIGKILL. 703*0b57cec5SDimitry Andric if (PDeathSig == 1) 704*0b57cec5SDimitry Andric lprofRestoreSigKill(); 705*0b57cec5SDimitry Andric 706*0b57cec5SDimitry Andric return rc; 707*0b57cec5SDimitry Andric } 708*0b57cec5SDimitry Andric 709*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 710*0b57cec5SDimitry Andric int __llvm_profile_dump(void) { 711*0b57cec5SDimitry Andric if (!doMerging()) 712*0b57cec5SDimitry Andric PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering " 713*0b57cec5SDimitry Andric " of previously dumped profile data : %s. Either use %%m " 714*0b57cec5SDimitry Andric "in profile name or change profile name before dumping.\n", 715*0b57cec5SDimitry Andric "online profile merging is not on"); 716*0b57cec5SDimitry Andric int rc = __llvm_profile_write_file(); 717*0b57cec5SDimitry Andric lprofSetProfileDumped(); 718*0b57cec5SDimitry Andric return rc; 719*0b57cec5SDimitry Andric } 720*0b57cec5SDimitry Andric 721*0b57cec5SDimitry Andric /* Order file data will be saved in a file with suffx .order. */ 722*0b57cec5SDimitry Andric static const char *OrderFileSuffix = ".order"; 723*0b57cec5SDimitry Andric 724*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 725*0b57cec5SDimitry Andric int __llvm_orderfile_write_file(void) { 726*0b57cec5SDimitry Andric int rc, Length, LengthBeforeAppend, SuffixLength; 727*0b57cec5SDimitry Andric const char *Filename; 728*0b57cec5SDimitry Andric char *FilenameBuf; 729*0b57cec5SDimitry Andric int PDeathSig = 0; 730*0b57cec5SDimitry Andric 731*0b57cec5SDimitry Andric SuffixLength = strlen(OrderFileSuffix); 732*0b57cec5SDimitry Andric Length = getCurFilenameLength() + SuffixLength; 733*0b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 734*0b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 1); 735*0b57cec5SDimitry Andric 736*0b57cec5SDimitry Andric /* Check the filename. */ 737*0b57cec5SDimitry Andric if (!Filename) { 738*0b57cec5SDimitry Andric PROF_ERR("Failed to write file : %s\n", "Filename not set"); 739*0b57cec5SDimitry Andric return -1; 740*0b57cec5SDimitry Andric } 741*0b57cec5SDimitry Andric 742*0b57cec5SDimitry Andric /* Append order file suffix */ 743*0b57cec5SDimitry Andric LengthBeforeAppend = strlen(Filename); 744*0b57cec5SDimitry Andric memcpy(FilenameBuf + LengthBeforeAppend, OrderFileSuffix, SuffixLength); 745*0b57cec5SDimitry Andric FilenameBuf[LengthBeforeAppend + SuffixLength] = '\0'; 746*0b57cec5SDimitry Andric 747*0b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 748*0b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 749*0b57cec5SDimitry Andric PROF_ERR("Runtime and instrumentation version mismatch : " 750*0b57cec5SDimitry Andric "expected %d, but get %d\n", 751*0b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 752*0b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 753*0b57cec5SDimitry Andric return -1; 754*0b57cec5SDimitry Andric } 755*0b57cec5SDimitry Andric 756*0b57cec5SDimitry Andric // Temporarily suspend getting SIGKILL when the parent exits. 757*0b57cec5SDimitry Andric PDeathSig = lprofSuspendSigKill(); 758*0b57cec5SDimitry Andric 759*0b57cec5SDimitry Andric /* Write order data to the file. */ 760*0b57cec5SDimitry Andric rc = writeOrderFile(Filename); 761*0b57cec5SDimitry Andric if (rc) 762*0b57cec5SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 763*0b57cec5SDimitry Andric 764*0b57cec5SDimitry Andric // Restore SIGKILL. 765*0b57cec5SDimitry Andric if (PDeathSig == 1) 766*0b57cec5SDimitry Andric lprofRestoreSigKill(); 767*0b57cec5SDimitry Andric 768*0b57cec5SDimitry Andric return rc; 769*0b57cec5SDimitry Andric } 770*0b57cec5SDimitry Andric 771*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 772*0b57cec5SDimitry Andric int __llvm_orderfile_dump(void) { 773*0b57cec5SDimitry Andric int rc = __llvm_orderfile_write_file(); 774*0b57cec5SDimitry Andric return rc; 775*0b57cec5SDimitry Andric } 776*0b57cec5SDimitry Andric 777*0b57cec5SDimitry Andric static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 778*0b57cec5SDimitry Andric 779*0b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 780*0b57cec5SDimitry Andric int __llvm_profile_register_write_file_atexit(void) { 781*0b57cec5SDimitry Andric static int HasBeenRegistered = 0; 782*0b57cec5SDimitry Andric 783*0b57cec5SDimitry Andric if (HasBeenRegistered) 784*0b57cec5SDimitry Andric return 0; 785*0b57cec5SDimitry Andric 786*0b57cec5SDimitry Andric lprofSetupValueProfiler(); 787*0b57cec5SDimitry Andric 788*0b57cec5SDimitry Andric HasBeenRegistered = 1; 789*0b57cec5SDimitry Andric return atexit(writeFileWithoutReturn); 790*0b57cec5SDimitry Andric } 791*0b57cec5SDimitry Andric 792*0b57cec5SDimitry Andric #endif 793