Have configure take arguments telling it where gmp is; fixes trac #957
[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 int totalTickCount = 0;          // How many ticks have we got to work with
29 static FILE *tixFile;                   // file being read/written
30 static int tix_ch;                      // current char
31 static StgWord64 magicTixNumber;        // Magic/Hash number to mark .tix files
32
33 static FILE *rixFile = NULL;            // The tracer file/pipe (to debugger)
34 static FILE *rixCmdFile = NULL;         // The tracer file/pipe (from debugger)
35 static StgWord64 rixCounter = 0;        // The global event counter
36 static int debuggee_pid;
37
38 typedef enum {
39   RixThreadFinishedOp   = -1,
40   RixRaiseOp            = -2,
41   RixFinishedOp         = -3
42 } HpcRixOp;
43
44
45 typedef struct _Info {
46   char *modName;                // name of module
47   int tickCount;                // number of ticks
48   int tickOffset;               // offset into a single large .tix Array
49   StgWord64 *tixArr;            // tix Array from the program execution (local for this module)
50   struct _Info *next;
51 } Info;
52
53 // This is a cruel hack, we should completely redesign the format specifier handling in the RTS.
54 #if SIZEOF_LONG == 8
55 #define PRIuWORD64 "lu"
56 #else
57 #define PRIuWORD64 "llu"
58 #endif
59
60 Info *modules = 0;
61 Info *nextModule = 0;
62 StgWord64 *tixBoxes = 0;        // local copy of tixBoxes array, from file.
63 int totalTixes = 0;             // total number of tix boxes.
64
65 static char *tixFilename;
66
67 static void failure(char *msg) {
68   debugTrace(DEBUG_hpc,"hpc failure: %s\n",msg);
69   fprintf(stderr,"Hpc failure: %s\n",msg);
70   fprintf(stderr,"(perhaps remove .tix file?)\n");
71   exit(-1);
72 }
73
74 static int init_open(char *filename) 
75 {
76   tixFile = fopen(filename,"r");
77  if (tixFile == 0) {
78     return 0;
79   }
80   tix_ch = getc(tixFile);
81   return 1;
82 }
83
84 static void expect(char c) {
85   if (tix_ch != c) {
86     failure("parse error when reading .tix file");
87   }
88   tix_ch = getc(tixFile);
89 }
90
91 static void ws(void) {
92   while (tix_ch == ' ') {
93     tix_ch = getc(tixFile);
94   }
95 }
96
97 static char *expectString(void) {
98   char tmp[256], *res;
99   int tmp_ix = 0;
100   expect('"');
101   while (tix_ch != '"') {
102     tmp[tmp_ix++] = tix_ch;
103     tix_ch = getc(tixFile);
104   }
105   tmp[tmp_ix++] = 0;
106   expect('"');
107   res = malloc(tmp_ix);
108   strcpy(res,tmp);
109   return res;
110 }
111
112 static StgWord64 expectWord64(void) {
113   StgWord64 tmp = 0;
114   while (isdigit(tix_ch)) {
115     tmp = tmp * 10 + (tix_ch -'0');
116     tix_ch = getc(tixFile);
117   }
118   return tmp;
119 }
120
121 static void hpc_init(void) {
122   int i;
123   Info *tmpModule;  
124
125   if (hpc_inited != 0) {
126     return;
127   }
128   hpc_inited = 1;
129   
130
131   tixFilename = (char *) malloc(strlen(prog_name) + 6);
132   sprintf(tixFilename, "%s.tix", prog_name);
133
134   if (init_open(tixFilename)) { 
135     totalTixes = 0;
136
137     ws();
138     expect('T');
139     expect('i');
140     expect('x');
141     ws();
142     magicTixNumber = expectWord64();
143     ws();
144     expect('[');
145     ws();
146     while(tix_ch != ']') {
147       tmpModule = (Info *)calloc(1,sizeof(Info));
148       expect('(');
149       ws();
150       tmpModule -> modName = expectString();
151       ws();
152       expect(',');
153       ws();
154       tmpModule -> tickCount = (int)expectWord64();
155       ws();
156       expect(')');
157       ws();
158       
159       tmpModule -> tickOffset = totalTixes;
160       totalTixes += tmpModule -> tickCount;
161       
162       tmpModule -> tixArr = 0;
163       
164       if (!modules) {
165         modules = tmpModule;
166       } else {
167         nextModule->next=tmpModule;
168       }
169       nextModule=tmpModule;
170       
171       if (tix_ch == ',') {
172         expect(',');
173         ws();
174       }
175     }
176     expect(']');
177     ws();
178     tixBoxes = (StgWord64 *)calloc(totalTixes,sizeof(StgWord64));
179
180     expect('[');
181     for(i = 0;i < totalTixes;i++) {
182       if (i != 0) {
183         expect(',');
184         ws();
185       }
186     tixBoxes[i] = expectWord64();
187     ws();
188     }
189     expect(']');
190
191     fclose(tixFile);
192   } else {
193     // later, we will find a binary specific 
194     magicTixNumber = (StgWord64)0;
195   }
196 }
197
198 /* Called on a per-module basis, at startup time, declaring where the tix boxes are stored in memory.
199  * This memory can be uninitized, because we will initialize it with either the contents
200  * of the tix file, or all zeros.
201  */
202
203 int
204 hs_hpc_module(char *modName,int modCount,StgWord64 *tixArr) {
205   Info *tmpModule, *lastModule;
206   int i;
207   int offset = 0;
208   
209   debugTrace(DEBUG_hpc,"hs_hpc_module(%s,%d)",modName,modCount);
210
211   hpc_init();
212
213   tmpModule = modules;
214   lastModule = 0;
215   
216   for(;tmpModule != 0;tmpModule = tmpModule->next) {
217     if (!strcmp(tmpModule->modName,modName)) {
218       if (tmpModule->tickCount != modCount) {
219         failure("inconsistent number of tick boxes");
220       }
221       assert(tmpModule->tixArr == 0);   
222       assert(tixBoxes != 0);
223       tmpModule->tixArr = tixArr;
224       for(i=0;i < modCount;i++) {
225         tixArr[i] = tixBoxes[i + tmpModule->tickOffset];
226       }
227       return tmpModule->tickOffset;
228     }
229     lastModule = tmpModule;
230   }
231   // Did not find entry so add one on.
232   tmpModule = (Info *)calloc(1,sizeof(Info));
233   tmpModule->modName = modName;
234   tmpModule->tickCount = modCount;
235   if (lastModule) {
236     tmpModule->tickOffset = lastModule->tickOffset + lastModule->tickCount;
237   } else {
238     tmpModule->tickOffset = 0;
239   }
240   tmpModule->tixArr = tixArr;
241   for(i=0;i < modCount;i++) {
242     tixArr[i] = 0;
243   }
244   tmpModule->next = 0;
245
246   if (!modules) {
247     modules = tmpModule;
248   } else {
249     lastModule->next=tmpModule;
250   }
251
252   debugTrace(DEBUG_hpc,"end: hs_hpc_module");
253
254   return offset;
255 }
256
257 static void breakPointCommand(HpcRixOp rixOp, StgThreadID rixTid);
258
259 // Breakpointing
260 static StgThreadID previousTid = 0;
261 static StgWord64 rixBPCounter = 0;      // The global event breakpoint counter
262 static int *tixBoxBP;
263 static HpcRixOp rixOpBack[WOP_SIZE];    // The actual op
264 static HpcRixOp rixTidBack[WOP_SIZE];   // Tid's before the op
265
266 void 
267 hs_hpc_raise_event(StgTSO *current_tso) {
268   hs_hpc_tick(RixRaiseOp,current_tso);
269 }
270
271 void 
272 hs_hpc_thread_finished_event(StgTSO *current_tso) {
273   hs_hpc_tick(RixThreadFinishedOp,current_tso);
274 }
275
276 /* Called on every tick, dynamically, sending to our 
277  * external record of program execution.
278  */
279
280 void
281 hs_hpc_tick(int rixOp, StgTSO *current_tso) {
282
283   debugTrace(DEBUG_hpc,"hs_hpc_tick(%x)",rixOp);
284
285   if (rixFile == NULL) {
286     return;
287   }
288   assert(rixCmdFile != NULL);
289   StgThreadID tid = (current_tso == 0) ? 0 : current_tso->id;
290
291   // now check to see if we have met a breakpoint condition
292   if (rixCounter == rixBPCounter 
293       || tid != previousTid) {
294     breakPointCommand(rixOp,tid);
295   } else {
296     if (rixOp >= 0) {
297       // Tix op
298       if (tixBoxBP[rixOp] == 1) {       // reached a bp tixbox
299           breakPointCommand(rixOp,tid);
300       }
301     } else {
302       // record the special operation
303       breakPointCommand(rixOp,tid);
304     }
305   }
306   // update the history information.
307   previousTid = tid;
308   rixOpBack[rixCounter % WOP_SIZE]  = rixOp;
309   rixTidBack[rixCounter % WOP_SIZE] = tid;
310   rixCounter++;
311
312   debugTrace(DEBUG_hpc, "end: hs_hpc_tick");
313 }
314
315 static void 
316 printEvent(FILE *out,StgWord64 rixCounter,StgThreadID rixTid,HpcRixOp rixOp) {
317   char prefixMsg[128];
318   char suffixMsg[128];
319
320   sprintf(prefixMsg,
321           "Event %" PRIuWORD64 " %u ",
322           rixCounter,
323           (unsigned int)rixTid);
324
325   switch(rixOp) {
326   case RixThreadFinishedOp:
327     sprintf(suffixMsg,"ThreadFinished");
328     break;
329   case RixRaiseOp:
330     sprintf(suffixMsg,"Raise");
331     break;
332   case RixFinishedOp:
333     sprintf(suffixMsg,"Finished");
334     break;
335   default:
336     sprintf(suffixMsg,"%u",rixOp);
337   }
338
339   fprintf(out,"%s%s\n",prefixMsg,suffixMsg);
340   debugTrace(DEBUG_hpc,"sending %s%s",prefixMsg,suffixMsg);
341 }
342
343 static void
344 breakPointCommand(HpcRixOp rixOp, StgThreadID rixTid) {
345   StgWord64 tmp64 = 0;
346   unsigned int tmp = 0;
347
348   if (getpid() != debuggee_pid) {
349     // We are not the original process, to do not issue 
350     // any events, and do not try to talk to the debugger.
351     return;
352   }
353
354   debugTrace(DEBUG_hpc,"breakPointCommand %d %x",rixOp,(unsigned int)rixTid);
355
356   printEvent(rixFile,rixCounter,rixTid,rixOp);
357   fflush(rixFile);
358
359   /* From here, you can ask some basic questions.
360    * 
361    *  c<nat>            set the (one) counter breakpoint
362    *  s<nat>            set the (many) tickbox breakpoint
363    *  u<nat>            unset the (many) tickbox breakpoint
364    *  h                 history
365
366    * Note that you aways end up here on the first tick
367    * because the rixBPCounter starts equal to 0.
368    */
369   int c = getc(rixCmdFile);
370   while(c != 10 && c != -1) {
371     switch(c) {
372     case 'c': // c1234  -- set counter breakpoint at 1234
373       c = getc(rixCmdFile);
374       tmp64 = 0;
375       while(isdigit(c)) {
376         tmp64 = tmp64 * 10 + (c - '0');
377         c = getc(rixCmdFile);
378       }
379       debugTrace(DEBUG_hpc,"setting countBP = %" PRIuWORD64,tmp64);
380
381       rixBPCounter = tmp64;
382       break;
383     case 's': // s2323  -- set tick box breakpoint at 2323
384       c = getc(rixCmdFile);
385       tmp = 0;
386       while(isdigit(c)) {
387         tmp = tmp * 10 + (c - '0');
388         c = getc(rixCmdFile);
389       }
390
391       debugTrace(DEBUG_hpc,"seting bp for tix %d",tmp);
392
393       tixBoxBP[tmp] = 1;
394       break;
395     case 'u': // u2323  -- unset tick box breakpoint at 2323
396       c = getc(rixCmdFile);
397       tmp = 0;
398       while(isdigit(c)) {
399         tmp = tmp * 10 + (c - '0');
400         c = getc(rixCmdFile);
401       }
402
403       debugTrace(DEBUG_hpc,"unseting bp for tix %d",tmp);
404
405       tixBoxBP[tmp] = 0;
406       break;
407     case 'h': // h -- history of the last few (WOP_SIZE) steps 
408       if (rixCounter > WOP_SIZE) {
409         tmp64 = rixCounter - WOP_SIZE;
410       } else {
411         tmp64 = 0;
412       }
413       for(;tmp64 < rixCounter;tmp64++) {
414         printEvent(rixFile,
415                    tmp64,
416                    rixTidBack[tmp64 % WOP_SIZE],
417                    rixOpBack[tmp64 % WOP_SIZE]);
418       }
419       fflush(rixFile);
420       c = getc(rixCmdFile);
421       break;
422     default:
423
424       debugTrace(DEBUG_hpc,"strange command from HPCRIX (%d)",c);
425
426       c = getc(rixCmdFile);
427     }
428     while (c != 10) {          // the end of the line
429         c = getc(rixCmdFile); // to the end of the line
430     }
431     c = getc(rixCmdFile); // the first char on the next command
432   }
433
434   debugTrace(DEBUG_hpc,"leaving breakPointCommand");
435
436 }
437
438 /* This is called after all the modules have registered their local tixboxes,
439  * and does a sanity check: are we good to go?
440  */
441
442 void
443 startupHpc(void) {
444   Info *tmpModule;
445   char *hpcRix;
446
447   debugTrace(DEBUG_hpc,"startupHpc");
448  
449  if (hpc_inited == 0) {
450     return;
451   }
452
453   tmpModule = modules;
454
455   if (tixBoxes) {
456     for(;tmpModule != 0;tmpModule = tmpModule->next) {
457       totalTickCount += tmpModule->tickCount;
458       if (!tmpModule->tixArr) {
459         fprintf(stderr,"error: module %s did not register any hpc tick data\n",
460                 tmpModule->modName);
461         fprintf(stderr,"(perhaps remove %s ?)\n",tixFilename);
462         exit(-1);
463       }
464     }
465   }
466
467   // HPCRIX contains the name of the file to send our dynamic runtime output to (a named pipe).
468
469   hpcRix = getenv("HPCRIX");
470   if (hpcRix) {
471     int comma;
472     Info *tmpModule;  
473     int rixFD, rixCmdFD;
474     int tixCount = 0;
475
476     assert(hpc_inited);
477
478     if (sscanf(hpcRix,"%d:%d",&rixFD,&rixCmdFD) != 2) {
479       /* Bad format for HPCRIX.
480        */
481       debugTrace(DEBUG_hpc,"Bad HPCRIX (%s)",hpcRix);
482       exit(0);
483     }
484
485     debugTrace(DEBUG_hpc,"found HPCRIX pipes: %d:%d",rixFD,rixCmdFD);
486
487     rixFile = fdopen(rixFD,"w");
488     assert(rixFile != NULL);
489
490     rixCmdFile = fdopen(rixCmdFD,"r");
491     assert(rixCmdFile != NULL);
492
493     // If we fork a process, then we do not want ticks inside
494     // the sub-process to talk to the debugger. So we remember
495     // our pid at startup time, so we can check if we are still
496     // the original process.
497
498     debuggee_pid = getpid();
499
500     comma = 0;
501     
502     fprintf(rixFile,"Starting %s\n",prog_name);
503     fprintf(rixFile,"[");
504     tmpModule = modules;
505     for(;tmpModule != 0;tmpModule = tmpModule->next) {
506       if (comma) {
507         fprintf(rixFile,",");
508       } else {
509         comma = 1;
510       }
511       fprintf(rixFile,"(\"%s\",%u)",
512               tmpModule->modName,
513               tmpModule->tickCount);
514
515       tixCount += tmpModule->tickCount;
516
517       debugTrace(DEBUG_hpc,"(tracer)%s: %u (offset=%u)\n",
518               tmpModule->modName,
519               tmpModule->tickCount,
520               tmpModule->tickOffset);
521
522     }
523     fprintf(rixFile,"]\n");
524     fflush(rixFile);
525
526     // Allocate the tixBox breakpoint array
527     // These are set to 1 if you want to 
528     // stop at a specific breakpoint
529     tixBoxBP = (int *)calloc(tixCount,sizeof(int));
530   }
531
532 }
533
534
535 /* Called at the end of execution, to write out the Hpc *.tix file  
536  * for this exection. Safe to call, even if coverage is not used.
537  */
538 void
539 exitHpc(void) {
540   Info *tmpModule;  
541   int i, comma;
542
543   debugTrace(DEBUG_hpc,"exitHpc");
544
545   if (hpc_inited == 0) {
546     return;
547   }
548
549   FILE *f = fopen(tixFilename,"w");
550   
551   comma = 0;
552
553   fprintf(f,"Tix %" PRIuWORD64 " [", magicTixNumber);
554   tmpModule = modules;
555   for(;tmpModule != 0;tmpModule = tmpModule->next) {
556     if (comma) {
557       fprintf(f,",");
558     } else {
559       comma = 1;
560     }
561     fprintf(f,"(\"%s\",%u)",
562            tmpModule->modName,
563             tmpModule->tickCount);
564     debugTrace(DEBUG_hpc,"%s: %u (offset=%u)\n",
565            tmpModule->modName,
566            tmpModule->tickCount,
567            tmpModule->tickOffset);
568   }
569   fprintf(f,"] [");
570   
571   comma = 0;
572   tmpModule = modules;
573   for(;tmpModule != 0;tmpModule = tmpModule->next) {
574       if (!tmpModule->tixArr) {
575         debugTrace(DEBUG_hpc,
576                    "warning: module %s did not register any hpc tick data\n",
577                    tmpModule->modName);
578       }
579
580     for(i = 0;i < tmpModule->tickCount;i++) {
581       if (comma) {
582         fprintf(f,",");
583       } else {
584         comma = 1;
585       }
586
587       if (tmpModule->tixArr) {
588         fprintf(f,"%" PRIuWORD64,tmpModule->tixArr[i]);
589       } else {
590         fprintf(f,"0");
591       }
592
593     }
594   }
595       
596   fprintf(f,"]\n");
597   fclose(f);
598
599   if (rixFile != NULL) {
600     hs_hpc_tick(RixFinishedOp,(StgThreadID)0);
601     fclose(rixFile);
602   }
603   if (rixCmdFile != NULL) {
604     fclose(rixCmdFile);
605   }
606   
607 }
608