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