2 * (c)2006 Galois Connections, Inc.
5 #include "PosixSource.h"
17 #ifdef HAVE_SYS_TYPES_H
18 #include <sys/types.h>
21 #ifdef HAVE_SYS_STAT_H
30 /* This is the runtime support for the Haskell Program Coverage (hpc) toolkit,
35 static int hpc_inited = 0; // Have you started this component?
36 static pid_t hpc_pid = 0; // pid of this process at hpc-boot time.
37 // Only this pid will read or write .tix file(s).
38 static FILE *tixFile; // file being read/written
39 static int tix_ch; // current char
41 static HashTable * moduleHash = NULL; // module name -> HpcModuleInfo
43 HpcModuleInfo *modules = 0;
45 static char *tixFilename = NULL;
47 static void GNU_ATTRIBUTE(__noreturn__)
49 debugTrace(DEBUG_hpc,"hpc failure: %s\n",msg);
50 fprintf(stderr,"Hpc failure: %s\n",msg);
52 fprintf(stderr,"(perhaps remove %s file?)\n",tixFilename);
54 fprintf(stderr,"(perhaps remove .tix file?)\n");
59 static int init_open(FILE *file) {
64 tix_ch = getc(tixFile);
68 static void expect(char c) {
70 fprintf(stderr,"('%c' '%c')\n",tix_ch,c);
71 failure("parse error when reading .tix file");
73 tix_ch = getc(tixFile);
76 static void ws(void) {
77 while (tix_ch == ' ') {
78 tix_ch = getc(tixFile);
82 static char *expectString(void) {
83 char tmp[256], *res; // XXX
86 while (tix_ch != '"') {
87 tmp[tmp_ix++] = tix_ch;
88 tix_ch = getc(tixFile);
92 res = stgMallocBytes(tmp_ix,"Hpc.expectString");
97 static StgWord64 expectWord64(void) {
99 while (isdigit(tix_ch)) {
100 tmp = tmp * 10 + (tix_ch -'0');
101 tix_ch = getc(tixFile);
109 HpcModuleInfo *tmpModule, *lookup;
119 while(tix_ch != ']') {
120 tmpModule = (HpcModuleInfo *)stgMallocBytes(sizeof(HpcModuleInfo),
122 tmpModule->from_file = rtsTrue;
133 tmpModule -> modName = expectString();
135 tmpModule -> hashNo = (unsigned int)expectWord64();
137 tmpModule -> tickCount = (int)expectWord64();
138 tmpModule -> tixArr = (StgWord64 *)calloc(tmpModule->tickCount,sizeof(StgWord64));
142 for(i = 0;i < tmpModule->tickCount;i++) {
143 tmpModule->tixArr[i] = expectWord64();
153 lookup = lookupHashTable(moduleHash, (StgWord)tmpModule->modName);
154 if (tmpModule == NULL) {
155 debugTrace(DEBUG_hpc,"readTix: new HpcModuleInfo for %s",
157 insertHashTable(moduleHash, (StgWord)tmpModule->modName, tmpModule);
159 ASSERT(lookup->tixArr != 0);
160 ASSERT(!strcmp(tmpModule->modName, lookup->modName));
161 debugTrace(DEBUG_hpc,"readTix: existing HpcModuleInfo for %s",
163 if (tmpModule->hashNo != lookup->hashNo) {
164 fprintf(stderr,"in module '%s'\n",tmpModule->modName);
165 failure("module mismatch with .tix/.mix file hash number");
166 if (tixFilename != NULL) {
167 fprintf(stderr,"(perhaps remove %s ?)\n",tixFilename);
169 stg_exit(EXIT_FAILURE);
171 for (i=0; i < tmpModule->tickCount; i++) {
172 lookup->tixArr[i] = tmpModule->tixArr[i];
174 stgFree(tmpModule->tixArr);
175 stgFree(tmpModule->modName);
194 if (moduleHash == NULL) {
195 // no modules were registered with hs_hpc_module, so don't bother
196 // creating the .tix file.
200 if (hpc_inited != 0) {
205 hpc_tixdir = getenv("HPCTIXDIR");
206 hpc_tixfile = getenv("HPCTIXFILE");
208 debugTrace(DEBUG_hpc,"startupHpc");
210 /* XXX Check results of mallocs/strdups, and check we are requesting
212 if (hpc_tixfile != NULL) {
213 tixFilename = strdup(hpc_tixfile);
214 } else if (hpc_tixdir != NULL) {
215 /* Make sure the directory is present;
216 * conditional code for mkdir lifted from lndir.c
221 mkdir(hpc_tixdir,0777);
223 /* Then, try open the file
225 tixFilename = (char *) stgMallocBytes(strlen(hpc_tixdir) +
226 strlen(prog_name) + 12,
228 sprintf(tixFilename,"%s/%s-%d.tix",hpc_tixdir,prog_name,(int)hpc_pid);
230 tixFilename = (char *) stgMallocBytes(strlen(prog_name) + 6,
232 sprintf(tixFilename, "%s.tix", prog_name);
235 if (init_open(fopen(tixFilename,"r"))) {
241 * Called on a per-module basis, by a constructor function compiled
242 * with each module (see Coverage.hpcInitCode), declaring where the
243 * tix boxes are stored in memory. This memory can be uninitized,
244 * because we will initialize it with either the contents of the tix
245 * file, or all zeros.
247 * Note that we might call this before reading the .tix file, or after
248 * in the case where we loaded some Haskell code from a .so with
249 * dlopen(). So we must handle the case where we already have an
250 * HpcModuleInfo for the module which was read from the .tix file.
254 hs_hpc_module(char *modName,
259 HpcModuleInfo *tmpModule;
262 if (moduleHash == NULL) {
263 moduleHash = allocStrHashTable();
266 tmpModule = lookupHashTable(moduleHash, (StgWord)modName);
267 if (tmpModule == NULL)
269 // Did not find entry so add one on.
270 tmpModule = (HpcModuleInfo *)stgMallocBytes(sizeof(HpcModuleInfo),
271 "Hpc.hs_hpc_module");
272 tmpModule->modName = modName;
273 tmpModule->tickCount = modCount;
274 tmpModule->hashNo = modHashNo;
276 tmpModule->tixArr = tixArr;
277 for(i=0;i < modCount;i++) {
280 tmpModule->next = modules;
281 tmpModule->from_file = rtsFalse;
283 insertHashTable(moduleHash, (StgWord)modName, tmpModule);
287 if (tmpModule->tickCount != modCount) {
288 failure("inconsistent number of tick boxes");
290 ASSERT(tmpModule->tixArr != 0);
291 if (tmpModule->hashNo != modHashNo) {
292 fprintf(stderr,"in module '%s'\n",tmpModule->modName);
293 failure("module mismatch with .tix/.mix file hash number");
294 if (tixFilename != NULL) {
295 fprintf(stderr,"(perhaps remove %s ?)\n",tixFilename);
297 stg_exit(EXIT_FAILURE);
299 // The existing tixArr was made up when we read the .tix file,
300 // whereas this is the real tixArr, so copy the data from the
301 // .tix into the real tixArr.
302 for(i=0;i < modCount;i++) {
303 tixArr[i] = tmpModule->tixArr[i];
306 if (tmpModule->from_file) {
307 stgFree(tmpModule->modName);
308 stgFree(tmpModule->tixArr);
310 tmpModule->from_file = rtsFalse;
316 HpcModuleInfo *tmpModule;
317 unsigned int i, inner_comma, outer_comma;
327 for(;tmpModule != 0;tmpModule = tmpModule->next) {
333 fprintf(f," TixModule \"%s\" %u %u [",
335 (nat)tmpModule->hashNo,
336 (nat)tmpModule->tickCount);
337 debugTrace(DEBUG_hpc,"%s: %u (hash=%u)\n",
339 (nat)tmpModule->tickCount,
340 (nat)tmpModule->hashNo);
343 for(i = 0;i < tmpModule->tickCount;i++) {
350 if (tmpModule->tixArr) {
351 fprintf(f,"%" FMT_Word64,tmpModule->tixArr[i]);
364 freeHpcModuleInfo (HpcModuleInfo *mod)
366 if (mod->from_file) {
367 stgFree(mod->modName);
368 stgFree(mod->tixArr);
373 /* Called at the end of execution, to write out the Hpc *.tix file
374 * for this exection. Safe to call, even if coverage is not used.
378 debugTrace(DEBUG_hpc,"exitHpc");
380 if (hpc_inited == 0) {
384 // Only write the tix file if you are the original process.
385 // Any sub-process from use of fork from inside Haskell will
386 // not clober the .tix file.
388 if (hpc_pid == getpid()) {
389 FILE *f = fopen(tixFilename,"w");
393 freeHashTable(moduleHash, (void (*)(void *))freeHpcModuleInfo);
396 stgFree(tixFilename);
400 //////////////////////////////////////////////////////////////////////////////
401 // This is the API into Hpc RTS from Haskell, allowing the tixs boxes
402 // to be first class.
404 HpcModuleInfo *hs_hpc_rootModule(void) {