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