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