Home | History | Annotate | Line # | Download | only in profile
      1  1.1  joerg /*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
      2  1.1  joerg |*
      3  1.1  joerg |*                     The LLVM Compiler Infrastructure
      4  1.1  joerg |*
      5  1.1  joerg |* This file is distributed under the University of Illinois Open Source
      6  1.1  joerg |* License. See LICENSE.TXT for details.
      7  1.1  joerg |*
      8  1.1  joerg \*===----------------------------------------------------------------------===*/
      9  1.1  joerg 
     10  1.1  joerg #include "InstrProfiling.h"
     11  1.2  kamil #include "InstrProfilingInternal.h"
     12  1.2  kamil #include "InstrProfilingUtil.h"
     13  1.2  kamil #include <errno.h>
     14  1.1  joerg #include <stdio.h>
     15  1.1  joerg #include <stdlib.h>
     16  1.1  joerg #include <string.h>
     17  1.1  joerg 
     18  1.2  kamil #define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
     19  1.2  kamil 
     20  1.2  kamil /* Return 1 if there is an error, otherwise return  0.  */
     21  1.2  kamil static uint32_t fileWriter(ProfDataIOVec *IOVecs, uint32_t NumIOVecs,
     22  1.2  kamil                            void **WriterCtx) {
     23  1.2  kamil   uint32_t I;
     24  1.2  kamil   FILE *File = (FILE *)*WriterCtx;
     25  1.2  kamil   for (I = 0; I < NumIOVecs; I++) {
     26  1.2  kamil     if (fwrite(IOVecs[I].Data, IOVecs[I].ElmSize, IOVecs[I].NumElm, File) !=
     27  1.2  kamil         IOVecs[I].NumElm)
     28  1.2  kamil       return 1;
     29  1.2  kamil   }
     30  1.2  kamil   return 0;
     31  1.2  kamil }
     32  1.2  kamil 
     33  1.2  kamil COMPILER_RT_VISIBILITY ProfBufferIO *
     34  1.2  kamil llvmCreateBufferIOInternal(void *File, uint32_t BufferSz) {
     35  1.2  kamil   CallocHook = calloc;
     36  1.2  kamil   FreeHook = free;
     37  1.2  kamil   return llvmCreateBufferIO(fileWriter, File, BufferSz);
     38  1.2  kamil }
     39  1.2  kamil 
     40  1.1  joerg static int writeFile(FILE *File) {
     41  1.2  kamil   const char *BufferSzStr = 0;
     42  1.2  kamil   uint64_t ValueDataSize = 0;
     43  1.2  kamil   struct ValueProfData **ValueDataArray =
     44  1.2  kamil       __llvm_profile_gather_value_data(&ValueDataSize);
     45  1.2  kamil   FreeHook = &free;
     46  1.2  kamil   CallocHook = &calloc;
     47  1.2  kamil   BufferSzStr = getenv("LLVM_VP_BUFFER_SIZE");
     48  1.2  kamil   if (BufferSzStr && BufferSzStr[0])
     49  1.2  kamil     VPBufferSize = atoi(BufferSzStr);
     50  1.2  kamil   return llvmWriteProfData(fileWriter, File, ValueDataArray, ValueDataSize);
     51  1.1  joerg }
     52  1.1  joerg 
     53  1.1  joerg static int writeFileWithName(const char *OutputName) {
     54  1.1  joerg   int RetVal;
     55  1.1  joerg   FILE *OutputFile;
     56  1.1  joerg   if (!OutputName || !OutputName[0])
     57  1.1  joerg     return -1;
     58  1.2  kamil 
     59  1.2  kamil   /* Append to the file to support profiling multiple shared objects. */
     60  1.2  kamil   OutputFile = fopen(OutputName, "ab");
     61  1.1  joerg   if (!OutputFile)
     62  1.1  joerg     return -1;
     63  1.1  joerg 
     64  1.1  joerg   RetVal = writeFile(OutputFile);
     65  1.1  joerg 
     66  1.1  joerg   fclose(OutputFile);
     67  1.1  joerg   return RetVal;
     68  1.1  joerg }
     69  1.1  joerg 
     70  1.2  kamil COMPILER_RT_WEAK int __llvm_profile_OwnsFilename = 0;
     71  1.2  kamil COMPILER_RT_WEAK const char *__llvm_profile_CurrentFilename = NULL;
     72  1.2  kamil 
     73  1.2  kamil static void truncateCurrentFile(void) {
     74  1.2  kamil   const char *Filename;
     75  1.2  kamil   FILE *File;
     76  1.2  kamil 
     77  1.2  kamil   Filename = __llvm_profile_CurrentFilename;
     78  1.2  kamil   if (!Filename || !Filename[0])
     79  1.2  kamil     return;
     80  1.2  kamil 
     81  1.2  kamil   /* Create the directory holding the file, if needed. */
     82  1.2  kamil   if (strchr(Filename, '/')) {
     83  1.2  kamil     char *Copy = malloc(strlen(Filename) + 1);
     84  1.2  kamil     strcpy(Copy, Filename);
     85  1.2  kamil     __llvm_profile_recursive_mkdir(Copy);
     86  1.2  kamil     free(Copy);
     87  1.2  kamil   }
     88  1.2  kamil 
     89  1.2  kamil   /* Truncate the file.  Later we'll reopen and append. */
     90  1.2  kamil   File = fopen(Filename, "w");
     91  1.2  kamil   if (!File)
     92  1.2  kamil     return;
     93  1.2  kamil   fclose(File);
     94  1.2  kamil }
     95  1.2  kamil 
     96  1.2  kamil static void setFilename(const char *Filename, int OwnsFilename) {
     97  1.2  kamil   /* Check if this is a new filename and therefore needs truncation. */
     98  1.2  kamil   int NewFile = !__llvm_profile_CurrentFilename ||
     99  1.2  kamil       (Filename && strcmp(Filename, __llvm_profile_CurrentFilename));
    100  1.2  kamil   if (__llvm_profile_OwnsFilename)
    101  1.2  kamil     free(UNCONST(__llvm_profile_CurrentFilename));
    102  1.2  kamil 
    103  1.2  kamil   __llvm_profile_CurrentFilename = Filename;
    104  1.2  kamil   __llvm_profile_OwnsFilename = OwnsFilename;
    105  1.2  kamil 
    106  1.2  kamil   /* If not a new file, append to support profiling multiple shared objects. */
    107  1.2  kamil   if (NewFile)
    108  1.2  kamil     truncateCurrentFile();
    109  1.1  joerg }
    110  1.1  joerg 
    111  1.2  kamil static void resetFilenameToDefault(void) { setFilename("default.profraw", 0); }
    112  1.2  kamil 
    113  1.1  joerg int getpid(void);
    114  1.2  kamil static int setFilenamePossiblyWithPid(const char *Filename) {
    115  1.2  kamil #define MAX_PID_SIZE 16
    116  1.2  kamil   char PidChars[MAX_PID_SIZE] = {0};
    117  1.2  kamil   int NumPids = 0, PidLength = 0;
    118  1.2  kamil   char *Allocated;
    119  1.1  joerg   int I, J;
    120  1.1  joerg 
    121  1.2  kamil   /* Reset filename on NULL, except with env var which is checked by caller. */
    122  1.2  kamil   if (!Filename) {
    123  1.2  kamil     resetFilenameToDefault();
    124  1.2  kamil     return 0;
    125  1.2  kamil   }
    126  1.1  joerg 
    127  1.1  joerg   /* Check the filename for "%p", which indicates a pid-substitution. */
    128  1.1  joerg   for (I = 0; Filename[I]; ++I)
    129  1.1  joerg     if (Filename[I] == '%' && Filename[++I] == 'p')
    130  1.1  joerg       if (!NumPids++) {
    131  1.1  joerg         PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
    132  1.1  joerg         if (PidLength <= 0)
    133  1.1  joerg           return -1;
    134  1.1  joerg       }
    135  1.2  kamil   if (!NumPids) {
    136  1.2  kamil     setFilename(Filename, 0);
    137  1.2  kamil     return 0;
    138  1.2  kamil   }
    139  1.2  kamil 
    140  1.2  kamil   /* Allocate enough space for the substituted filename. */
    141  1.2  kamil   Allocated = malloc(I + NumPids*(PidLength - 2) + 1);
    142  1.2  kamil   if (!Allocated)
    143  1.2  kamil     return -1;
    144  1.2  kamil 
    145  1.2  kamil   /* Construct the new filename. */
    146  1.2  kamil   for (I = 0, J = 0; Filename[I]; ++I)
    147  1.2  kamil     if (Filename[I] == '%') {
    148  1.2  kamil       if (Filename[++I] == 'p') {
    149  1.2  kamil         memcpy(Allocated + J, PidChars, PidLength);
    150  1.2  kamil         J += PidLength;
    151  1.2  kamil       }
    152  1.2  kamil       /* Drop any unknown substitutions. */
    153  1.2  kamil     } else
    154  1.2  kamil       Allocated[J++] = Filename[I];
    155  1.2  kamil   Allocated[J] = 0;
    156  1.2  kamil 
    157  1.2  kamil   /* Use the computed name. */
    158  1.2  kamil   setFilename(Allocated, 1);
    159  1.2  kamil   return 0;
    160  1.2  kamil }
    161  1.2  kamil 
    162  1.2  kamil static int setFilenameFromEnvironment(void) {
    163  1.2  kamil   const char *Filename = getenv("LLVM_PROFILE_FILE");
    164  1.2  kamil 
    165  1.2  kamil   if (!Filename || !Filename[0])
    166  1.2  kamil     return -1;
    167  1.1  joerg 
    168  1.2  kamil   return setFilenamePossiblyWithPid(Filename);
    169  1.2  kamil }
    170  1.2  kamil 
    171  1.2  kamil static void setFilenameAutomatically(void) {
    172  1.2  kamil   if (!setFilenameFromEnvironment())
    173  1.2  kamil     return;
    174  1.2  kamil 
    175  1.2  kamil   resetFilenameToDefault();
    176  1.2  kamil }
    177  1.2  kamil 
    178  1.2  kamil COMPILER_RT_VISIBILITY
    179  1.2  kamil void __llvm_profile_initialize_file(void) {
    180  1.2  kamil   /* Check if the filename has been initialized. */
    181  1.2  kamil   if (__llvm_profile_CurrentFilename)
    182  1.2  kamil     return;
    183  1.1  joerg 
    184  1.2  kamil   /* Detect the filename and truncate. */
    185  1.2  kamil   setFilenameAutomatically();
    186  1.2  kamil }
    187  1.1  joerg 
    188  1.2  kamil COMPILER_RT_VISIBILITY
    189  1.2  kamil void __llvm_profile_set_filename(const char *Filename) {
    190  1.2  kamil   setFilenamePossiblyWithPid(Filename);
    191  1.2  kamil }
    192  1.1  joerg 
    193  1.2  kamil COMPILER_RT_VISIBILITY
    194  1.2  kamil void __llvm_profile_override_default_filename(const char *Filename) {
    195  1.2  kamil   /* If the env var is set, skip setting filename from argument. */
    196  1.2  kamil   const char *Env_Filename = getenv("LLVM_PROFILE_FILE");
    197  1.2  kamil   if (Env_Filename && Env_Filename[0])
    198  1.2  kamil     return;
    199  1.2  kamil   setFilenamePossiblyWithPid(Filename);
    200  1.1  joerg }
    201  1.1  joerg 
    202  1.2  kamil COMPILER_RT_VISIBILITY
    203  1.2  kamil int __llvm_profile_write_file(void) {
    204  1.2  kamil   int rc;
    205  1.2  kamil 
    206  1.2  kamil   GetEnvHook = &getenv;
    207  1.2  kamil   /* Check the filename. */
    208  1.2  kamil   if (!__llvm_profile_CurrentFilename) {
    209  1.2  kamil     PROF_ERR("LLVM Profile: Failed to write file : %s\n", "Filename not set");
    210  1.2  kamil     return -1;
    211  1.2  kamil   }
    212  1.2  kamil 
    213  1.2  kamil   /* Check if there is llvm/runtime version mismatch.  */
    214  1.2  kamil   if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
    215  1.2  kamil     PROF_ERR("LLVM Profile: runtime and instrumentation version mismatch : "
    216  1.2  kamil              "expected %d, but get %d\n",
    217  1.2  kamil              INSTR_PROF_RAW_VERSION,
    218  1.2  kamil              (int)GET_VERSION(__llvm_profile_get_version()));
    219  1.2  kamil     return -1;
    220  1.2  kamil   }
    221  1.2  kamil 
    222  1.2  kamil   /* Write the file. */
    223  1.2  kamil   rc = writeFileWithName(__llvm_profile_CurrentFilename);
    224  1.2  kamil   if (rc)
    225  1.2  kamil     PROF_ERR("LLVM Profile: Failed to write file \"%s\": %s\n",
    226  1.2  kamil             __llvm_profile_CurrentFilename, strerror(errno));
    227  1.2  kamil   return rc;
    228  1.1  joerg }
    229  1.1  joerg 
    230  1.2  kamil static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
    231  1.2  kamil 
    232  1.2  kamil COMPILER_RT_VISIBILITY
    233  1.1  joerg int __llvm_profile_register_write_file_atexit(void) {
    234  1.1  joerg   static int HasBeenRegistered = 0;
    235  1.1  joerg 
    236  1.1  joerg   if (HasBeenRegistered)
    237  1.1  joerg     return 0;
    238  1.1  joerg 
    239  1.1  joerg   HasBeenRegistered = 1;
    240  1.1  joerg   return atexit(writeFileWithoutReturn);
    241  1.1  joerg }
    242