blob: 5ed32d56267a93e0d2c3f9e8ad96c889d336b26a [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
56typedef struct __llvm_profile_writer {
57 struct __llvm_profile_writer *Next;
58 int (*Data)(FILE *);
59} __llvm_profile_writer;
60
61__attribute__((weak)) __llvm_profile_writer *__llvm_profile_HeadWriter = NULL;
62static __llvm_profile_writer Writer = {NULL, writeFile};
63
64__attribute__((visibility("hidden")))
65void __llvm_profile_register_write_file(void) {
66 static int HasBeenRegistered = 0;
67
68 if (HasBeenRegistered)
69 return;
70
71 HasBeenRegistered = 1;
72 Writer.Next = __llvm_profile_HeadWriter;
73 __llvm_profile_HeadWriter = &Writer;
Duncan P. N. Exon Smithcf4bb962014-03-21 18:29:19 +000074}
75
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +000076static int writeFileWithName(const char *OutputName) {
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000077 int RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000078 FILE *OutputFile;
79 if (!OutputName || !OutputName[0])
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000080 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000081 OutputFile = fopen(OutputName, "w");
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000082 if (!OutputFile)
83 return -1;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000084
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +000085 __llvm_profile_writer *Writer = __llvm_profile_HeadWriter;
86 if (Writer)
87 for (; Writer; Writer = Writer->Next) {
88 RetVal = Writer->Data(OutputFile);
89 if (RetVal != 0)
90 break;
91 }
92 else
93 // Default to calling this executable's writeFile.
94 RetVal = writeFile(OutputFile);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000095
96 fclose(OutputFile);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +000097 return RetVal;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +000098}
99
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +0000100__attribute__((weak)) const char *__llvm_profile_CurrentFilename = NULL;
101__attribute__((weak)) void __llvm_profile_set_filename(const char *Filename) {
102 __llvm_profile_CurrentFilename = Filename;
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000103}
104
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000105int getpid(void);
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +0000106__attribute__((weak)) int __llvm_profile_write_file(void) {
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000107 char *AllocatedFilename = NULL;
108 int I, J;
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000109 int RetVal;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000110
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000111#define MAX_PID_SIZE 16
112 char PidChars[MAX_PID_SIZE] = { 0 };
113 int PidLength = 0;
114 int NumPids = 0;
115
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000116 /* Get the filename. */
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +0000117 const char *Filename = __llvm_profile_CurrentFilename;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000118#define UPDATE_FILENAME(NextFilename) \
119 if (!Filename || !Filename[0]) Filename = NextFilename
120 UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE"));
Duncan P. N. Exon Smith21b98a62014-03-24 21:53:42 +0000121 UPDATE_FILENAME("default.profraw");
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000122#undef UPDATE_FILENAME
123
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000124 /* Check the filename for "%p", which indicates a pid-substitution. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000125 for (I = 0; Filename[I]; ++I)
126 if (Filename[I] == '%' && Filename[++I] == 'p')
127 if (!NumPids++) {
128 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
129 if (PidLength <= 0)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000130 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000131 }
132 if (NumPids) {
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000133 /* Allocate enough space for the substituted filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000134 AllocatedFilename = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
135 if (!AllocatedFilename)
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000136 return -1;
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000137
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000138 /* Construct the new filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000139 for (I = 0, J = 0; Filename[I]; ++I)
140 if (Filename[I] == '%') {
141 if (Filename[++I] == 'p') {
142 memcpy(AllocatedFilename + J, PidChars, PidLength);
143 J += PidLength;
144 }
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000145 /* Drop any unknown substitutions. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000146 } else
147 AllocatedFilename[J++] = Filename[I];
148 AllocatedFilename[J] = 0;
149
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000150 /* Actually use the computed name. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000151 Filename = AllocatedFilename;
152 }
153
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000154 /* Write the file. */
155 RetVal = writeFileWithName(Filename);
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000156
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000157 /* Free the filename. */
Duncan P. N. Exon Smithe5edc882014-03-21 00:27:48 +0000158 if (AllocatedFilename)
159 free(AllocatedFilename);
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000160
161 return RetVal;
Duncan P. N. Exon Smith54cc0e22014-03-20 19:23:55 +0000162}
163
Duncan P. N. Exon Smith4543aac2014-03-21 00:27:50 +0000164static void writeFileWithoutReturn(void) {
165 __llvm_profile_write_file();
166}
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000167
Duncan P. N. Exon Smith08439882014-05-16 01:30:24 +0000168__attribute__((weak)) int __llvm_profile_register_write_file_atexit(void) {
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000169 static int HasBeenRegistered = 0;
170
Duncan P. N. Exon Smithbe0a5e12014-03-21 18:29:15 +0000171 if (HasBeenRegistered)
172 return 0;
173
174 HasBeenRegistered = 1;
175 return atexit(writeFileWithoutReturn);
Duncan P. N. Exon Smith8353a262014-03-19 22:10:27 +0000176}