InstrProfilingFile.c revision 1.1.1.1.2.2 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 <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 static int writeFile(FILE *File) {
16 /* Match logic in __llvm_profile_write_buffer(). */
17 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;
28
29 /* Create the header. */
30 uint64_t Header[PROFILE_HEADER_SIZE];
31 Header[0] = __llvm_profile_get_magic();
32 Header[1] = __llvm_profile_get_version();
33 Header[2] = DataSize;
34 Header[3] = CountersSize;
35 Header[4] = NamesSize;
36 Header[5] = (uintptr_t)CountersBegin;
37 Header[6] = (uintptr_t)NamesBegin;
38
39 /* Write the data. */
40 #define CHECK_fwrite(Data, Size, Length, File) \
41 do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
42 CHECK_fwrite(Header, sizeof(uint64_t), PROFILE_HEADER_SIZE, File);
43 CHECK_fwrite(DataBegin, sizeof(__llvm_profile_data), DataSize, File);
44 CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
45 CHECK_fwrite(NamesBegin, sizeof(char), NamesSize, File);
46 #undef CHECK_fwrite
47
48 return 0;
49 }
50
51 static int writeFileWithName(const char *OutputName) {
52 int RetVal;
53 FILE *OutputFile;
54 if (!OutputName || !OutputName[0])
55 return -1;
56 OutputFile = fopen(OutputName, "w");
57 if (!OutputFile)
58 return -1;
59
60 RetVal = writeFile(OutputFile);
61
62 fclose(OutputFile);
63 return RetVal;
64 }
65
66 static const char *CurrentFilename = NULL;
67 void __llvm_profile_set_filename(const char *Filename) {
68 CurrentFilename = Filename;
69 }
70
71 int getpid(void);
72 int __llvm_profile_write_file(void) {
73 char *AllocatedFilename = NULL;
74 int I, J;
75 int RetVal;
76
77 #define MAX_PID_SIZE 16
78 char PidChars[MAX_PID_SIZE] = { 0 };
79 int PidLength = 0;
80 int NumPids = 0;
81
82 /* Get the filename. */
83 const char *Filename = CurrentFilename;
84 #define UPDATE_FILENAME(NextFilename) \
85 if (!Filename || !Filename[0]) Filename = NextFilename
86 UPDATE_FILENAME(getenv("LLVM_PROFILE_FILE"));
87 UPDATE_FILENAME("default.profraw");
88 #undef UPDATE_FILENAME
89
90 /* Check the filename for "%p", which indicates a pid-substitution. */
91 for (I = 0; Filename[I]; ++I)
92 if (Filename[I] == '%' && Filename[++I] == 'p')
93 if (!NumPids++) {
94 PidLength = snprintf(PidChars, MAX_PID_SIZE, "%d", getpid());
95 if (PidLength <= 0)
96 return -1;
97 }
98 if (NumPids) {
99 /* Allocate enough space for the substituted filename. */
100 AllocatedFilename = (char*)malloc(I + NumPids*(PidLength - 2) + 1);
101 if (!AllocatedFilename)
102 return -1;
103
104 /* Construct the new filename. */
105 for (I = 0, J = 0; Filename[I]; ++I)
106 if (Filename[I] == '%') {
107 if (Filename[++I] == 'p') {
108 memcpy(AllocatedFilename + J, PidChars, PidLength);
109 J += PidLength;
110 }
111 /* Drop any unknown substitutions. */
112 } else
113 AllocatedFilename[J++] = Filename[I];
114 AllocatedFilename[J] = 0;
115
116 /* Actually use the computed name. */
117 Filename = AllocatedFilename;
118 }
119
120 /* Write the file. */
121 RetVal = writeFileWithName(Filename);
122
123 /* Free the filename. */
124 if (AllocatedFilename)
125 free(AllocatedFilename);
126
127 return RetVal;
128 }
129
130 static void writeFileWithoutReturn(void) {
131 __llvm_profile_write_file();
132 }
133
134 int __llvm_profile_register_write_file_atexit(void) {
135 static int HasBeenRegistered = 0;
136
137 if (HasBeenRegistered)
138 return 0;
139
140 HasBeenRegistered = 1;
141 return atexit(writeFileWithoutReturn);
142 }
143