blob: 346665fd5b3eb89aff48e91fadc8f8a726379dd2 [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>
Justin Bogner66fd5c92015-01-16 20:10:56 +000014#include <sys/errno.h>
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000015
Joerg Sonnenbergerb1cc6d52014-05-20 16:37:07 +000016#define UNCONST(ptr) ((void *)(uintptr_t)(ptr))
17
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000018static int writeFile(FILE *File) {
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000019 /* Match logic in __llvm_profile_write_buffer(). */
Justin Bognercc0d7ee2014-09-04 15:45:31 +000020 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();
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000026
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;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000031 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};
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000035
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000036 /* Create the header. */
Reid Kleckneraf6b2502014-05-01 18:52:14 +000037 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;
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000045
46 /* Write the data. */
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000047#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);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000051 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
Duncan P. N. Exon Smith812dcae2014-03-21 18:29:24 +000052 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000053 CHECK_fwrite(Zeroes, sizeof(char), Padding, File);
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000054#undef CHECK_fwrite
55
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000056 return 0;
57}
58
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000059static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000060 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000061 FILE *OutputFile;
62 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000063 return -1;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000064
65 /* Append to the file to support profiling multiple shared objects. */
66 OutputFile = fopen(OutputName, "a");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000067 if (!OutputFile)
68 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000069
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000070 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000071
72 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000073 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000074}
75
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000076__attribute__((weak)) int __llvm_profile_OwnsFilename = 0;
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000077__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000078
79static void setFilename(const char *Filename, int OwnsFilename) {
80 if (__llvm_profile_OwnsFilename)
Joerg Sonnenbergerb1cc6d52014-05-20 16:37:07 +000081 free(UNCONST(__llvm_profile_CurrentFilename));
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000082
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000083 __llvm_profile_CurrentFilename = Filename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000084 __llvm_profile_OwnsFilename = OwnsFilename;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000085}
86
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000087static void truncateCurrentFile(void) {
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000088 const char *Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +000089 if (!Filename || !Filename[0])
90 return;
91
92 /* Truncate the file. Later we'll reopen and append. */
93 FILE *File = fopen(Filename, "w");
94 if (!File)
95 return;
96 fclose(File);
97}
98
99static void setDefaultFilename(void) { setFilename("default.profraw", 0); }
100
101int getpid(void);
102static int setFilenameFromEnvironment(void) {
103 const char *Filename = getenv("LLVM_PROFILE_FILE");
104 if (!Filename || !Filename[0])
105 return -1;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000106
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000107 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000108#define MAX_PID_SIZE 16
109 char PidChars[MAX_PID_SIZE] = {0};
110 int NumPids = 0;
111 int PidLength = 0;
112 int I;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000113 for (I = 0; Filename[I]; ++I)
114 if (Filename[I] == '%' && Filename[++I] == 'p')
115 if (!NumPids++) {
116 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
117 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000118 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000119 }
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000120 if (!NumPids) {
121 setFilename(Filename, 0);
122 return 0;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000123 }
124
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000125 /* Allocate enough space for the substituted filename. */
126 char *Allocated = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
127 if (!Allocated)
128 return -1;
129
130 /* Construct the new filename. */
131 int J;
132 for (I = 0, J = 0; Filename[I]; ++I)
133 if (Filename[I] == '%') {
134 if (Filename[++I] == 'p') {
135 memcpy(Allocated + J, PidChars, PidLength);
136 J += PidLength;
137 }
138 /* Drop any unknown substitutions. */
139 } else
140 Allocated[J++] = Filename[I];
141 Allocated[J] = 0;
142
143 /* Use the computed name. */
144 setFilename(Allocated, 1);
145 return 0;
146}
147
148static void setFilenameAutomatically(void) {
149 if (!setFilenameFromEnvironment())
150 return;
151
152 setDefaultFilename();
153}
154
155__attribute__((visibility("hidden")))
156void __llvm_profile_initialize_file(void) {
157 /* Check if the filename has been initialized. */
158 if (__llvm_profile_CurrentFilename)
159 return;
160
161 /* Detect the filename and truncate. */
162 setFilenameAutomatically();
163 truncateCurrentFile();
164}
165
166__attribute__((visibility("hidden")))
167void __llvm_profile_set_filename(const char *Filename) {
168 setFilename(Filename, 0);
169 truncateCurrentFile();
170}
171
172__attribute__((visibility("hidden")))
173int __llvm_profile_write_file(void) {
174 /* Check the filename. */
175 if (!__llvm_profile_CurrentFilename)
176 return -1;
177
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000178 /* Write the file. */
Justin Bogner66fd5c92015-01-16 20:10:56 +0000179 int rc = writeFileWithName(__llvm_profile_CurrentFilename);
180 if (rc && getenv("LLVM_PROFILE_VERBOSE_ERRORS"))
181 fprintf(stderr, "LLVM Profile: Failed to write file \"%s\": %s\n",
182 __llvm_profile_CurrentFilename, strerror(errno));
183 return rc;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000184}
185
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000186static void writeFileWithoutReturn(void) {
187 __llvm_profile_write_file();
188}
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000189
Duncan P. N. Exon Smith55e4d662014-05-17 01:27:30 +0000190__attribute__((visibility("hidden")))
191int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000192 static int HasBeenRegistered = 0;
193
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000194 if (HasBeenRegistered)
195 return 0;
196
197 HasBeenRegistered = 1;
198 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000199}