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