Cleanup Hpc sub-system, remove hpc-tracer implementation.
[ghc.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