Misc unsigned printing issues; adding magicTixNumber.
[ghc-hetmet.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