Home | History | Annotate | Download | only in profile
      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 #include "InstrProfiling.h"
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 
     15 #define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
     16 
     17 static int writeFile(FILE *File) {
     18   /* Match logic in __llvm_profile_write_buffer(). */
     19   const __llvm_profile_data *DataBegin = __llvm_profile_data_begin();
     20   const __llvm_profile_data *DataEnd = __llvm_profile_data_end();
     21   const uint64_t *CountersBegin = __llvm_profile_counters_begin();
     22   const uint64_t *CountersEnd   = __llvm_profile_counters_end();
     23   const char *NamesBegin = __llvm_profile_names_begin();
     24   const char *NamesEnd   = __llvm_profile_names_end();
     25 
     26   /* Calculate size of sections. */
     27   const uint64_t DataSize = DataEnd - DataBegin;
     28   const uint64_t CountersSize = CountersEnd - CountersBegin;
     29   const uint64_t NamesSize = NamesEnd - NamesBegin;
     30   const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
     31 
     32   /* Enough zeroes for padding. */
     33   const char Zeroes[sizeof(uint64_t)] = {0};
     34 
     35   /* Create the header. */
     36   uint64_t Header[PROFILE_HEADER_SIZE];
     37   Header[0] = __llvm_profile_get_magic();
     38   Header[1] = __llvm_profile_get_version();
     39   Header[2] = DataSize;
     40   Header[3] = CountersSize;
     41   Header[4] = NamesSize;
     42   Header[5] = (uintptr_t)CountersBegin;
     43   Header[6] = (uintptr_t)NamesBegin;
     44 
     45   /* Write the data. */
     46 #define CHECK_fwrite(Data, Size, Length, File) \
     47   do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
     48   CHECK_fwrite(Header,        sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
     49   CHECK_fwrite(DataBegin,     sizeof(__llvm_profile_data), DataSize, File);
     50   CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
     51   CHECK_fwrite(NamesBegin,    sizeof(char), NamesSize, File);
     52   CHECK_fwrite(Zeroes,        sizeof(char), Padding, File);
     53 #undef CHECK_fwrite
     54 
     55   return 0;
     56 }
     57 
     58 static int writeFileWithName(const char *OutputName) {
     59   int RetVal;
     60   FILE *OutputFile;
     61   if (!OutputName || !OutputName[0])
     62     return -1;
     63 
     64   /* Append to the file to support profiling multiple shared objects. */
     65   OutputFile = fopen(OutputName, "a");
     66   if (!OutputFile)
     67     return -1;
     68 
     69   RetVal = writeFile(OutputFile);
     70 
     71   fclose(OutputFile);
     72   return RetVal;
     73 }
     74 
     75 __attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
     76 __attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
     77 
     78 static void setFilename(const char *Filename, int OwnsFilename) {
     79   if (__llvm_profile_OwnsFilename)
     80     free(UNCONST(__llvm_profile_CurrentFilename));
     81 
     82   __llvm_profile_CurrentFilename = Filename;
     83   __llvm_profile_OwnsFilename = OwnsFilename;
     84 }
     85 
     86 static void truncateCurrentFile(void) {
     87   const char *Filename = __llvm_profile_CurrentFilename;
     88   if (!Filename || !Filename[0])
     89     return;
     90 
     91   /* Truncate the file.  Later we'll reopen and append. */
     92   FILE *File = fopen(Filename, "w");
     93   if (!File)
     94     return;
     95   fclose(File);
     96 }
     97 
     98 static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
     99 
    100 int getpid(void);
    101 static int setFilenameFromEnvironment(void) {
    102   const char *Filename = getenv("LLVM_PROFILE_FILE");
    103   if (!Filename || !Filename[0])
    104     return -1;
    105 
    106   /* Check the filename for "%p", which indicates a pid-substitution. */
    107 #define MAX_PID_SIZE 16
    108   char PidChars[MAX_PID_SIZE] = {0};
    109   int NumPids = 0;
    110   int PidLength = 0;
    111   int I;
    112   for (I = 0; Filename[I]; ++I)
    113     if (Filename[I] == '%' && Filename[++I] == 'p')
    114       if (!NumPids++) {
    115         PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
    116         if (PidLength <= 0)
    117           return -1;
    118       }
    119   if (!NumPids) {
    120     setFilename(Filename, 0);
    121     return 0;
    122   }
    123 
    124   /* Allocate enough space for the substituted filename. */
    125   char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
    126   if (!Allocated)
    127     return -1;
    128 
    129   /* Construct the new filename. */
    130   int J;
    131   for (I = 0, J = 0; Filename[I]; ++I)
    132     if (Filename[I] == '%') {
    133       if (Filename[++I] == 'p') {
    134         memcpy(Allocated + J, PidChars, PidLength);
    135         J += PidLength;
    136       }
    137       /* Drop any unknown substitutions. */
    138     } else
    139       Allocated[J++] = Filename[I];
    140   Allocated[J] = 0;
    141 
    142   /* Use the computed name. */
    143   setFilename(Allocated, 1);
    144   return 0;
    145 }
    146 
    147 static void setFilenameAutomatically(void) {
    148   if (!setFilenameFromEnvironment())
    149     return;
    150 
    151   setDefaultFilename();
    152 }
    153 
    154 __attribute__((visibility("hidden")))
    155 void __llvm_profile_initialize_file(void) {
    156   /* Check if the filename has been initialized. */
    157   if (__llvm_profile_CurrentFilename)
    158     return;
    159 
    160   /* Detect the filename and truncate. */
    161   setFilenameAutomatically();
    162   truncateCurrentFile();
    163 }
    164 
    165 __attribute__((visibility("hidden")))
    166 void __llvm_profile_set_filename(const char *Filename) {
    167   setFilename(Filename, 0);
    168   truncateCurrentFile();
    169 }
    170 
    171 __attribute__((visibility("hidden")))
    172 int __llvm_profile_write_file(void) {
    173   /* Check the filename. */
    174   if (!__llvm_profile_CurrentFilename)
    175     return -1;
    176 
    177   /* Write the file. */
    178   return writeFileWithName(__llvm_profile_CurrentFilename);
    179 }
    180 
    181 static void writeFileWithoutReturn(void) {
    182   __llvm_profile_write_file();
    183 }
    184 
    185 __attribute__((visibility("hidden")))
    186 int __llvm_profile_register_write_file_atexit(void) {
    187   static int HasBeenRegistered = 0;
    188 
    189   if (HasBeenRegistered)
    190     return 0;
    191 
    192   HasBeenRegistered = 1;
    193   return atexit(writeFileWithoutReturn);
    194 }
    195