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