blob: 779a68225c31d2a1806b04c0d0e55c7a03467952 [file] [log] [blame]
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +00001/*===- InstrProfilingFile.c - Write instrumentation to a file -------------===*\
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +00002|*
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"
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000011#include <stdio.h>
12#include <stdlib.h>
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +000013#include <string.h>
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000014
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000015static int writeFile(FILE *File) {
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000016 /* Match logic in __llvm_profile_write_buffer(). */
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000017 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;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000028 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};
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000032
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000033 /* Create the header. */
Reid Kleckneraf6b2502014-05-01 18:52:14 +000034 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;
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000042
43 /* Write the data. */
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000044#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);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000048 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000049 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000050 CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000051#undef CHECK_fwrite
52
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000053 return 0;
54}
55
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000056static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000057 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000058 FILE *OutputFile;
59 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000060 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000061
62 /* Append to the file to support profiling multiple shared objects. */
63 OutputFile = fopen(OutputName, "a");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000064 if (!OutputFile)
65 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000066
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000067 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000068
69 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000070 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000071}
72
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000073__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000074__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000075
76static void setFilename(const char *Filename, int OwnsFilename) {
77 if (__llvm_profile_OwnsFilename)
78 free((char *)__llvm_profile_CurrentFilename);
79
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000080 __llvm_profile_CurrentFilename = Filename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000081 __llvm_profile_OwnsFilename = OwnsFilename;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000082}
83
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000084static void truncateCurrentFile(void) {
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000085 const char *Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000086 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
96static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
97
98int getpid(void);
99static int setFilenameFromEnvironment(void) {
100 const char *Filename = getenv("LLVM_PROFILE_FILE");
101 if (!Filename || !Filename[0])
102 return -1;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000103
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000104 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000105#define MAX_PID_SIZE 16
106 char PidChars[MAX_PID_SIZE] = {0};
107 int NumPids = 0;
108 int PidLength = 0;
109 int I;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000110 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)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000115 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000116 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000117 if (!NumPids) {
118 setFilename(Filename, 0);
119 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000120 }
121
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000122 /* 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
145static void setFilenameAutomatically(void) {
146 if (!setFilenameFromEnvironment())
147 return;
148
149 setDefaultFilename();
150}
151
152__attribute__((visibility("hidden")))
153void __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")))
164void __llvm_profile_set_filename(const char *Filename) {
165 setFilename(Filename, 0);
166 truncateCurrentFile();
167}
168
169__attribute__((visibility("hidden")))
170int __llvm_profile_write_file(void) {
171 /* Check the filename. */
172 if (!__llvm_profile_CurrentFilename)
173 return -1;
174
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000175 /* Write the file. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000176 return writeFileWithName(__llvm_profile_CurrentFilename);
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000177}
178
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000179static void writeFileWithoutReturn(void) {
180 __llvm_profile_write_file();
181}
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000182
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000183__attribute__((visibility("hidden")))
184int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000185 static int HasBeenRegistered = 0;
186
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000187 if (HasBeenRegistered)
188 return 0;
189
190 HasBeenRegistered = 1;
191 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000192}