Changing Main.tix to <prog_name>.tix in the Hpc RTS
[ghc.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