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 11fe6060f1SDimitry Andric #include <assert.h> 120b57cec5SDimitry Andric #include <errno.h> 130b57cec5SDimitry Andric #include <stdio.h> 140b57cec5SDimitry Andric #include <stdlib.h> 150b57cec5SDimitry Andric #include <string.h> 160b57cec5SDimitry Andric #ifdef _MSC_VER 170b57cec5SDimitry Andric /* For _alloca. */ 180b57cec5SDimitry Andric #include <malloc.h> 190b57cec5SDimitry Andric #endif 200b57cec5SDimitry Andric #if defined(_WIN32) 210b57cec5SDimitry Andric #include "WindowsMMap.h" 220b57cec5SDimitry Andric /* For _chsize_s */ 230b57cec5SDimitry Andric #include <io.h> 240b57cec5SDimitry Andric #include <process.h> 250b57cec5SDimitry Andric #else 260b57cec5SDimitry Andric #include <sys/file.h> 270b57cec5SDimitry Andric #include <sys/mman.h> 280b57cec5SDimitry Andric #include <unistd.h> 290b57cec5SDimitry Andric #if defined(__linux__) 300b57cec5SDimitry Andric #include <sys/types.h> 310b57cec5SDimitry Andric #endif 320b57cec5SDimitry Andric #endif 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric #include "InstrProfiling.h" 350b57cec5SDimitry Andric #include "InstrProfilingInternal.h" 36480093f4SDimitry Andric #include "InstrProfilingPort.h" 370b57cec5SDimitry Andric #include "InstrProfilingUtil.h" 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric /* From where is profile name specified. 400b57cec5SDimitry Andric * The order the enumerators define their 410b57cec5SDimitry Andric * precedence. Re-order them may lead to 420b57cec5SDimitry Andric * runtime behavior change. */ 430b57cec5SDimitry Andric typedef enum ProfileNameSpecifier { 440b57cec5SDimitry Andric PNS_unknown = 0, 450b57cec5SDimitry Andric PNS_default, 460b57cec5SDimitry Andric PNS_command_line, 470b57cec5SDimitry Andric PNS_environment, 480b57cec5SDimitry Andric PNS_runtime_api 490b57cec5SDimitry Andric } ProfileNameSpecifier; 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric static const char *getPNSStr(ProfileNameSpecifier PNS) { 520b57cec5SDimitry Andric switch (PNS) { 530b57cec5SDimitry Andric case PNS_default: 540b57cec5SDimitry Andric return "default setting"; 550b57cec5SDimitry Andric case PNS_command_line: 560b57cec5SDimitry Andric return "command line"; 570b57cec5SDimitry Andric case PNS_environment: 580b57cec5SDimitry Andric return "environment variable"; 590b57cec5SDimitry Andric case PNS_runtime_api: 600b57cec5SDimitry Andric return "runtime API"; 610b57cec5SDimitry Andric default: 620b57cec5SDimitry Andric return "Unknown"; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric #define MAX_PID_SIZE 16 670b57cec5SDimitry Andric /* Data structure holding the result of parsed filename pattern. */ 680b57cec5SDimitry Andric typedef struct lprofFilename { 690b57cec5SDimitry Andric /* File name string possibly with %p or %h specifiers. */ 700b57cec5SDimitry Andric const char *FilenamePat; 710b57cec5SDimitry Andric /* A flag indicating if FilenamePat's memory is allocated 720b57cec5SDimitry Andric * by runtime. */ 730b57cec5SDimitry Andric unsigned OwnsFilenamePat; 740b57cec5SDimitry Andric const char *ProfilePathPrefix; 750b57cec5SDimitry Andric char PidChars[MAX_PID_SIZE]; 76e8d8bef9SDimitry Andric char *TmpDir; 770b57cec5SDimitry Andric char Hostname[COMPILER_RT_MAX_HOSTLEN]; 780b57cec5SDimitry Andric unsigned NumPids; 790b57cec5SDimitry Andric unsigned NumHosts; 800b57cec5SDimitry Andric /* When in-process merging is enabled, this parameter specifies 810b57cec5SDimitry Andric * the total number of profile data files shared by all the processes 820b57cec5SDimitry Andric * spawned from the same binary. By default the value is 1. If merging 830b57cec5SDimitry Andric * is not enabled, its value should be 0. This parameter is specified 840b57cec5SDimitry Andric * by the %[0-9]m specifier. For instance %2m enables merging using 850b57cec5SDimitry Andric * 2 profile data files. %1m is equivalent to %m. Also %m specifier 860b57cec5SDimitry Andric * can only appear once at the end of the name pattern. */ 870b57cec5SDimitry Andric unsigned MergePoolSize; 880b57cec5SDimitry Andric ProfileNameSpecifier PNS; 890b57cec5SDimitry Andric } lprofFilename; 900b57cec5SDimitry Andric 91e8d8bef9SDimitry Andric static lprofFilename lprofCurFilename = {0, 0, 0, {0}, NULL, 92e8d8bef9SDimitry Andric {0}, 0, 0, 0, PNS_unknown}; 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric static int ProfileMergeRequested = 0; 95349cc55cSDimitry Andric static int getProfileFileSizeForMerging(FILE *ProfileFile, 96349cc55cSDimitry Andric uint64_t *ProfileFileSize); 97349cc55cSDimitry Andric 98349cc55cSDimitry Andric #if defined(__APPLE__) 99349cc55cSDimitry Andric static const int ContinuousModeSupported = 1; 100349cc55cSDimitry Andric static const int UseBiasVar = 0; 101349cc55cSDimitry Andric static const char *FileOpenMode = "a+b"; 102349cc55cSDimitry Andric static void *BiasAddr = NULL; 103349cc55cSDimitry Andric static void *BiasDefaultAddr = NULL; 104349cc55cSDimitry Andric static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { 105349cc55cSDimitry Andric /* Get the sizes of various profile data sections. Taken from 106349cc55cSDimitry Andric * __llvm_profile_get_size_for_buffer(). */ 107349cc55cSDimitry Andric const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); 108349cc55cSDimitry Andric const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); 10904eeddc0SDimitry Andric const char *CountersBegin = __llvm_profile_begin_counters(); 11004eeddc0SDimitry Andric const char *CountersEnd = __llvm_profile_end_counters(); 1115f757f3fSDimitry Andric const char *BitmapBegin = __llvm_profile_begin_bitmap(); 1125f757f3fSDimitry Andric const char *BitmapEnd = __llvm_profile_end_bitmap(); 113349cc55cSDimitry Andric const char *NamesBegin = __llvm_profile_begin_names(); 114349cc55cSDimitry Andric const char *NamesEnd = __llvm_profile_end_names(); 115349cc55cSDimitry Andric const uint64_t NamesSize = (NamesEnd - NamesBegin) * sizeof(char); 116349cc55cSDimitry Andric uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); 11704eeddc0SDimitry Andric uint64_t CountersSize = 11804eeddc0SDimitry Andric __llvm_profile_get_counters_size(CountersBegin, CountersEnd); 1195f757f3fSDimitry Andric uint64_t NumBitmapBytes = 1205f757f3fSDimitry Andric __llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd); 121349cc55cSDimitry Andric 1225f757f3fSDimitry Andric /* Check that the counter, bitmap, and data sections in this image are 123349cc55cSDimitry Andric * page-aligned. */ 124349cc55cSDimitry Andric unsigned PageSize = getpagesize(); 125349cc55cSDimitry Andric if ((intptr_t)CountersBegin % PageSize != 0) { 126349cc55cSDimitry Andric PROF_ERR("Counters section not page-aligned (start = %p, pagesz = %u).\n", 127349cc55cSDimitry Andric CountersBegin, PageSize); 128349cc55cSDimitry Andric return 1; 129349cc55cSDimitry Andric } 1305f757f3fSDimitry Andric if ((intptr_t)BitmapBegin % PageSize != 0) { 1315f757f3fSDimitry Andric PROF_ERR("Bitmap section not page-aligned (start = %p, pagesz = %u).\n", 1325f757f3fSDimitry Andric BitmapBegin, PageSize); 1335f757f3fSDimitry Andric return 1; 1345f757f3fSDimitry Andric } 135349cc55cSDimitry Andric if ((intptr_t)DataBegin % PageSize != 0) { 136349cc55cSDimitry Andric PROF_ERR("Data section not page-aligned (start = %p, pagesz = %u).\n", 137349cc55cSDimitry Andric DataBegin, PageSize); 138349cc55cSDimitry Andric return 1; 139349cc55cSDimitry Andric } 140*0fca6ea1SDimitry Andric 141349cc55cSDimitry Andric int Fileno = fileno(File); 142349cc55cSDimitry Andric /* Determine how much padding is needed before/after the counters and 143349cc55cSDimitry Andric * after the names. */ 144349cc55cSDimitry Andric uint64_t PaddingBytesBeforeCounters, PaddingBytesAfterCounters, 145*0fca6ea1SDimitry Andric PaddingBytesAfterNames, PaddingBytesAfterBitmapBytes, 146*0fca6ea1SDimitry Andric PaddingBytesAfterVTable, PaddingBytesAfterVNames; 147349cc55cSDimitry Andric __llvm_profile_get_padding_sizes_for_counters( 148*0fca6ea1SDimitry Andric DataSize, CountersSize, NumBitmapBytes, NamesSize, /*VTableSize=*/0, 149*0fca6ea1SDimitry Andric /*VNameSize=*/0, &PaddingBytesBeforeCounters, &PaddingBytesAfterCounters, 150*0fca6ea1SDimitry Andric &PaddingBytesAfterBitmapBytes, &PaddingBytesAfterNames, 151*0fca6ea1SDimitry Andric &PaddingBytesAfterVTable, &PaddingBytesAfterVNames); 152349cc55cSDimitry Andric 15304eeddc0SDimitry Andric uint64_t PageAlignedCountersLength = CountersSize + PaddingBytesAfterCounters; 15404eeddc0SDimitry Andric uint64_t FileOffsetToCounters = CurrentFileOffset + 15504eeddc0SDimitry Andric sizeof(__llvm_profile_header) + DataSize + 15604eeddc0SDimitry Andric PaddingBytesBeforeCounters; 15781ad6265SDimitry Andric void *CounterMmap = mmap((void *)CountersBegin, PageAlignedCountersLength, 15881ad6265SDimitry Andric PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, 15981ad6265SDimitry Andric Fileno, FileOffsetToCounters); 160349cc55cSDimitry Andric if (CounterMmap != CountersBegin) { 161349cc55cSDimitry Andric PROF_ERR( 162349cc55cSDimitry Andric "Continuous counter sync mode is enabled, but mmap() failed (%s).\n" 163349cc55cSDimitry Andric " - CountersBegin: %p\n" 164349cc55cSDimitry Andric " - PageAlignedCountersLength: %" PRIu64 "\n" 165349cc55cSDimitry Andric " - Fileno: %d\n" 166349cc55cSDimitry Andric " - FileOffsetToCounters: %" PRIu64 "\n", 167349cc55cSDimitry Andric strerror(errno), CountersBegin, PageAlignedCountersLength, Fileno, 168349cc55cSDimitry Andric FileOffsetToCounters); 169349cc55cSDimitry Andric return 1; 170349cc55cSDimitry Andric } 1715f757f3fSDimitry Andric 1725f757f3fSDimitry Andric /* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap() 1735f757f3fSDimitry Andric * will fail with EINVAL. */ 1745f757f3fSDimitry Andric if (NumBitmapBytes == 0) 1755f757f3fSDimitry Andric return 0; 1765f757f3fSDimitry Andric 1775f757f3fSDimitry Andric uint64_t PageAlignedBitmapLength = 1785f757f3fSDimitry Andric NumBitmapBytes + PaddingBytesAfterBitmapBytes; 1795f757f3fSDimitry Andric uint64_t FileOffsetToBitmap = 180*0fca6ea1SDimitry Andric FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters; 1815f757f3fSDimitry Andric void *BitmapMmap = 1825f757f3fSDimitry Andric mmap((void *)BitmapBegin, PageAlignedBitmapLength, PROT_READ | PROT_WRITE, 1835f757f3fSDimitry Andric MAP_FIXED | MAP_SHARED, Fileno, FileOffsetToBitmap); 1845f757f3fSDimitry Andric if (BitmapMmap != BitmapBegin) { 1855f757f3fSDimitry Andric PROF_ERR( 1865f757f3fSDimitry Andric "Continuous counter sync mode is enabled, but mmap() failed (%s).\n" 1875f757f3fSDimitry Andric " - BitmapBegin: %p\n" 1885f757f3fSDimitry Andric " - PageAlignedBitmapLength: %" PRIu64 "\n" 1895f757f3fSDimitry Andric " - Fileno: %d\n" 1905f757f3fSDimitry Andric " - FileOffsetToBitmap: %" PRIu64 "\n", 1915f757f3fSDimitry Andric strerror(errno), BitmapBegin, PageAlignedBitmapLength, Fileno, 1925f757f3fSDimitry Andric FileOffsetToBitmap); 1935f757f3fSDimitry Andric return 1; 1945f757f3fSDimitry Andric } 195349cc55cSDimitry Andric return 0; 196349cc55cSDimitry Andric } 197349cc55cSDimitry Andric #elif defined(__ELF__) || defined(_WIN32) 198349cc55cSDimitry Andric 199349cc55cSDimitry Andric #define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR \ 200349cc55cSDimitry Andric INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR, _default) 201bdd1243dSDimitry Andric COMPILER_RT_VISIBILITY intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR = 0; 202349cc55cSDimitry Andric 203349cc55cSDimitry Andric /* This variable is a weak external reference which could be used to detect 204349cc55cSDimitry Andric * whether or not the compiler defined this symbol. */ 205349cc55cSDimitry Andric #if defined(_MSC_VER) 206349cc55cSDimitry Andric COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR; 207349cc55cSDimitry Andric #if defined(_M_IX86) || defined(__i386__) 208349cc55cSDimitry Andric #define WIN_SYM_PREFIX "_" 209349cc55cSDimitry Andric #else 210349cc55cSDimitry Andric #define WIN_SYM_PREFIX 211349cc55cSDimitry Andric #endif 212349cc55cSDimitry Andric #pragma comment( \ 213349cc55cSDimitry Andric linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \ 214349cc55cSDimitry Andric INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \ 215349cc55cSDimitry Andric INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR)) 216349cc55cSDimitry Andric #else 217349cc55cSDimitry Andric COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR 218349cc55cSDimitry Andric __attribute__((weak, alias(INSTR_PROF_QUOTE( 219349cc55cSDimitry Andric INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR)))); 220349cc55cSDimitry Andric #endif 221349cc55cSDimitry Andric static const int ContinuousModeSupported = 1; 222349cc55cSDimitry Andric static const int UseBiasVar = 1; 223349cc55cSDimitry Andric /* TODO: If there are two DSOs, the second DSO initilization will truncate the 224349cc55cSDimitry Andric * first profile file. */ 225349cc55cSDimitry Andric static const char *FileOpenMode = "w+b"; 226349cc55cSDimitry Andric /* This symbol is defined by the compiler when runtime counter relocation is 227349cc55cSDimitry Andric * used and runtime provides a weak alias so we can check if it's defined. */ 228349cc55cSDimitry Andric static void *BiasAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_VAR; 229349cc55cSDimitry Andric static void *BiasDefaultAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR; 230349cc55cSDimitry Andric static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { 231349cc55cSDimitry Andric /* Get the sizes of various profile data sections. Taken from 232349cc55cSDimitry Andric * __llvm_profile_get_size_for_buffer(). */ 233349cc55cSDimitry Andric const __llvm_profile_data *DataBegin = __llvm_profile_begin_data(); 234349cc55cSDimitry Andric const __llvm_profile_data *DataEnd = __llvm_profile_end_data(); 23504eeddc0SDimitry Andric const char *CountersBegin = __llvm_profile_begin_counters(); 23604eeddc0SDimitry Andric const char *CountersEnd = __llvm_profile_end_counters(); 2375f757f3fSDimitry Andric const char *BitmapBegin = __llvm_profile_begin_bitmap(); 2385f757f3fSDimitry Andric const char *BitmapEnd = __llvm_profile_end_bitmap(); 239349cc55cSDimitry Andric uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); 240349cc55cSDimitry Andric /* Get the file size. */ 241349cc55cSDimitry Andric uint64_t FileSize = 0; 242349cc55cSDimitry Andric if (getProfileFileSizeForMerging(File, &FileSize)) 243349cc55cSDimitry Andric return 1; 244349cc55cSDimitry Andric 245*0fca6ea1SDimitry Andric int Fileno = fileno(File); 246*0fca6ea1SDimitry Andric uint64_t FileOffsetToCounters = 247*0fca6ea1SDimitry Andric sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) + DataSize; 248*0fca6ea1SDimitry Andric 249349cc55cSDimitry Andric /* Map the profile. */ 250349cc55cSDimitry Andric char *Profile = (char *)mmap(NULL, FileSize, PROT_READ | PROT_WRITE, 251*0fca6ea1SDimitry Andric MAP_SHARED, Fileno, 0); 252349cc55cSDimitry Andric if (Profile == MAP_FAILED) { 253349cc55cSDimitry Andric PROF_ERR("Unable to mmap profile: %s\n", strerror(errno)); 254349cc55cSDimitry Andric return 1; 255349cc55cSDimitry Andric } 256349cc55cSDimitry Andric /* Update the profile fields based on the current mapping. */ 257349cc55cSDimitry Andric INSTR_PROF_PROFILE_COUNTER_BIAS_VAR = 258*0fca6ea1SDimitry Andric (intptr_t)Profile - (uintptr_t)CountersBegin + FileOffsetToCounters; 259349cc55cSDimitry Andric 260349cc55cSDimitry Andric /* Return the memory allocated for counters to OS. */ 261349cc55cSDimitry Andric lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd); 2625f757f3fSDimitry Andric 2635f757f3fSDimitry Andric /* BIAS MODE not supported yet for Bitmap (MCDC). */ 2645f757f3fSDimitry Andric 2655f757f3fSDimitry Andric /* Return the memory allocated for counters to OS. */ 2665f757f3fSDimitry Andric lprofReleaseMemoryPagesToOS((uintptr_t)BitmapBegin, (uintptr_t)BitmapEnd); 267349cc55cSDimitry Andric return 0; 268349cc55cSDimitry Andric } 269349cc55cSDimitry Andric #else 270349cc55cSDimitry Andric static const int ContinuousModeSupported = 0; 271349cc55cSDimitry Andric static const int UseBiasVar = 0; 272349cc55cSDimitry Andric static const char *FileOpenMode = "a+b"; 273349cc55cSDimitry Andric static void *BiasAddr = NULL; 274349cc55cSDimitry Andric static void *BiasDefaultAddr = NULL; 275349cc55cSDimitry Andric static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { 276349cc55cSDimitry Andric return 0; 277349cc55cSDimitry Andric } 278349cc55cSDimitry Andric #endif 279349cc55cSDimitry Andric 28081ad6265SDimitry Andric static int isProfileMergeRequested(void) { return ProfileMergeRequested; } 2810b57cec5SDimitry Andric static void setProfileMergeRequested(int EnableMerge) { 2820b57cec5SDimitry Andric ProfileMergeRequested = EnableMerge; 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric static FILE *ProfileFile = NULL; 28681ad6265SDimitry Andric static FILE *getProfileFile(void) { return ProfileFile; } 2870b57cec5SDimitry Andric static void setProfileFile(FILE *File) { ProfileFile = File; } 2880b57cec5SDimitry Andric 28981ad6265SDimitry Andric static int getCurFilenameLength(void); 2900b57cec5SDimitry Andric static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf); 29181ad6265SDimitry Andric static unsigned doMerging(void) { 2920b57cec5SDimitry Andric return lprofCurFilename.MergePoolSize || isProfileMergeRequested(); 2930b57cec5SDimitry Andric } 2940b57cec5SDimitry Andric 2950b57cec5SDimitry Andric /* Return 1 if there is an error, otherwise return 0. */ 2960b57cec5SDimitry Andric static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs, 2970b57cec5SDimitry Andric uint32_t NumIOVecs) { 2980b57cec5SDimitry Andric uint32_t I; 2990b57cec5SDimitry Andric FILE *File = (FILE *)This->WriterCtx; 300480093f4SDimitry Andric char Zeroes[sizeof(uint64_t)] = {0}; 3010b57cec5SDimitry Andric for (I = 0; I < NumIOVecs; I++) { 3020b57cec5SDimitry Andric if (IOVecs[I].Data) { 3030b57cec5SDimitry Andric if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) != 3040b57cec5SDimitry Andric IOVecs[I].NumElm) 3050b57cec5SDimitry Andric return 1; 306480093f4SDimitry Andric } else if (IOVecs[I].UseZeroPadding) { 307480093f4SDimitry Andric size_t BytesToWrite = IOVecs[I].ElmSize * IOVecs[I].NumElm; 308480093f4SDimitry Andric while (BytesToWrite > 0) { 309480093f4SDimitry Andric size_t PartialWriteLen = 310480093f4SDimitry Andric (sizeof(uint64_t) > BytesToWrite) ? BytesToWrite : sizeof(uint64_t); 311480093f4SDimitry Andric if (fwrite(Zeroes, sizeof(uint8_t), PartialWriteLen, File) != 312480093f4SDimitry Andric PartialWriteLen) { 313480093f4SDimitry Andric return 1; 314480093f4SDimitry Andric } 315480093f4SDimitry Andric BytesToWrite -= PartialWriteLen; 316480093f4SDimitry Andric } 3170b57cec5SDimitry Andric } else { 3180b57cec5SDimitry Andric if (fseek(File, IOVecs[I].ElmSize * IOVecs[I].NumElm, SEEK_CUR) == -1) 3190b57cec5SDimitry Andric return 1; 3200b57cec5SDimitry Andric } 3210b57cec5SDimitry Andric } 3220b57cec5SDimitry Andric return 0; 3230b57cec5SDimitry Andric } 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric /* TODO: make buffer size controllable by an internal option, and compiler can pass the size 3260b57cec5SDimitry Andric to runtime via a variable. */ 3270b57cec5SDimitry Andric static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) { 3280b57cec5SDimitry Andric if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) != 3290b57cec5SDimitry Andric INSTR_ORDER_FILE_BUFFER_SIZE) 3300b57cec5SDimitry Andric return 1; 3310b57cec5SDimitry Andric return 0; 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric static void initFileWriter(ProfDataWriter *This, FILE *File) { 3350b57cec5SDimitry Andric This->Write = fileWriter; 3360b57cec5SDimitry Andric This->WriterCtx = File; 3370b57cec5SDimitry Andric } 3380b57cec5SDimitry Andric 3390b57cec5SDimitry Andric COMPILER_RT_VISIBILITY ProfBufferIO * 3400b57cec5SDimitry Andric lprofCreateBufferIOInternal(void *File, uint32_t BufferSz) { 3410b57cec5SDimitry Andric FreeHook = &free; 3427a6dacacSDimitry Andric DynamicBufferIOBuffer = (uint8_t *)calloc(1, BufferSz); 3430b57cec5SDimitry Andric VPBufferSize = BufferSz; 3440b57cec5SDimitry Andric ProfDataWriter *fileWriter = 3457a6dacacSDimitry Andric (ProfDataWriter *)calloc(1, sizeof(ProfDataWriter)); 3460b57cec5SDimitry Andric initFileWriter(fileWriter, File); 3470b57cec5SDimitry Andric ProfBufferIO *IO = lprofCreateBufferIO(fileWriter); 3480b57cec5SDimitry Andric IO->OwnFileWriter = 1; 3490b57cec5SDimitry Andric return IO; 3500b57cec5SDimitry Andric } 3510b57cec5SDimitry Andric 35281ad6265SDimitry Andric static void setupIOBuffer(void) { 3530b57cec5SDimitry Andric const char *BufferSzStr = 0; 3540b57cec5SDimitry Andric BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE"); 3550b57cec5SDimitry Andric if (BufferSzStr && BufferSzStr[0]) { 3560b57cec5SDimitry Andric VPBufferSize = atoi(BufferSzStr); 3570b57cec5SDimitry Andric DynamicBufferIOBuffer = (uint8_t *)calloc(VPBufferSize, 1); 3580b57cec5SDimitry Andric } 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric 361480093f4SDimitry Andric /* Get the size of the profile file. If there are any errors, print the 362480093f4SDimitry Andric * message under the assumption that the profile is being read for merging 363480093f4SDimitry Andric * purposes, and return -1. Otherwise return the file size in the inout param 364480093f4SDimitry Andric * \p ProfileFileSize. */ 365480093f4SDimitry Andric static int getProfileFileSizeForMerging(FILE *ProfileFile, 366480093f4SDimitry Andric uint64_t *ProfileFileSize) { 367480093f4SDimitry Andric if (fseek(ProfileFile, 0L, SEEK_END) == -1) { 368480093f4SDimitry Andric PROF_ERR("Unable to merge profile data, unable to get size: %s\n", 369480093f4SDimitry Andric strerror(errno)); 370480093f4SDimitry Andric return -1; 371480093f4SDimitry Andric } 372480093f4SDimitry Andric *ProfileFileSize = ftell(ProfileFile); 373480093f4SDimitry Andric 374480093f4SDimitry Andric /* Restore file offset. */ 375480093f4SDimitry Andric if (fseek(ProfileFile, 0L, SEEK_SET) == -1) { 376480093f4SDimitry Andric PROF_ERR("Unable to merge profile data, unable to rewind: %s\n", 377480093f4SDimitry Andric strerror(errno)); 378480093f4SDimitry Andric return -1; 379480093f4SDimitry Andric } 380480093f4SDimitry Andric 381480093f4SDimitry Andric if (*ProfileFileSize > 0 && 382480093f4SDimitry Andric *ProfileFileSize < sizeof(__llvm_profile_header)) { 383480093f4SDimitry Andric PROF_WARN("Unable to merge profile data: %s\n", 384480093f4SDimitry Andric "source profile file is too small."); 385480093f4SDimitry Andric return -1; 386480093f4SDimitry Andric } 387480093f4SDimitry Andric return 0; 388480093f4SDimitry Andric } 389480093f4SDimitry Andric 390480093f4SDimitry Andric /* mmap() \p ProfileFile for profile merging purposes, assuming that an 391480093f4SDimitry Andric * exclusive lock is held on the file and that \p ProfileFileSize is the 392480093f4SDimitry Andric * length of the file. Return the mmap'd buffer in the inout variable 393480093f4SDimitry Andric * \p ProfileBuffer. Returns -1 on failure. On success, the caller is 394480093f4SDimitry Andric * responsible for unmapping the mmap'd buffer in \p ProfileBuffer. */ 395480093f4SDimitry Andric static int mmapProfileForMerging(FILE *ProfileFile, uint64_t ProfileFileSize, 396480093f4SDimitry Andric char **ProfileBuffer) { 397480093f4SDimitry Andric *ProfileBuffer = mmap(NULL, ProfileFileSize, PROT_READ, MAP_SHARED | MAP_FILE, 398480093f4SDimitry Andric fileno(ProfileFile), 0); 399480093f4SDimitry Andric if (*ProfileBuffer == MAP_FAILED) { 400480093f4SDimitry Andric PROF_ERR("Unable to merge profile data, mmap failed: %s\n", 401480093f4SDimitry Andric strerror(errno)); 402480093f4SDimitry Andric return -1; 403480093f4SDimitry Andric } 404480093f4SDimitry Andric 405480093f4SDimitry Andric if (__llvm_profile_check_compatibility(*ProfileBuffer, ProfileFileSize)) { 406480093f4SDimitry Andric (void)munmap(*ProfileBuffer, ProfileFileSize); 407480093f4SDimitry Andric PROF_WARN("Unable to merge profile data: %s\n", 408480093f4SDimitry Andric "source profile file is not compatible."); 409480093f4SDimitry Andric return -1; 410480093f4SDimitry Andric } 411480093f4SDimitry Andric return 0; 412480093f4SDimitry Andric } 413480093f4SDimitry Andric 4140b57cec5SDimitry Andric /* Read profile data in \c ProfileFile and merge with in-memory 4150b57cec5SDimitry Andric profile counters. Returns -1 if there is fatal error, otheriwse 4160b57cec5SDimitry Andric 0 is returned. Returning 0 does not mean merge is actually 4170b57cec5SDimitry Andric performed. If merge is actually done, *MergeDone is set to 1. 4180b57cec5SDimitry Andric */ 4190b57cec5SDimitry Andric static int doProfileMerging(FILE *ProfileFile, int *MergeDone) { 4200b57cec5SDimitry Andric uint64_t ProfileFileSize; 4210b57cec5SDimitry Andric char *ProfileBuffer; 4220b57cec5SDimitry Andric 423480093f4SDimitry Andric /* Get the size of the profile on disk. */ 424480093f4SDimitry Andric if (getProfileFileSizeForMerging(ProfileFile, &ProfileFileSize) == -1) 4250b57cec5SDimitry Andric return -1; 4260b57cec5SDimitry Andric 4270b57cec5SDimitry Andric /* Nothing to merge. */ 428480093f4SDimitry Andric if (!ProfileFileSize) 4290b57cec5SDimitry Andric return 0; 4300b57cec5SDimitry Andric 431480093f4SDimitry Andric /* mmap() the profile and check that it is compatible with the data in 432480093f4SDimitry Andric * the current image. */ 433480093f4SDimitry Andric if (mmapProfileForMerging(ProfileFile, ProfileFileSize, &ProfileBuffer) == -1) 4340b57cec5SDimitry Andric return -1; 4350b57cec5SDimitry Andric 4360b57cec5SDimitry Andric /* Now start merging */ 437fe6060f1SDimitry Andric if (__llvm_profile_merge_from_buffer(ProfileBuffer, ProfileFileSize)) { 438fe6060f1SDimitry Andric PROF_ERR("%s\n", "Invalid profile data to merge"); 439fe6060f1SDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 440fe6060f1SDimitry Andric return -1; 441fe6060f1SDimitry Andric } 4420b57cec5SDimitry Andric 443fe6060f1SDimitry Andric // Truncate the file in case merging of value profile did not happen to 4440b57cec5SDimitry Andric // prevent from leaving garbage data at the end of the profile file. 445fe6060f1SDimitry Andric (void)COMPILER_RT_FTRUNCATE(ProfileFile, 446fe6060f1SDimitry Andric __llvm_profile_get_size_for_buffer()); 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 4490b57cec5SDimitry Andric *MergeDone = 1; 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric return 0; 4520b57cec5SDimitry Andric } 4530b57cec5SDimitry Andric 4540b57cec5SDimitry Andric /* Create the directory holding the file, if needed. */ 4550b57cec5SDimitry Andric static void createProfileDir(const char *Filename) { 4560b57cec5SDimitry Andric size_t Length = strlen(Filename); 4570b57cec5SDimitry Andric if (lprofFindFirstDirSeparator(Filename)) { 4580b57cec5SDimitry Andric char *Copy = (char *)COMPILER_RT_ALLOCA(Length + 1); 4590b57cec5SDimitry Andric strncpy(Copy, Filename, Length + 1); 4600b57cec5SDimitry Andric __llvm_profile_recursive_mkdir(Copy); 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric /* Open the profile data for merging. It opens the file in r+b mode with 4650b57cec5SDimitry Andric * file locking. If the file has content which is compatible with the 4660b57cec5SDimitry Andric * current process, it also reads in the profile data in the file and merge 4670b57cec5SDimitry Andric * it with in-memory counters. After the profile data is merged in memory, 4680b57cec5SDimitry Andric * the original profile data is truncated and gets ready for the profile 4690b57cec5SDimitry Andric * dumper. With profile merging enabled, each executable as well as any of 4700b57cec5SDimitry Andric * its instrumented shared libraries dump profile data into their own data file. 4710b57cec5SDimitry Andric */ 4720b57cec5SDimitry Andric static FILE *openFileForMerging(const char *ProfileFileName, int *MergeDone) { 4735f757f3fSDimitry Andric FILE *ProfileFile = getProfileFile(); 4740b57cec5SDimitry Andric int rc; 4755f757f3fSDimitry Andric // initializeProfileForContinuousMode will lock the profile, but if 4765f757f3fSDimitry Andric // ProfileFile is set by user via __llvm_profile_set_file_object, it's assumed 4775f757f3fSDimitry Andric // unlocked at this point. 4785f757f3fSDimitry Andric if (ProfileFile && !__llvm_profile_is_continuous_mode_enabled()) { 4798a4dda33SDimitry Andric lprofLockFileHandle(ProfileFile); 4805f757f3fSDimitry Andric } 4815f757f3fSDimitry Andric if (!ProfileFile) { 4820b57cec5SDimitry Andric createProfileDir(ProfileFileName); 4830b57cec5SDimitry Andric ProfileFile = lprofOpenFileEx(ProfileFileName); 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric if (!ProfileFile) 4860b57cec5SDimitry Andric return NULL; 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric rc = doProfileMerging(ProfileFile, MergeDone); 4890b57cec5SDimitry Andric if (rc || (!*MergeDone && COMPILER_RT_FTRUNCATE(ProfileFile, 0L)) || 4900b57cec5SDimitry Andric fseek(ProfileFile, 0L, SEEK_SET) == -1) { 4910b57cec5SDimitry Andric PROF_ERR("Profile Merging of file %s failed: %s\n", ProfileFileName, 4920b57cec5SDimitry Andric strerror(errno)); 4930b57cec5SDimitry Andric fclose(ProfileFile); 4940b57cec5SDimitry Andric return NULL; 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric return ProfileFile; 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric 4990b57cec5SDimitry Andric static FILE *getFileObject(const char *OutputName) { 5000b57cec5SDimitry Andric FILE *File; 5010b57cec5SDimitry Andric File = getProfileFile(); 5020b57cec5SDimitry Andric if (File != NULL) { 5030b57cec5SDimitry Andric return File; 5040b57cec5SDimitry Andric } 5050b57cec5SDimitry Andric 5060b57cec5SDimitry Andric return fopen(OutputName, "ab"); 5070b57cec5SDimitry Andric } 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric /* Write profile data to file \c OutputName. */ 5100b57cec5SDimitry Andric static int writeFile(const char *OutputName) { 5110b57cec5SDimitry Andric int RetVal; 5120b57cec5SDimitry Andric FILE *OutputFile; 5130b57cec5SDimitry Andric 5140b57cec5SDimitry Andric int MergeDone = 0; 5150b57cec5SDimitry Andric VPMergeHook = &lprofMergeValueProfData; 5160b57cec5SDimitry Andric if (doMerging()) 5170b57cec5SDimitry Andric OutputFile = openFileForMerging(OutputName, &MergeDone); 5180b57cec5SDimitry Andric else 5190b57cec5SDimitry Andric OutputFile = getFileObject(OutputName); 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric if (!OutputFile) 5220b57cec5SDimitry Andric return -1; 5230b57cec5SDimitry Andric 5240b57cec5SDimitry Andric FreeHook = &free; 5250b57cec5SDimitry Andric setupIOBuffer(); 5260b57cec5SDimitry Andric ProfDataWriter fileWriter; 5270b57cec5SDimitry Andric initFileWriter(&fileWriter, OutputFile); 5280b57cec5SDimitry Andric RetVal = lprofWriteData(&fileWriter, lprofGetVPDataReader(), MergeDone); 5290b57cec5SDimitry Andric 5300b57cec5SDimitry Andric if (OutputFile == getProfileFile()) { 5310b57cec5SDimitry Andric fflush(OutputFile); 5325f757f3fSDimitry Andric if (doMerging() && !__llvm_profile_is_continuous_mode_enabled()) { 5338a4dda33SDimitry Andric lprofUnlockFileHandle(OutputFile); 5348a4dda33SDimitry Andric } 5350b57cec5SDimitry Andric } else { 5360b57cec5SDimitry Andric fclose(OutputFile); 5370b57cec5SDimitry Andric } 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric return RetVal; 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric /* Write order data to file \c OutputName. */ 5430b57cec5SDimitry Andric static int writeOrderFile(const char *OutputName) { 5440b57cec5SDimitry Andric int RetVal; 5450b57cec5SDimitry Andric FILE *OutputFile; 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric OutputFile = fopen(OutputName, "w"); 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric if (!OutputFile) { 5500b57cec5SDimitry Andric PROF_WARN("can't open file with mode ab: %s\n", OutputName); 5510b57cec5SDimitry Andric return -1; 5520b57cec5SDimitry Andric } 5530b57cec5SDimitry Andric 5540b57cec5SDimitry Andric FreeHook = &free; 5550b57cec5SDimitry Andric setupIOBuffer(); 5560b57cec5SDimitry Andric const uint32_t *DataBegin = __llvm_profile_begin_orderfile(); 5570b57cec5SDimitry Andric RetVal = orderFileWriter(OutputFile, DataBegin); 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric fclose(OutputFile); 5600b57cec5SDimitry Andric return RetVal; 5610b57cec5SDimitry Andric } 5620b57cec5SDimitry Andric 563480093f4SDimitry Andric #define LPROF_INIT_ONCE_ENV "__LLVM_PROFILE_RT_INIT_ONCE" 564480093f4SDimitry Andric 5650b57cec5SDimitry Andric static void truncateCurrentFile(void) { 5660b57cec5SDimitry Andric const char *Filename; 5670b57cec5SDimitry Andric char *FilenameBuf; 5680b57cec5SDimitry Andric FILE *File; 5690b57cec5SDimitry Andric int Length; 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric Length = getCurFilenameLength(); 5720b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 5730b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 5740b57cec5SDimitry Andric if (!Filename) 5750b57cec5SDimitry Andric return; 5760b57cec5SDimitry Andric 577480093f4SDimitry Andric /* Only create the profile directory and truncate an existing profile once. 578480093f4SDimitry Andric * In continuous mode, this is necessary, as the profile is written-to by the 579480093f4SDimitry Andric * runtime initializer. */ 580480093f4SDimitry Andric int initialized = getenv(LPROF_INIT_ONCE_ENV) != NULL; 581480093f4SDimitry Andric if (initialized) 582480093f4SDimitry Andric return; 583480093f4SDimitry Andric #if defined(_WIN32) 584480093f4SDimitry Andric _putenv(LPROF_INIT_ONCE_ENV "=" LPROF_INIT_ONCE_ENV); 585480093f4SDimitry Andric #else 586480093f4SDimitry Andric setenv(LPROF_INIT_ONCE_ENV, LPROF_INIT_ONCE_ENV, 1); 587480093f4SDimitry Andric #endif 588480093f4SDimitry Andric 589480093f4SDimitry Andric /* Create the profile dir (even if online merging is enabled), so that 590480093f4SDimitry Andric * the profile file can be set up if continuous mode is enabled. */ 591480093f4SDimitry Andric createProfileDir(Filename); 592480093f4SDimitry Andric 593480093f4SDimitry Andric /* By pass file truncation to allow online raw profile merging. */ 5940b57cec5SDimitry Andric if (lprofCurFilename.MergePoolSize) 5950b57cec5SDimitry Andric return; 5960b57cec5SDimitry Andric 5970b57cec5SDimitry Andric /* Truncate the file. Later we'll reopen and append. */ 5980b57cec5SDimitry Andric File = fopen(Filename, "w"); 5990b57cec5SDimitry Andric if (!File) 6000b57cec5SDimitry Andric return; 6010b57cec5SDimitry Andric fclose(File); 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric 604480093f4SDimitry Andric /* Write a partial profile to \p Filename, which is required to be backed by 605480093f4SDimitry Andric * the open file object \p File. */ 606480093f4SDimitry Andric static int writeProfileWithFileObject(const char *Filename, FILE *File) { 607480093f4SDimitry Andric setProfileFile(File); 608480093f4SDimitry Andric int rc = writeFile(Filename); 609480093f4SDimitry Andric if (rc) 610480093f4SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 611480093f4SDimitry Andric setProfileFile(NULL); 612480093f4SDimitry Andric return rc; 613480093f4SDimitry Andric } 614480093f4SDimitry Andric 615480093f4SDimitry Andric static void initializeProfileForContinuousMode(void) { 616480093f4SDimitry Andric if (!__llvm_profile_is_continuous_mode_enabled()) 617480093f4SDimitry Andric return; 618349cc55cSDimitry Andric if (!ContinuousModeSupported) { 619349cc55cSDimitry Andric PROF_ERR("%s\n", "continuous mode is unsupported on this platform"); 620480093f4SDimitry Andric return; 621480093f4SDimitry Andric } 622349cc55cSDimitry Andric if (UseBiasVar && BiasAddr == BiasDefaultAddr) { 623fe6060f1SDimitry Andric PROF_ERR("%s\n", "__llvm_profile_counter_bias is undefined"); 624fe6060f1SDimitry Andric return; 625fe6060f1SDimitry Andric } 626fe6060f1SDimitry Andric 627349cc55cSDimitry Andric /* Get the sizes of counter section. */ 62804eeddc0SDimitry Andric uint64_t CountersSize = __llvm_profile_get_counters_size( 62904eeddc0SDimitry Andric __llvm_profile_begin_counters(), __llvm_profile_end_counters()); 630fe6060f1SDimitry Andric 631fe6060f1SDimitry Andric int Length = getCurFilenameLength(); 632fe6060f1SDimitry Andric char *FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 633fe6060f1SDimitry Andric const char *Filename = getCurFilename(FilenameBuf, 0); 634fe6060f1SDimitry Andric if (!Filename) 635fe6060f1SDimitry Andric return; 636fe6060f1SDimitry Andric 637fe6060f1SDimitry Andric FILE *File = NULL; 638349cc55cSDimitry Andric uint64_t CurrentFileOffset = 0; 639349cc55cSDimitry Andric if (doMerging()) { 640349cc55cSDimitry Andric /* We are merging profiles. Map the counter section as shared memory into 641349cc55cSDimitry Andric * the profile, i.e. into each participating process. An increment in one 642349cc55cSDimitry Andric * process should be visible to every other process with the same counter 643349cc55cSDimitry Andric * section mapped. */ 644fe6060f1SDimitry Andric File = lprofOpenFileEx(Filename); 645fe6060f1SDimitry Andric if (!File) 646fe6060f1SDimitry Andric return; 647fe6060f1SDimitry Andric 648fe6060f1SDimitry Andric uint64_t ProfileFileSize = 0; 649fe6060f1SDimitry Andric if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) { 650fe6060f1SDimitry Andric lprofUnlockFileHandle(File); 651fe6060f1SDimitry Andric fclose(File); 652fe6060f1SDimitry Andric return; 653fe6060f1SDimitry Andric } 654349cc55cSDimitry Andric if (ProfileFileSize == 0) { 655349cc55cSDimitry Andric /* Grow the profile so that mmap() can succeed. Leak the file handle, as 656349cc55cSDimitry Andric * the file should stay open. */ 657349cc55cSDimitry Andric if (writeProfileWithFileObject(Filename, File) != 0) { 658349cc55cSDimitry Andric lprofUnlockFileHandle(File); 659fe6060f1SDimitry Andric fclose(File); 660fe6060f1SDimitry Andric return; 661fe6060f1SDimitry Andric } 662fe6060f1SDimitry Andric } else { 663fe6060f1SDimitry Andric /* The merged profile has a non-zero length. Check that it is compatible 664fe6060f1SDimitry Andric * with the data in this process. */ 665349cc55cSDimitry Andric char *ProfileBuffer; 666349cc55cSDimitry Andric if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) { 667349cc55cSDimitry Andric lprofUnlockFileHandle(File); 668349cc55cSDimitry Andric fclose(File); 669349cc55cSDimitry Andric return; 670349cc55cSDimitry Andric } 671349cc55cSDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 672349cc55cSDimitry Andric } 673349cc55cSDimitry Andric } else { 674349cc55cSDimitry Andric File = fopen(Filename, FileOpenMode); 675349cc55cSDimitry Andric if (!File) 676349cc55cSDimitry Andric return; 677349cc55cSDimitry Andric /* Check that the offset within the file is page-aligned. */ 678349cc55cSDimitry Andric CurrentFileOffset = ftell(File); 679349cc55cSDimitry Andric unsigned PageSize = getpagesize(); 680349cc55cSDimitry Andric if (CurrentFileOffset % PageSize != 0) { 681349cc55cSDimitry Andric PROF_ERR("Continuous counter sync mode is enabled, but raw profile is not" 682349cc55cSDimitry Andric "page-aligned. CurrentFileOffset = %" PRIu64 ", pagesz = %u.\n", 683349cc55cSDimitry Andric (uint64_t)CurrentFileOffset, PageSize); 68456727255SDimitry Andric fclose(File); 685349cc55cSDimitry Andric return; 686349cc55cSDimitry Andric } 687349cc55cSDimitry Andric if (writeProfileWithFileObject(Filename, File) != 0) { 688fe6060f1SDimitry Andric fclose(File); 689fe6060f1SDimitry Andric return; 690fe6060f1SDimitry Andric } 691fe6060f1SDimitry Andric } 692fe6060f1SDimitry Andric 693349cc55cSDimitry Andric /* mmap() the profile counters so long as there is at least one counter. 694349cc55cSDimitry Andric * If there aren't any counters, mmap() would fail with EINVAL. */ 695349cc55cSDimitry Andric if (CountersSize > 0) 696349cc55cSDimitry Andric mmapForContinuousMode(CurrentFileOffset, File); 697349cc55cSDimitry Andric 698349cc55cSDimitry Andric if (doMerging()) { 699fe6060f1SDimitry Andric lprofUnlockFileHandle(File); 70056727255SDimitry Andric } 70156727255SDimitry Andric if (File != NULL) { 702349cc55cSDimitry Andric fclose(File); 703fe6060f1SDimitry Andric } 704fe6060f1SDimitry Andric } 705480093f4SDimitry Andric 7060b57cec5SDimitry Andric static const char *DefaultProfileName = "default.profraw"; 7070b57cec5SDimitry Andric static void resetFilenameToDefault(void) { 7080b57cec5SDimitry Andric if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 70906c3fb27SDimitry Andric #ifdef __GNUC__ 71006c3fb27SDimitry Andric #pragma GCC diagnostic push 71106c3fb27SDimitry Andric #pragma GCC diagnostic ignored "-Wcast-qual" 7127a6dacacSDimitry Andric #elif defined(__clang__) 7137a6dacacSDimitry Andric #pragma clang diagnostic push 7147a6dacacSDimitry Andric #pragma clang diagnostic ignored "-Wcast-qual" 71506c3fb27SDimitry Andric #endif 7160b57cec5SDimitry Andric free((void *)lprofCurFilename.FilenamePat); 71706c3fb27SDimitry Andric #ifdef __GNUC__ 71806c3fb27SDimitry Andric #pragma GCC diagnostic pop 7197a6dacacSDimitry Andric #elif defined(__clang__) 7207a6dacacSDimitry Andric #pragma clang diagnostic pop 72106c3fb27SDimitry Andric #endif 7220b57cec5SDimitry Andric } 7230b57cec5SDimitry Andric memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 7240b57cec5SDimitry Andric lprofCurFilename.FilenamePat = DefaultProfileName; 7250b57cec5SDimitry Andric lprofCurFilename.PNS = PNS_default; 7260b57cec5SDimitry Andric } 7270b57cec5SDimitry Andric 728480093f4SDimitry Andric static unsigned getMergePoolSize(const char *FilenamePat, int *I) { 729480093f4SDimitry Andric unsigned J = 0, Num = 0; 730480093f4SDimitry Andric for (;; ++J) { 731480093f4SDimitry Andric char C = FilenamePat[*I + J]; 732480093f4SDimitry Andric if (C == 'm') { 733480093f4SDimitry Andric *I += J; 734480093f4SDimitry Andric return Num ? Num : 1; 735480093f4SDimitry Andric } 736480093f4SDimitry Andric if (C < '0' || C > '9') 737480093f4SDimitry Andric break; 738480093f4SDimitry Andric Num = Num * 10 + C - '0'; 739480093f4SDimitry Andric 740480093f4SDimitry Andric /* If FilenamePat[*I+J] is between '0' and '9', the next byte is guaranteed 7410b57cec5SDimitry Andric * to be in-bound as the string is null terminated. */ 742480093f4SDimitry Andric } 743480093f4SDimitry Andric return 0; 7440b57cec5SDimitry Andric } 7450b57cec5SDimitry Andric 746fe6060f1SDimitry Andric /* Assert that Idx does index past a string null terminator. Return the 747fe6060f1SDimitry Andric * result of the check. */ 748fe6060f1SDimitry Andric static int checkBounds(int Idx, int Strlen) { 749fe6060f1SDimitry Andric assert(Idx <= Strlen && "Indexing past string null terminator"); 750fe6060f1SDimitry Andric return Idx <= Strlen; 751fe6060f1SDimitry Andric } 752fe6060f1SDimitry Andric 7530b57cec5SDimitry Andric /* Parses the pattern string \p FilenamePat and stores the result to 7540b57cec5SDimitry Andric * lprofcurFilename structure. */ 7550b57cec5SDimitry Andric static int parseFilenamePattern(const char *FilenamePat, 7560b57cec5SDimitry Andric unsigned CopyFilenamePat) { 7570b57cec5SDimitry Andric int NumPids = 0, NumHosts = 0, I; 7580b57cec5SDimitry Andric char *PidChars = &lprofCurFilename.PidChars[0]; 7590b57cec5SDimitry Andric char *Hostname = &lprofCurFilename.Hostname[0]; 7600b57cec5SDimitry Andric int MergingEnabled = 0; 761fe6060f1SDimitry Andric int FilenamePatLen = strlen(FilenamePat); 7620b57cec5SDimitry Andric 76306c3fb27SDimitry Andric #ifdef __GNUC__ 76406c3fb27SDimitry Andric #pragma GCC diagnostic push 76506c3fb27SDimitry Andric #pragma GCC diagnostic ignored "-Wcast-qual" 7667a6dacacSDimitry Andric #elif defined(__clang__) 7677a6dacacSDimitry Andric #pragma clang diagnostic push 7687a6dacacSDimitry Andric #pragma clang diagnostic ignored "-Wcast-qual" 76906c3fb27SDimitry Andric #endif 7700b57cec5SDimitry Andric /* Clean up cached prefix and filename. */ 7710b57cec5SDimitry Andric if (lprofCurFilename.ProfilePathPrefix) 7720b57cec5SDimitry Andric free((void *)lprofCurFilename.ProfilePathPrefix); 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric if (lprofCurFilename.FilenamePat && lprofCurFilename.OwnsFilenamePat) { 7750b57cec5SDimitry Andric free((void *)lprofCurFilename.FilenamePat); 7760b57cec5SDimitry Andric } 77706c3fb27SDimitry Andric #ifdef __GNUC__ 77806c3fb27SDimitry Andric #pragma GCC diagnostic pop 7797a6dacacSDimitry Andric #elif defined(__clang__) 7807a6dacacSDimitry Andric #pragma clang diagnostic pop 78106c3fb27SDimitry Andric #endif 7820b57cec5SDimitry Andric 7830b57cec5SDimitry Andric memset(&lprofCurFilename, 0, sizeof(lprofCurFilename)); 7840b57cec5SDimitry Andric 7850b57cec5SDimitry Andric if (!CopyFilenamePat) 7860b57cec5SDimitry Andric lprofCurFilename.FilenamePat = FilenamePat; 7870b57cec5SDimitry Andric else { 7880b57cec5SDimitry Andric lprofCurFilename.FilenamePat = strdup(FilenamePat); 7890b57cec5SDimitry Andric lprofCurFilename.OwnsFilenamePat = 1; 7900b57cec5SDimitry Andric } 7910b57cec5SDimitry Andric /* Check the filename for "%p", which indicates a pid-substitution. */ 792fe6060f1SDimitry Andric for (I = 0; checkBounds(I, FilenamePatLen) && FilenamePat[I]; ++I) { 7930b57cec5SDimitry Andric if (FilenamePat[I] == '%') { 794fe6060f1SDimitry Andric ++I; /* Advance to the next character. */ 795fe6060f1SDimitry Andric if (!checkBounds(I, FilenamePatLen)) 796fe6060f1SDimitry Andric break; 797fe6060f1SDimitry Andric if (FilenamePat[I] == 'p') { 7980b57cec5SDimitry Andric if (!NumPids++) { 7990b57cec5SDimitry Andric if (snprintf(PidChars, MAX_PID_SIZE, "%ld", (long)getpid()) <= 0) { 8000b57cec5SDimitry Andric PROF_WARN("Unable to get pid for filename pattern %s. Using the " 8010b57cec5SDimitry Andric "default name.", 8020b57cec5SDimitry Andric FilenamePat); 8030b57cec5SDimitry Andric return -1; 8040b57cec5SDimitry Andric } 8050b57cec5SDimitry Andric } 8060b57cec5SDimitry Andric } else if (FilenamePat[I] == 'h') { 8070b57cec5SDimitry Andric if (!NumHosts++) 8080b57cec5SDimitry Andric if (COMPILER_RT_GETHOSTNAME(Hostname, COMPILER_RT_MAX_HOSTLEN)) { 8090b57cec5SDimitry Andric PROF_WARN("Unable to get hostname for filename pattern %s. Using " 8100b57cec5SDimitry Andric "the default name.", 8110b57cec5SDimitry Andric FilenamePat); 8120b57cec5SDimitry Andric return -1; 8130b57cec5SDimitry Andric } 814e8d8bef9SDimitry Andric } else if (FilenamePat[I] == 't') { 815e8d8bef9SDimitry Andric lprofCurFilename.TmpDir = getenv("TMPDIR"); 816e8d8bef9SDimitry Andric if (!lprofCurFilename.TmpDir) { 817e8d8bef9SDimitry Andric PROF_WARN("Unable to get the TMPDIR environment variable, referenced " 818e8d8bef9SDimitry Andric "in %s. Using the default path.", 819e8d8bef9SDimitry Andric FilenamePat); 820e8d8bef9SDimitry Andric return -1; 821e8d8bef9SDimitry Andric } 822480093f4SDimitry Andric } else if (FilenamePat[I] == 'c') { 823480093f4SDimitry Andric if (__llvm_profile_is_continuous_mode_enabled()) { 824480093f4SDimitry Andric PROF_WARN("%%c specifier can only be specified once in %s.\n", 825480093f4SDimitry Andric FilenamePat); 8265f757f3fSDimitry Andric __llvm_profile_disable_continuous_mode(); 827480093f4SDimitry Andric return -1; 828480093f4SDimitry Andric } 829fe6060f1SDimitry Andric #if defined(__APPLE__) || defined(__ELF__) || defined(_WIN32) 830e8d8bef9SDimitry Andric __llvm_profile_set_page_size(getpagesize()); 831480093f4SDimitry Andric __llvm_profile_enable_continuous_mode(); 832fe6060f1SDimitry Andric #else 833fe6060f1SDimitry Andric PROF_WARN("%s", "Continous mode is currently only supported for Mach-O," 834fe6060f1SDimitry Andric " ELF and COFF formats."); 835fe6060f1SDimitry Andric return -1; 836fe6060f1SDimitry Andric #endif 837480093f4SDimitry Andric } else { 838480093f4SDimitry Andric unsigned MergePoolSize = getMergePoolSize(FilenamePat, &I); 839480093f4SDimitry Andric if (!MergePoolSize) 840480093f4SDimitry Andric continue; 8410b57cec5SDimitry Andric if (MergingEnabled) { 8420b57cec5SDimitry Andric PROF_WARN("%%m specifier can only be specified once in %s.\n", 8430b57cec5SDimitry Andric FilenamePat); 8440b57cec5SDimitry Andric return -1; 8450b57cec5SDimitry Andric } 8460b57cec5SDimitry Andric MergingEnabled = 1; 847480093f4SDimitry Andric lprofCurFilename.MergePoolSize = MergePoolSize; 8480b57cec5SDimitry Andric } 8490b57cec5SDimitry Andric } 850fe6060f1SDimitry Andric } 8510b57cec5SDimitry Andric 8520b57cec5SDimitry Andric lprofCurFilename.NumPids = NumPids; 8530b57cec5SDimitry Andric lprofCurFilename.NumHosts = NumHosts; 8540b57cec5SDimitry Andric return 0; 8550b57cec5SDimitry Andric } 8560b57cec5SDimitry Andric 8570b57cec5SDimitry Andric static void parseAndSetFilename(const char *FilenamePat, 8580b57cec5SDimitry Andric ProfileNameSpecifier PNS, 8590b57cec5SDimitry Andric unsigned CopyFilenamePat) { 8600b57cec5SDimitry Andric 8610b57cec5SDimitry Andric const char *OldFilenamePat = lprofCurFilename.FilenamePat; 8620b57cec5SDimitry Andric ProfileNameSpecifier OldPNS = lprofCurFilename.PNS; 8630b57cec5SDimitry Andric 864480093f4SDimitry Andric /* The old profile name specifier takes precedence over the old one. */ 8650b57cec5SDimitry Andric if (PNS < OldPNS) 8660b57cec5SDimitry Andric return; 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric if (!FilenamePat) 8690b57cec5SDimitry Andric FilenamePat = DefaultProfileName; 8700b57cec5SDimitry Andric 8710b57cec5SDimitry Andric if (OldFilenamePat && !strcmp(OldFilenamePat, FilenamePat)) { 8720b57cec5SDimitry Andric lprofCurFilename.PNS = PNS; 8730b57cec5SDimitry Andric return; 8740b57cec5SDimitry Andric } 8750b57cec5SDimitry Andric 8760b57cec5SDimitry Andric /* When PNS >= OldPNS, the last one wins. */ 8770b57cec5SDimitry Andric if (!FilenamePat || parseFilenamePattern(FilenamePat, CopyFilenamePat)) 8780b57cec5SDimitry Andric resetFilenameToDefault(); 8790b57cec5SDimitry Andric lprofCurFilename.PNS = PNS; 8800b57cec5SDimitry Andric 8810b57cec5SDimitry Andric if (!OldFilenamePat) { 8820b57cec5SDimitry Andric if (getenv("LLVM_PROFILE_VERBOSE")) 8830b57cec5SDimitry Andric PROF_NOTE("Set profile file path to \"%s\" via %s.\n", 8840b57cec5SDimitry Andric lprofCurFilename.FilenamePat, getPNSStr(PNS)); 8850b57cec5SDimitry Andric } else { 8860b57cec5SDimitry Andric if (getenv("LLVM_PROFILE_VERBOSE")) 8870b57cec5SDimitry Andric PROF_NOTE("Override old profile path \"%s\" via %s to \"%s\" via %s.\n", 8880b57cec5SDimitry Andric OldFilenamePat, getPNSStr(OldPNS), lprofCurFilename.FilenamePat, 8890b57cec5SDimitry Andric getPNSStr(PNS)); 8900b57cec5SDimitry Andric } 8910b57cec5SDimitry Andric 8920b57cec5SDimitry Andric truncateCurrentFile(); 893fe6060f1SDimitry Andric if (__llvm_profile_is_continuous_mode_enabled()) 894480093f4SDimitry Andric initializeProfileForContinuousMode(); 8950b57cec5SDimitry Andric } 8960b57cec5SDimitry Andric 8970b57cec5SDimitry Andric /* Return buffer length that is required to store the current profile 8980b57cec5SDimitry Andric * filename with PID and hostname substitutions. */ 899480093f4SDimitry Andric /* The length to hold uint64_t followed by 3 digits pool id including '_' */ 9000b57cec5SDimitry Andric #define SIGLEN 24 90181ad6265SDimitry Andric static int getCurFilenameLength(void) { 9020b57cec5SDimitry Andric int Len; 9030b57cec5SDimitry Andric if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 9040b57cec5SDimitry Andric return 0; 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 907e8d8bef9SDimitry Andric lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize)) 9080b57cec5SDimitry Andric return strlen(lprofCurFilename.FilenamePat); 9090b57cec5SDimitry Andric 9100b57cec5SDimitry Andric Len = strlen(lprofCurFilename.FilenamePat) + 9110b57cec5SDimitry Andric lprofCurFilename.NumPids * (strlen(lprofCurFilename.PidChars) - 2) + 912e8d8bef9SDimitry Andric lprofCurFilename.NumHosts * (strlen(lprofCurFilename.Hostname) - 2) + 913e8d8bef9SDimitry Andric (lprofCurFilename.TmpDir ? (strlen(lprofCurFilename.TmpDir) - 1) : 0); 9140b57cec5SDimitry Andric if (lprofCurFilename.MergePoolSize) 9150b57cec5SDimitry Andric Len += SIGLEN; 9160b57cec5SDimitry Andric return Len; 9170b57cec5SDimitry Andric } 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric /* Return the pointer to the current profile file name (after substituting 9200b57cec5SDimitry Andric * PIDs and Hostnames in filename pattern. \p FilenameBuf is the buffer 9210b57cec5SDimitry Andric * to store the resulting filename. If no substitution is needed, the 9220b57cec5SDimitry Andric * current filename pattern string is directly returned, unless ForceUseBuf 9230b57cec5SDimitry Andric * is enabled. */ 9240b57cec5SDimitry Andric static const char *getCurFilename(char *FilenameBuf, int ForceUseBuf) { 925e8d8bef9SDimitry Andric int I, J, PidLength, HostNameLength, TmpDirLength, FilenamePatLength; 9260b57cec5SDimitry Andric const char *FilenamePat = lprofCurFilename.FilenamePat; 9270b57cec5SDimitry Andric 9280b57cec5SDimitry Andric if (!lprofCurFilename.FilenamePat || !lprofCurFilename.FilenamePat[0]) 9290b57cec5SDimitry Andric return 0; 9300b57cec5SDimitry Andric 9310b57cec5SDimitry Andric if (!(lprofCurFilename.NumPids || lprofCurFilename.NumHosts || 932e8d8bef9SDimitry Andric lprofCurFilename.TmpDir || lprofCurFilename.MergePoolSize || 933480093f4SDimitry Andric __llvm_profile_is_continuous_mode_enabled())) { 9340b57cec5SDimitry Andric if (!ForceUseBuf) 9350b57cec5SDimitry Andric return lprofCurFilename.FilenamePat; 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric FilenamePatLength = strlen(lprofCurFilename.FilenamePat); 9380b57cec5SDimitry Andric memcpy(FilenameBuf, lprofCurFilename.FilenamePat, FilenamePatLength); 9390b57cec5SDimitry Andric FilenameBuf[FilenamePatLength] = '\0'; 9400b57cec5SDimitry Andric return FilenameBuf; 9410b57cec5SDimitry Andric } 9420b57cec5SDimitry Andric 9430b57cec5SDimitry Andric PidLength = strlen(lprofCurFilename.PidChars); 9440b57cec5SDimitry Andric HostNameLength = strlen(lprofCurFilename.Hostname); 945e8d8bef9SDimitry Andric TmpDirLength = lprofCurFilename.TmpDir ? strlen(lprofCurFilename.TmpDir) : 0; 9460b57cec5SDimitry Andric /* Construct the new filename. */ 9470b57cec5SDimitry Andric for (I = 0, J = 0; FilenamePat[I]; ++I) 9480b57cec5SDimitry Andric if (FilenamePat[I] == '%') { 9490b57cec5SDimitry Andric if (FilenamePat[++I] == 'p') { 9500b57cec5SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.PidChars, PidLength); 9510b57cec5SDimitry Andric J += PidLength; 9520b57cec5SDimitry Andric } else if (FilenamePat[I] == 'h') { 9530b57cec5SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.Hostname, HostNameLength); 9540b57cec5SDimitry Andric J += HostNameLength; 955e8d8bef9SDimitry Andric } else if (FilenamePat[I] == 't') { 956e8d8bef9SDimitry Andric memcpy(FilenameBuf + J, lprofCurFilename.TmpDir, TmpDirLength); 957e8d8bef9SDimitry Andric FilenameBuf[J + TmpDirLength] = DIR_SEPARATOR; 958e8d8bef9SDimitry Andric J += TmpDirLength + 1; 959480093f4SDimitry Andric } else { 960480093f4SDimitry Andric if (!getMergePoolSize(FilenamePat, &I)) 961480093f4SDimitry Andric continue; 962480093f4SDimitry Andric char LoadModuleSignature[SIGLEN + 1]; 9630b57cec5SDimitry Andric int S; 9640b57cec5SDimitry Andric int ProfilePoolId = getpid() % lprofCurFilename.MergePoolSize; 965480093f4SDimitry Andric S = snprintf(LoadModuleSignature, SIGLEN + 1, "%" PRIu64 "_%d", 9660b57cec5SDimitry Andric lprofGetLoadModuleSignature(), ProfilePoolId); 9670b57cec5SDimitry Andric if (S == -1 || S > SIGLEN) 9680b57cec5SDimitry Andric S = SIGLEN; 9690b57cec5SDimitry Andric memcpy(FilenameBuf + J, LoadModuleSignature, S); 9700b57cec5SDimitry Andric J += S; 9710b57cec5SDimitry Andric } 9720b57cec5SDimitry Andric /* Drop any unknown substitutions. */ 9730b57cec5SDimitry Andric } else 9740b57cec5SDimitry Andric FilenameBuf[J++] = FilenamePat[I]; 9750b57cec5SDimitry Andric FilenameBuf[J] = 0; 9760b57cec5SDimitry Andric 9770b57cec5SDimitry Andric return FilenameBuf; 9780b57cec5SDimitry Andric } 9790b57cec5SDimitry Andric 9800b57cec5SDimitry Andric /* Returns the pointer to the environment variable 9810b57cec5SDimitry Andric * string. Returns null if the env var is not set. */ 9820b57cec5SDimitry Andric static const char *getFilenamePatFromEnv(void) { 9830b57cec5SDimitry Andric const char *Filename = getenv("LLVM_PROFILE_FILE"); 9840b57cec5SDimitry Andric if (!Filename || !Filename[0]) 9850b57cec5SDimitry Andric return 0; 9860b57cec5SDimitry Andric return Filename; 9870b57cec5SDimitry Andric } 9880b57cec5SDimitry Andric 9890b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 9900b57cec5SDimitry Andric const char *__llvm_profile_get_path_prefix(void) { 9910b57cec5SDimitry Andric int Length; 9920b57cec5SDimitry Andric char *FilenameBuf, *Prefix; 9930b57cec5SDimitry Andric const char *Filename, *PrefixEnd; 9940b57cec5SDimitry Andric 9950b57cec5SDimitry Andric if (lprofCurFilename.ProfilePathPrefix) 9960b57cec5SDimitry Andric return lprofCurFilename.ProfilePathPrefix; 9970b57cec5SDimitry Andric 9980b57cec5SDimitry Andric Length = getCurFilenameLength(); 9990b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 10000b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 10010b57cec5SDimitry Andric if (!Filename) 10020b57cec5SDimitry Andric return "\0"; 10030b57cec5SDimitry Andric 10040b57cec5SDimitry Andric PrefixEnd = lprofFindLastDirSeparator(Filename); 10050b57cec5SDimitry Andric if (!PrefixEnd) 10060b57cec5SDimitry Andric return "\0"; 10070b57cec5SDimitry Andric 10080b57cec5SDimitry Andric Length = PrefixEnd - Filename + 1; 10090b57cec5SDimitry Andric Prefix = (char *)malloc(Length + 1); 10100b57cec5SDimitry Andric if (!Prefix) { 10110b57cec5SDimitry Andric PROF_ERR("Failed to %s\n", "allocate memory."); 10120b57cec5SDimitry Andric return "\0"; 10130b57cec5SDimitry Andric } 10140b57cec5SDimitry Andric memcpy(Prefix, Filename, Length); 10150b57cec5SDimitry Andric Prefix[Length] = '\0'; 10160b57cec5SDimitry Andric lprofCurFilename.ProfilePathPrefix = Prefix; 10170b57cec5SDimitry Andric return Prefix; 10180b57cec5SDimitry Andric } 10190b57cec5SDimitry Andric 10200b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 10210b57cec5SDimitry Andric const char *__llvm_profile_get_filename(void) { 10220b57cec5SDimitry Andric int Length; 10230b57cec5SDimitry Andric char *FilenameBuf; 10240b57cec5SDimitry Andric const char *Filename; 10250b57cec5SDimitry Andric 10260b57cec5SDimitry Andric Length = getCurFilenameLength(); 10270b57cec5SDimitry Andric FilenameBuf = (char *)malloc(Length + 1); 10280b57cec5SDimitry Andric if (!FilenameBuf) { 10290b57cec5SDimitry Andric PROF_ERR("Failed to %s\n", "allocate memory."); 10300b57cec5SDimitry Andric return "\0"; 10310b57cec5SDimitry Andric } 10320b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 1); 10330b57cec5SDimitry Andric if (!Filename) 10340b57cec5SDimitry Andric return "\0"; 10350b57cec5SDimitry Andric 10360b57cec5SDimitry Andric return FilenameBuf; 10370b57cec5SDimitry Andric } 10380b57cec5SDimitry Andric 10395ffd83dbSDimitry Andric /* This API initializes the file handling, both user specified 10400b57cec5SDimitry Andric * profile path via -fprofile-instr-generate= and LLVM_PROFILE_FILE 10415ffd83dbSDimitry Andric * environment variable can override this default value. 10425ffd83dbSDimitry Andric */ 10430b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 10440b57cec5SDimitry Andric void __llvm_profile_initialize_file(void) { 10450b57cec5SDimitry Andric const char *EnvFilenamePat; 10460b57cec5SDimitry Andric const char *SelectedPat = NULL; 10470b57cec5SDimitry Andric ProfileNameSpecifier PNS = PNS_unknown; 10480b57cec5SDimitry Andric int hasCommandLineOverrider = (INSTR_PROF_PROFILE_NAME_VAR[0] != 0); 10490b57cec5SDimitry Andric 10500b57cec5SDimitry Andric EnvFilenamePat = getFilenamePatFromEnv(); 10510b57cec5SDimitry Andric if (EnvFilenamePat) { 10520b57cec5SDimitry Andric /* Pass CopyFilenamePat = 1, to ensure that the filename would be valid 10530b57cec5SDimitry Andric at the moment when __llvm_profile_write_file() gets executed. */ 10540b57cec5SDimitry Andric parseAndSetFilename(EnvFilenamePat, PNS_environment, 1); 10550b57cec5SDimitry Andric return; 10560b57cec5SDimitry Andric } else if (hasCommandLineOverrider) { 10570b57cec5SDimitry Andric SelectedPat = INSTR_PROF_PROFILE_NAME_VAR; 10580b57cec5SDimitry Andric PNS = PNS_command_line; 10590b57cec5SDimitry Andric } else { 10600b57cec5SDimitry Andric SelectedPat = NULL; 10610b57cec5SDimitry Andric PNS = PNS_default; 10620b57cec5SDimitry Andric } 10630b57cec5SDimitry Andric 10640b57cec5SDimitry Andric parseAndSetFilename(SelectedPat, PNS, 0); 10650b57cec5SDimitry Andric } 10660b57cec5SDimitry Andric 10675ffd83dbSDimitry Andric /* This method is invoked by the runtime initialization hook 10685ffd83dbSDimitry Andric * InstrProfilingRuntime.o if it is linked in. 10695ffd83dbSDimitry Andric */ 10705ffd83dbSDimitry Andric COMPILER_RT_VISIBILITY 10715ffd83dbSDimitry Andric void __llvm_profile_initialize(void) { 10725ffd83dbSDimitry Andric __llvm_profile_initialize_file(); 10735ffd83dbSDimitry Andric if (!__llvm_profile_is_continuous_mode_enabled()) 10745ffd83dbSDimitry Andric __llvm_profile_register_write_file_atexit(); 10755ffd83dbSDimitry Andric } 10765ffd83dbSDimitry Andric 10770b57cec5SDimitry Andric /* This API is directly called by the user application code. It has the 10780b57cec5SDimitry Andric * highest precedence compared with LLVM_PROFILE_FILE environment variable 10790b57cec5SDimitry Andric * and command line option -fprofile-instr-generate=<profile_name>. 10800b57cec5SDimitry Andric */ 10810b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 10820b57cec5SDimitry Andric void __llvm_profile_set_filename(const char *FilenamePat) { 1083480093f4SDimitry Andric if (__llvm_profile_is_continuous_mode_enabled()) 1084480093f4SDimitry Andric return; 10850b57cec5SDimitry Andric parseAndSetFilename(FilenamePat, PNS_runtime_api, 1); 10860b57cec5SDimitry Andric } 10870b57cec5SDimitry Andric 10880b57cec5SDimitry Andric /* The public API for writing profile data into the file with name 10890b57cec5SDimitry Andric * set by previous calls to __llvm_profile_set_filename or 10900b57cec5SDimitry Andric * __llvm_profile_override_default_filename or 10910b57cec5SDimitry Andric * __llvm_profile_initialize_file. */ 10920b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 10930b57cec5SDimitry Andric int __llvm_profile_write_file(void) { 10940b57cec5SDimitry Andric int rc, Length; 10950b57cec5SDimitry Andric const char *Filename; 10960b57cec5SDimitry Andric char *FilenameBuf; 10975f757f3fSDimitry Andric 10985f757f3fSDimitry Andric // Temporarily suspend getting SIGKILL when the parent exits. 10995f757f3fSDimitry Andric int PDeathSig = lprofSuspendSigKill(); 11000b57cec5SDimitry Andric 1101480093f4SDimitry Andric if (lprofProfileDumped() || __llvm_profile_is_continuous_mode_enabled()) { 11020b57cec5SDimitry Andric PROF_NOTE("Profile data not written to file: %s.\n", "already written"); 11035f757f3fSDimitry Andric if (PDeathSig == 1) 11045f757f3fSDimitry Andric lprofRestoreSigKill(); 11050b57cec5SDimitry Andric return 0; 11060b57cec5SDimitry Andric } 11070b57cec5SDimitry Andric 11080b57cec5SDimitry Andric Length = getCurFilenameLength(); 11090b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 11100b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 0); 11110b57cec5SDimitry Andric 11120b57cec5SDimitry Andric /* Check the filename. */ 11130b57cec5SDimitry Andric if (!Filename) { 11140b57cec5SDimitry Andric PROF_ERR("Failed to write file : %s\n", "Filename not set"); 11155f757f3fSDimitry Andric if (PDeathSig == 1) 11165f757f3fSDimitry Andric lprofRestoreSigKill(); 11170b57cec5SDimitry Andric return -1; 11180b57cec5SDimitry Andric } 11190b57cec5SDimitry Andric 11200b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 11210b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 11220b57cec5SDimitry Andric PROF_ERR("Runtime and instrumentation version mismatch : " 11230b57cec5SDimitry Andric "expected %d, but get %d\n", 11240b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 11250b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 11265f757f3fSDimitry Andric if (PDeathSig == 1) 11275f757f3fSDimitry Andric lprofRestoreSigKill(); 11280b57cec5SDimitry Andric return -1; 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric 11310b57cec5SDimitry Andric /* Write profile data to the file. */ 11320b57cec5SDimitry Andric rc = writeFile(Filename); 11330b57cec5SDimitry Andric if (rc) 11340b57cec5SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 11350b57cec5SDimitry Andric 11360b57cec5SDimitry Andric // Restore SIGKILL. 11370b57cec5SDimitry Andric if (PDeathSig == 1) 11380b57cec5SDimitry Andric lprofRestoreSigKill(); 11390b57cec5SDimitry Andric 11400b57cec5SDimitry Andric return rc; 11410b57cec5SDimitry Andric } 11420b57cec5SDimitry Andric 11430b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 11440b57cec5SDimitry Andric int __llvm_profile_dump(void) { 11450b57cec5SDimitry Andric if (!doMerging()) 11460b57cec5SDimitry Andric PROF_WARN("Later invocation of __llvm_profile_dump can lead to clobbering " 11470b57cec5SDimitry Andric " of previously dumped profile data : %s. Either use %%m " 11480b57cec5SDimitry Andric "in profile name or change profile name before dumping.\n", 11490b57cec5SDimitry Andric "online profile merging is not on"); 11500b57cec5SDimitry Andric int rc = __llvm_profile_write_file(); 11515ffd83dbSDimitry Andric lprofSetProfileDumped(1); 11520b57cec5SDimitry Andric return rc; 11530b57cec5SDimitry Andric } 11540b57cec5SDimitry Andric 11550b57cec5SDimitry Andric /* Order file data will be saved in a file with suffx .order. */ 11560b57cec5SDimitry Andric static const char *OrderFileSuffix = ".order"; 11570b57cec5SDimitry Andric 11580b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 11590b57cec5SDimitry Andric int __llvm_orderfile_write_file(void) { 11600b57cec5SDimitry Andric int rc, Length, LengthBeforeAppend, SuffixLength; 11610b57cec5SDimitry Andric const char *Filename; 11620b57cec5SDimitry Andric char *FilenameBuf; 11635f757f3fSDimitry Andric 11645f757f3fSDimitry Andric // Temporarily suspend getting SIGKILL when the parent exits. 11655f757f3fSDimitry Andric int PDeathSig = lprofSuspendSigKill(); 11660b57cec5SDimitry Andric 11670b57cec5SDimitry Andric SuffixLength = strlen(OrderFileSuffix); 11680b57cec5SDimitry Andric Length = getCurFilenameLength() + SuffixLength; 11690b57cec5SDimitry Andric FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1); 11700b57cec5SDimitry Andric Filename = getCurFilename(FilenameBuf, 1); 11710b57cec5SDimitry Andric 11720b57cec5SDimitry Andric /* Check the filename. */ 11730b57cec5SDimitry Andric if (!Filename) { 11740b57cec5SDimitry Andric PROF_ERR("Failed to write file : %s\n", "Filename not set"); 11755f757f3fSDimitry Andric if (PDeathSig == 1) 11765f757f3fSDimitry Andric lprofRestoreSigKill(); 11770b57cec5SDimitry Andric return -1; 11780b57cec5SDimitry Andric } 11790b57cec5SDimitry Andric 11800b57cec5SDimitry Andric /* Append order file suffix */ 11810b57cec5SDimitry Andric LengthBeforeAppend = strlen(Filename); 11820b57cec5SDimitry Andric memcpy(FilenameBuf + LengthBeforeAppend, OrderFileSuffix, SuffixLength); 11830b57cec5SDimitry Andric FilenameBuf[LengthBeforeAppend + SuffixLength] = '\0'; 11840b57cec5SDimitry Andric 11850b57cec5SDimitry Andric /* Check if there is llvm/runtime version mismatch. */ 11860b57cec5SDimitry Andric if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) { 11870b57cec5SDimitry Andric PROF_ERR("Runtime and instrumentation version mismatch : " 11880b57cec5SDimitry Andric "expected %d, but get %d\n", 11890b57cec5SDimitry Andric INSTR_PROF_RAW_VERSION, 11900b57cec5SDimitry Andric (int)GET_VERSION(__llvm_profile_get_version())); 11915f757f3fSDimitry Andric if (PDeathSig == 1) 11925f757f3fSDimitry Andric lprofRestoreSigKill(); 11930b57cec5SDimitry Andric return -1; 11940b57cec5SDimitry Andric } 11950b57cec5SDimitry Andric 11960b57cec5SDimitry Andric /* Write order data to the file. */ 11970b57cec5SDimitry Andric rc = writeOrderFile(Filename); 11980b57cec5SDimitry Andric if (rc) 11990b57cec5SDimitry Andric PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno)); 12000b57cec5SDimitry Andric 12010b57cec5SDimitry Andric // Restore SIGKILL. 12020b57cec5SDimitry Andric if (PDeathSig == 1) 12030b57cec5SDimitry Andric lprofRestoreSigKill(); 12040b57cec5SDimitry Andric 12050b57cec5SDimitry Andric return rc; 12060b57cec5SDimitry Andric } 12070b57cec5SDimitry Andric 12080b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 12090b57cec5SDimitry Andric int __llvm_orderfile_dump(void) { 12100b57cec5SDimitry Andric int rc = __llvm_orderfile_write_file(); 12110b57cec5SDimitry Andric return rc; 12120b57cec5SDimitry Andric } 12130b57cec5SDimitry Andric 12140b57cec5SDimitry Andric static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); } 12150b57cec5SDimitry Andric 12160b57cec5SDimitry Andric COMPILER_RT_VISIBILITY 12170b57cec5SDimitry Andric int __llvm_profile_register_write_file_atexit(void) { 12180b57cec5SDimitry Andric static int HasBeenRegistered = 0; 12190b57cec5SDimitry Andric 12200b57cec5SDimitry Andric if (HasBeenRegistered) 12210b57cec5SDimitry Andric return 0; 12220b57cec5SDimitry Andric 12230b57cec5SDimitry Andric lprofSetupValueProfiler(); 12240b57cec5SDimitry Andric 12250b57cec5SDimitry Andric HasBeenRegistered = 1; 12260b57cec5SDimitry Andric return atexit(writeFileWithoutReturn); 12270b57cec5SDimitry Andric } 12280b57cec5SDimitry Andric 1229349cc55cSDimitry Andric COMPILER_RT_VISIBILITY int __llvm_profile_set_file_object(FILE *File, 1230349cc55cSDimitry Andric int EnableMerge) { 1231349cc55cSDimitry Andric if (__llvm_profile_is_continuous_mode_enabled()) { 1232349cc55cSDimitry Andric if (!EnableMerge) { 1233349cc55cSDimitry Andric PROF_WARN("__llvm_profile_set_file_object(fd=%d) not supported in " 1234349cc55cSDimitry Andric "continuous sync mode when merging is disabled\n", 1235349cc55cSDimitry Andric fileno(File)); 1236349cc55cSDimitry Andric return 1; 1237349cc55cSDimitry Andric } 1238349cc55cSDimitry Andric if (lprofLockFileHandle(File) != 0) { 1239349cc55cSDimitry Andric PROF_WARN("Data may be corrupted during profile merging : %s\n", 1240349cc55cSDimitry Andric "Fail to obtain file lock due to system limit."); 1241349cc55cSDimitry Andric } 1242349cc55cSDimitry Andric uint64_t ProfileFileSize = 0; 1243349cc55cSDimitry Andric if (getProfileFileSizeForMerging(File, &ProfileFileSize) == -1) { 1244349cc55cSDimitry Andric lprofUnlockFileHandle(File); 1245349cc55cSDimitry Andric return 1; 1246349cc55cSDimitry Andric } 1247349cc55cSDimitry Andric if (ProfileFileSize == 0) { 1248349cc55cSDimitry Andric FreeHook = &free; 1249349cc55cSDimitry Andric setupIOBuffer(); 1250349cc55cSDimitry Andric ProfDataWriter fileWriter; 1251349cc55cSDimitry Andric initFileWriter(&fileWriter, File); 1252349cc55cSDimitry Andric if (lprofWriteData(&fileWriter, 0, 0)) { 1253349cc55cSDimitry Andric lprofUnlockFileHandle(File); 1254349cc55cSDimitry Andric PROF_ERR("Failed to write file \"%d\": %s\n", fileno(File), 1255349cc55cSDimitry Andric strerror(errno)); 1256349cc55cSDimitry Andric return 1; 1257349cc55cSDimitry Andric } 1258349cc55cSDimitry Andric fflush(File); 1259349cc55cSDimitry Andric } else { 1260349cc55cSDimitry Andric /* The merged profile has a non-zero length. Check that it is compatible 1261349cc55cSDimitry Andric * with the data in this process. */ 1262349cc55cSDimitry Andric char *ProfileBuffer; 1263349cc55cSDimitry Andric if (mmapProfileForMerging(File, ProfileFileSize, &ProfileBuffer) == -1) { 1264349cc55cSDimitry Andric lprofUnlockFileHandle(File); 1265349cc55cSDimitry Andric return 1; 1266349cc55cSDimitry Andric } 1267349cc55cSDimitry Andric (void)munmap(ProfileBuffer, ProfileFileSize); 1268349cc55cSDimitry Andric } 1269349cc55cSDimitry Andric mmapForContinuousMode(0, File); 1270349cc55cSDimitry Andric lprofUnlockFileHandle(File); 1271349cc55cSDimitry Andric } else { 1272349cc55cSDimitry Andric setProfileFile(File); 1273349cc55cSDimitry Andric setProfileMergeRequested(EnableMerge); 1274349cc55cSDimitry Andric } 1275349cc55cSDimitry Andric return 0; 1276349cc55cSDimitry Andric } 1277349cc55cSDimitry Andric 12780b57cec5SDimitry Andric #endif 1279