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