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