Misc unsigned printing issues; adding magicTixNumber.
[ghc.git] / rts / Hpc.c
1 /*
2 * (c)2006 Galois Connections, Inc.
3 */
4
5 // #include "HsFFI.h"
6
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <assert.h>
12 #include "HsFFI.h"
13 #include "Rts.h"
14 #include "Hpc.h"
15
16 /* This is the runtime support for the Haskell Program Coverage (hpc) toolkit,
17 * inside GHC.
18 *
19 */
20
21 #define DEBUG_HPC 0
22
23 static int hpc_inited = 0; // Have you started this component?
24 static FILE *tixFile; // file being read/written
25 static int tix_ch; // current char
26 static StgWord64 magicTixNumber; // Magic/Hash number to mark .tix files
27
28 typedef struct _Info {
29 char *modName; // name of module
30 int tickCount; // number of ticks
31 int tickOffset; // offset into a single large .tix Array
32 StgWord64 *tixArr; // tix Array from the program execution (local for this module)
33 struct _Info *next;
34 } Info;
35
36 // This is a cruel hack, we should completely redesign the format specifier handling in the RTS.
37 #if SIZEOF_LONG == 8
38 #define PRIuWORD64 "lu"
39 #else
40 #define PRIuWORD64 "llu"
41 #endif
42
43 Info *modules = 0;
44 Info *nextModule = 0;
45 StgWord64 *tixBoxes = 0; // local copy of tixBoxes array, from file.
46 int totalTixes = 0; // total number of tix boxes.
47
48
49
50 static char *tixFilename;
51
52 static void failure(char *msg) {
53 printf("Hpc failure: %s\n",msg);
54 printf("(perhaps remove .tix file?)\n");
55 exit(-1);
56 }
57
58
59 static int init_open(char *filename)
60 {
61 tixFile = fopen(filename,"r");
62 if (tixFile == 0) {
63 return 0;
64 }
65 tix_ch = getc(tixFile);
66 return 1;
67 }
68
69 static void expect(char c) {
70 if (tix_ch != c) {
71 printf("Hpc: parse failed (%c,%c)\n",tix_ch,c);
72 exit(-1);
73 }
74 tix_ch = getc(tixFile);
75 }
76
77 static void ws(void) {
78 while (tix_ch == ' ') {
79 tix_ch = getc(tixFile);
80 }
81 }
82
83 static char *expectString(void) {
84 char tmp[256], *res;
85 int tmp_ix = 0;
86 expect('"');
87 while (tix_ch != '"') {
88 tmp[tmp_ix++] = tix_ch;
89 tix_ch = getc(tixFile);
90 }
91 tmp[tmp_ix++] = 0;
92 expect('"');
93 res = malloc(tmp_ix);
94 strcpy(res,tmp);
95 return res;
96 }
97
98 static StgWord64 expectWord64(void) {
99 StgWord64 tmp = 0;
100 while (isdigit(tix_ch)) {
101 tmp = tmp * 10 + (tix_ch -'0');
102 tix_ch = getc(tixFile);
103 }
104 return tmp;
105 }
106
107 static void hpc_init(void) {
108 int i;
109 Info *tmpModule;
110
111 if (hpc_inited != 0) {
112 return;
113 }
114 hpc_inited = 1;
115
116
117 tixFilename = (char *) malloc(strlen(prog_name) + 6);
118 sprintf(tixFilename, "%s.tix", prog_name);
119
120 if (init_open(tixFilename)) {
121 totalTixes = 0;
122
123 ws();
124 expect('T');
125 expect('i');
126 expect('x');
127 ws();
128 magicTixNumber = expectWord64();
129 ws();
130 expect('[');
131 ws();
132 while(tix_ch != ']') {
133 tmpModule = (Info *)calloc(1,sizeof(Info));
134 expect('(');
135 ws();
136 tmpModule -> modName = expectString();
137 ws();
138 expect(',');
139 ws();
140 tmpModule -> tickCount = (int)expectWord64();
141 ws();
142 expect(')');
143 ws();
144
145 tmpModule -> tickOffset = totalTixes;
146 totalTixes += tmpModule -> tickCount;
147
148 tmpModule -> tixArr = 0;
149
150 if (!modules) {
151 modules = tmpModule;
152 } else {
153 nextModule->next=tmpModule;
154 }
155 nextModule=tmpModule;
156
157 if (tix_ch == ',') {
158 expect(',');
159 ws();
160 }
161 }
162 expect(']');
163 ws();
164 tixBoxes = (StgWord64 *)calloc(totalTixes,sizeof(StgWord64));
165
166 expect('[');
167 for(i = 0;i < totalTixes;i++) {
168 if (i != 0) {
169 expect(',');
170 ws();
171 }
172 tixBoxes[i] = expectWord64();
173 ws();
174 }
175 expect(']');
176
177 fclose(tixFile);
178 } else {
179 // later, we will find a binary specific
180 magicTixNumber = (StgWord64)0;
181 }
182 }
183
184 /* Called on a per-module basis, at startup time, declaring where the tix boxes are stored in memory.
185 * This memory can be uninitized, because we will initialize it with either the contents
186 * of the tix file, or all zeros.
187 */
188
189 void
190 hs_hpc_module(char *modName,int modCount,StgWord64 *tixArr) {
191 Info *tmpModule, *lastModule;
192 int i;
193
194 #if DEBUG_HPC
195 printf("hs_hpc_module(%s,%d)\n",modName,modCount);
196 #endif
197
198 hpc_init();
199
200 tmpModule = modules;
201 lastModule = 0;
202
203 for(;tmpModule != 0;tmpModule = tmpModule->next) {
204 if (!strcmp(tmpModule->modName,modName)) {
205 if (tmpModule->tickCount != modCount) {
206 failure("inconsistent number of tick boxes");
207 }
208 assert(tmpModule->tixArr == 0);
209 assert(tixBoxes != 0);
210 tmpModule->tixArr = tixArr;
211 for(i=0;i < modCount;i++) {
212 tixArr[i] = tixBoxes[i + tmpModule->tickOffset];
213 }
214 return;
215 }
216 lastModule = tmpModule;
217 }
218 // Did not find entry so add one on.
219 tmpModule = (Info *)calloc(1,sizeof(Info));
220 tmpModule->modName = modName;
221 tmpModule->tickCount = modCount;
222 if (lastModule) {
223 tmpModule->tickOffset = lastModule->tickOffset + lastModule->tickCount;
224 } else {
225 tmpModule->tickOffset = 0;
226 }
227 tmpModule->tixArr = tixArr;
228 for(i=0;i < modCount;i++) {
229 tixArr[i] = 0;
230 }
231 tmpModule->next = 0;
232
233 if (!modules) {
234 modules = tmpModule;
235 } else {
236 lastModule->next=tmpModule;
237 }
238
239 #if DEBUG_HPC
240 printf("end: hs_hpc_module\n");
241 #endif
242 }
243
244 /* This is called after all the modules have registered their local tixboxes,
245 * and does a sanity check: are we good to go?
246 */
247
248 void
249 startupHpc(void) {
250 Info *tmpModule;
251 #if DEBUG_HPC
252 printf("startupHpc\n");
253 #endif
254
255 if (hpc_inited == 0) {
256 return;
257 }
258
259 tmpModule = modules;
260
261 if (tixBoxes) {
262 for(;tmpModule != 0;tmpModule = tmpModule->next) {
263 if (!tmpModule->tixArr) {
264 fprintf(stderr,"error: module %s did not register any hpc tick data\n",
265 tmpModule->modName);
266 fprintf(stderr,"(perhaps remove %s ?)\n",tixFilename);
267 exit(-1);
268 }
269 }
270 }
271 }
272
273 /* Called at the end of execution, to write out the Hpc *.tix file
274 * for this exection. Safe to call, even if coverage is not used.
275 */
276 void
277 exitHpc(void) {
278 Info *tmpModule;
279 int i, comma;
280
281 #if DEBUG_HPC
282 printf("exitHpc\n");
283 #endif
284
285 if (hpc_inited == 0) {
286 return;
287 }
288
289 FILE *f = fopen(tixFilename,"w");
290
291 comma = 0;
292
293 fprintf(f,"Tix %" PRIuWORD64 " [", magicTixNumber);
294 tmpModule = modules;
295 for(;tmpModule != 0;tmpModule = tmpModule->next) {
296 if (comma) {
297 fprintf(f,",");
298 } else {
299 comma = 1;
300 }
301 fprintf(f,"(\"%s\",%u)",
302 tmpModule->modName,
303 tmpModule->tickCount);
304 #if DEBUG_HPC
305 fprintf(stderr,"%s: %u (offset=%u)\n",
306 tmpModule->modName,
307 tmpModule->tickCount,
308 tmpModule->tickOffset);
309 #endif
310 }
311 fprintf(f,"] [");
312
313 comma = 0;
314 tmpModule = modules;
315 for(;tmpModule != 0;tmpModule = tmpModule->next) {
316 if (!tmpModule->tixArr) {
317 fprintf(stderr,"warning: module %s did not register any hpc tick data\n",
318 tmpModule->modName);
319 }
320
321 for(i = 0;i < tmpModule->tickCount;i++) {
322 if (comma) {
323 fprintf(f,",");
324 } else {
325 comma = 1;
326 }
327
328 if (tmpModule->tixArr) {
329 fprintf(f,"%" PRIuWORD64,tmpModule->tixArr[i]);
330 } else {
331 fprintf(f,"0");
332 }
333
334 }
335 }
336
337 fprintf(f,"]\n");
338 fclose(f);
339
340 }
341