source: icGREP/icgrep-devel/cudd-2.5.1/mnemosyne/mnemosyne.c @ 6055

Last change on this file since 6055 was 4597, checked in by nmedfort, 4 years ago

Upload of the CUDD library.

File size: 13.5 KB
Line 
1/************************************************************************
2 *                                                                      *
3 *                      Copyright (c) 1985 by                           *
4 *              Digital Equipment Corporation, Maynard, MA              *
5 *                      All rights reserved.                            *
6 *                                                                      *
7 *   The information in this software is subject to change  without     *
8 *   notice  and should not be construed as a commitment by Digital     *
9 *   Equipment Corporation.                                             *
10 *                                                                      *
11 *   Digital assumes no responsibility for the use  or  reliability     *
12 *   of its software on equipment which is not supplied by Digital.     *
13 *                                                                      *
14 *   Redistribution and use in source and binary forms are permitted    *
15 *   provided that the above copyright notice and this paragraph are    *
16 *   duplicated in all such forms and that any documentation,           *
17 *   advertising materials, and other materials related to such         *
18 *   distribution and use acknowledge that the software was developed   *
19 *   by Digital Equipment Corporation. The name of Digital Equipment    *
20 *   Corporation may not be used to endorse or promote products derived *
21 *   from this software without specific prior written permission.      *
22 *   THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR     *
23 *   IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED     *
24 *   WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.*
25 *   Do not take internally. In case of accidental ingestion, contact   *
26 *   your physician immediately.                                        *
27 *                                                                      *
28 ************************************************************************/
29
30/* DO NOT INCLUDE "mnemosyne.h" !!! */
31#include        <stdio.h>
32#include        <sys/types.h>
33#include        <sys/file.h>
34
35/* shared stuff - and decl of struct ptr */
36#include        "mnemconf.h"
37
38static  char    rcsid[] = "/fats/tools/hsv/mnemosyne/mnemosyne.c,v 1.1.1.1 1995/06/06 18:18:28 fabio Exp";
39
40
41/*
42malloc() realloc() and family wrappers - these functions manage a set
43of data files that are updated whenever a pointer is allocated or freed,
44as well as gathering stats about dynamic memory use and leakage.
45
46        Marcus J. Ranum, 1990. (mjr@decuac.dec.com)
47*/
48
49
50/*
51there is some egregious use of globals, void functions, and whatnot
52in this code. it is mostly due to the constraint that nothing must
53be visible to the outside, and that the code must be structurally
54simple. error checking is pitched out the window in spots, since an
55error in the mnemosyne code should not affect whatever is being
56instrumented if at all possible. this means no errors, no signals,
57nothing. (this message brought to you by my ego, in case you think
58I don't know how to write better code than this) :)
59
60mjr, hacking on Christmas, 1990.
61*/
62
63#define REC_UNINIT      000
64#define REC_INITTED     001
65#define REC_ERR         002
66#define REC_ON          010
67#define REC_ONOFF       020
68static  int     rec_state = REC_UNINIT;
69
70/*
71this method of storing the symbol maps is not the most efficient, but
72then that's not important here, since all we're trying to do is find
73memory leaks. if you choose to improve the symbol management to use
74bucketed hash tables, please contact the author and the code will be
75updated :) - besides, since we do file I/O every time you malloc or
76free something, there's no way in hell this is going to set any new
77records for speed.
78*/
79
80
81/* storage for code/line # entry */
82struct  sym     {
83        char            *labl;
84        int             lineno;
85        int             mapno;
86        int             mallcnt;
87        float           avsiz;
88        struct  sym     *next;
89};
90
91
92
93/* static symbol map */
94static  struct  {
95        FILE    *fp;
96        FILE    *log;
97        int     fd;
98
99        long    nalloc;         /* count of allocations */
100        long    nrlloc;         /* count of re-allocations */
101        long    nfree;          /* count of frees */
102        long    nbfree;         /* count of bad frees */
103        long    ninuse;         /* known allocated memory in use */
104        float   avgsiz;         /* average malloc size */
105
106        /* one entry per pointer returned by malloc */
107        int     pmap;           /* current next ptr map to alloc */
108        struct  ptr     *phash[HASHSIZ];
109
110        /* one entry per line of code that calls malloc/realloc, etc */
111        int     lmap;           /* current next line map to alloc */
112        struct  sym     *shash[HASHSIZ];        /* hash access */
113} map;
114
115
116
117
118/* print a locale record with checks for closed log file */
119static  void
120ploc(lab,lin,siz)
121char    *lab;
122int     lin;
123int     siz;
124{
125        if(map.log == (FILE *)0)
126                return;
127        if(lab != (char *)0)
128                (void)fprintf(map.log," \"%s\"",lab);
129        else
130                (void)fprintf(map.log," unknown");
131        if(lin != -1)
132                (void)fprintf(map.log," line:%d",lin);
133        if(siz != -1)
134                (void)fprintf(map.log," size:%d",siz);
135}
136
137
138
139
140/* print a symbol map entry with checks for closed log file */
141static  void
142psym(s)
143struct  sym     *s;
144{
145        if(map.log == (FILE *)0)
146                return;
147        (void)fprintf(map.log," \"%s\"",s->labl);
148        if(s->lineno != -1)
149                (void)fprintf(map.log," line:%d",s->lineno);
150}
151
152
153
154
155/* output a warning message with checks for closed log file */
156static  void
157pmsg(s)
158char    *s;
159{
160        if(map.log == (FILE *)0)
161                return;
162        (void)fprintf(map.log,"%s",s);
163}
164
165
166
167
168/* save an entry to the .lines file */
169static  void
170savesym(s)
171struct  sym     *s;
172{
173        if(map.fp == (FILE *)0)
174                return;
175
176        (void)fprintf(map.fp,"%d\t%d\t%.1f\t%d\t%s\n",
177                s->mapno,s->mallcnt,s->avsiz,s->lineno,s->labl);
178}
179
180
181
182
183/* save an entry in the pointer map file */
184static  void
185saveptr(p)
186register struct ptr     *p;
187{
188        if(lseek(map.fd,(off_t)(p->map * sizeof(p->dsk)),0) !=
189                (off_t)(p->map * sizeof(p->dsk))) {
190                pmsg("mnemosyne: cannot seek in pointer map file\n");
191                rec_state |= REC_ERR;
192                return;
193        }
194
195        if(write(map.fd,(char *)&(p->dsk),sizeof(p->dsk)) != sizeof(p->dsk)) {
196                pmsg("mnemosyne: cannot write in pointer map file\n");
197                rec_state |= REC_ERR;
198                return;
199        }
200}
201
202
203
204
205/* initialize everything - symbol tables, files, and maps */
206static  void
207initmap()
208{
209        register int    xp;
210
211        if(rec_state & REC_INITTED)
212                return;
213
214        if((map.fp = fopen(LINESFILE,"w")) == (FILE *)0)
215                return;
216        if((map.fd = open(PTRFILE,O_RDWR|O_CREAT|O_TRUNC,0600)) < 0) {
217                (void)fclose(map.fp);
218                return;
219        }
220
221        map.log = stderr;
222        map.lmap = map.pmap = 0;
223        map.nalloc = map.nrlloc = map.nfree = map.nbfree = 0L;
224        map.ninuse = 0L;
225        map.avgsiz = 0.0;
226
227        for(xp = 0; xp < HASHSIZ; xp++) {
228                map.phash[xp] = (struct ptr *)0;
229                map.shash[xp] = (struct sym *)0;
230        }
231
232        rec_state = REC_INITTED | REC_ON;
233}
234
235
236
237
238/* set logging to a FILE * */
239void
240mnem_setlog(fp)
241FILE    *fp;
242{
243        map.log = fp;
244}
245
246
247
248
249/* return state of the recorder */
250int
251mnem_recording()
252{
253        return((rec_state & REC_ON) && !(rec_state & REC_ERR));
254}
255
256
257
258
259/* turn on or off recording */
260int
261mnem_setrecording(val)
262int     val;
263{
264        if(!(rec_state & REC_INITTED))
265                initmap();
266
267        if(val)
268                rec_state |= REC_ON;
269        else
270                rec_state &= ~REC_ON;
271
272        if(map.fp != (FILE *)0)
273                (void)fflush(map.fp);
274
275        rec_state |= REC_ONOFF;
276        return(0);
277}
278
279
280
281
282/* lookup a pointer record - search pointer hash table */
283static struct   ptr     *
284lookupptr(ptr)
285mall_t  ptr;
286{
287        register struct ptr     *p;
288
289        /* this probably give simply terrible hash performance */
290        p = map.phash[(unsigned long)ptr % HASHSIZ];
291        while(p != (struct ptr *)0) {
292                if(ptr == p->ptr)
293                        return(p);
294                p = p->next;
295        }
296        return((struct ptr *)0);
297}
298
299
300
301
302/*
303 * polynomial conversion ignoring overflows
304 * [this seems to work remarkably well, in fact better
305 * then the ndbm hash function. Replace at your own risk]
306 * use: 65599   nice.
307 *      65587   even better.
308 * author: oz@nexus.yorku.ca
309 */
310static unsigned int
311dbm_hash(str)
312register char *str;
313{
314        register unsigned int n = 0;
315
316        while(*str != '\0')
317                n = *str++ + 65599 * n;
318        return(n);
319}
320
321
322
323
324/* lookup a line/source entry by name (search hash table) */
325static struct   sym     *
326lookupsymbyname(nam,lin)
327char    *nam;
328int     lin;
329{
330        register struct sym     *s;
331        char                    *p = nam;
332
333        if(p == (char *)0)
334                p = "unknown";
335
336        s = map.shash[(dbm_hash(p) + lin) % HASHSIZ];
337        while(s != (struct sym *)0) {
338                if(!strcmp(s->labl,nam) && s->lineno == lin)
339                        return(s);
340                s = s->next;
341        }
342
343        return((struct sym *)0);
344}
345
346
347
348
349/* lookup a line/source entry by number (exhaustively search hash table) */
350static struct   sym     *
351lookupsymbynum(num)
352int     num;
353{
354        register struct sym     *s;
355        register int            x;
356
357        for(x = 0; x < HASHSIZ; x++) {
358                s = map.shash[x];
359                while(s != (struct sym *)0) {
360                        if(s->mapno == num)
361                                return(s);
362                        s = s->next;
363                }
364        }
365        return((struct sym *)0);
366}
367
368
369
370/* stuff a pointer's value in the pointer map table */
371static  void
372storeptr(ptr,siz,lab,lin)
373mall_t  ptr;
374int     siz;
375char    *lab;
376int     lin;
377{
378        register struct ptr     *p;
379        register struct sym     *s;
380        int                     hv;
381
382        /*
383        is there is no existing symbol entry for this line of code...
384        we must needs make one - and painful it is...
385        */
386        if((s = lookupsymbyname(lab,lin)) == (struct sym *)0) {
387                s = (struct sym *)malloc(sizeof(struct sym));
388                if(s == (struct sym *)0) {
389                        pmsg("mnemosyne: cannot allocate sym entry\n");
390                        rec_state |= REC_ERR;
391                        return;
392                }
393
394                /*
395                this is funky - since we know the label is (?)
396                compiled-in, we can just keep a pointer to it,
397                rather than copying our own version of it.
398                */
399                if(lab != (char *)0)
400                        s->labl = lab;
401                else
402                        s->labl = "unknown";
403
404                s->mapno = map.lmap++;
405
406                /* add sym to hash table */
407                s->next = map.shash[hv = ((dbm_hash(s->labl) + lin) % HASHSIZ)];
408                map.shash[hv] = s;
409 
410                s->lineno = lin;
411                s->mallcnt = 1;
412                s->avsiz = siz;
413                savesym(s);
414        } else {
415                /* found an already defined symbol. store some averages */
416                s->avsiz = ((s->avsiz * s->mallcnt) + siz) / (s->mallcnt + 1);
417                (s->mallcnt)++;
418        }
419
420        p = lookupptr(ptr);
421        if(p != (struct ptr *)0 && p->dsk.siz != 0) {
422                struct  sym     *x;
423
424                pmsg("pointer re-allocated without being freed");
425                ploc(lab,lin,(int)siz);
426                if((x = lookupsymbynum(p->dsk.smap)) != (struct sym *)0) {
427                        pmsg(" last allocated ");
428                        psym(x);
429                }
430                pmsg("\n");
431        }
432
433        /* heavy sigh. no entry for this pointer. make one. */
434        if(p == (struct ptr *)0) {
435                p = (struct ptr *)malloc(sizeof(struct ptr));
436                if(p == (struct ptr *)0) {
437                        pmsg("mnemosyne: cannot expand pointer table\n");
438                        rec_state |= REC_ERR;
439                        return;
440                }
441
442                /* link it in */
443                p->next = map.phash[(unsigned long)ptr % HASHSIZ];
444                map.phash[(unsigned long)ptr % HASHSIZ] = p;
445        }
446
447        /* if we get to here (hazoo! hazaa!) both 's' and 'p' are OK */
448        p->ptr = ptr;
449        p->dsk.siz = siz;
450        p->dsk.smap = s->mapno;
451        p->map = map.pmap++;
452
453        /* store the size */
454        map.ninuse += siz;
455
456        saveptr(p);
457}
458
459
460
461
462/*
463mark a pointer as now being free. note that a 1 is returned IF
464the actual value should NOT be really passed to free()
465*/
466static  int
467freeptr(ptr,lab,lin)
468mall_t  ptr;
469char    *lab;
470int     lin;
471{
472        register struct ptr     *p;
473
474        p = lookupptr(ptr);
475        if(p == (struct ptr *)0) {
476                pmsg("pointer freed that was never allocated");
477                ploc(lab,lin,-1);
478                pmsg("\n");
479                return(1);
480        }
481
482        if(p != (struct ptr *)0 && p->dsk.siz == 0) {
483                struct  sym     *x;
484
485                pmsg("pointer re-freed when already free");
486                ploc(lab,lin,-1);
487                if((x = lookupsymbynum(p->dsk.smap)) != (struct sym *)0) {
488                        pmsg(" last allocated:");
489                        psym(x);
490                }
491                pmsg("\n");
492                return(1);
493        }
494
495        /* get some free */
496        map.ninuse -= p->dsk.siz;
497
498        /* write in the map that it is free */
499        p->dsk.siz = 0;
500        saveptr(p);
501
502        return(0);
503}
504
505
506
507
508/* pretend we are malloc() */
509mall_t
510mnem_malloc(siz,lab,lin)
511unsigned        siz;
512char            *lab;
513int             lin;
514{
515        mall_t ret;
516
517        if(!(rec_state & REC_INITTED))
518                initmap();
519
520        if((ret = malloc(siz)) == (mall_t)0) {
521                pmsg("malloc returned null pointer at");
522                ploc(lab,lin,(int)siz);
523                pmsg("\n");
524                return(ret);
525        }
526
527        if((rec_state & REC_ON) && !(rec_state & REC_ERR))
528                storeptr(ret,(int)siz,lab,lin);
529
530        map.avgsiz = ((map.avgsiz * map.nalloc) + siz) / (map.nalloc + 1);
531        map.nalloc++;
532        return(ret);
533}
534
535
536
537
538/* pretend we are calloc() */
539mall_t
540mnem_calloc(cnt,siz,lab,lin)
541unsigned        cnt;
542unsigned        siz;
543char            *lab;
544int             lin;
545{
546        mall_t ret;
547
548        if(!(rec_state & REC_INITTED))
549                initmap();
550
551        if((ret = calloc(cnt,siz)) == (mall_t)0) {
552                pmsg("calloc returned null pointer at");
553                ploc(lab,lin,(int)(siz * cnt));
554                pmsg("\n");
555                return(ret);
556        }
557
558        if((rec_state & REC_ON) && !(rec_state & REC_ERR))
559                storeptr(ret,(int)(cnt * siz),lab,lin);
560
561        map.avgsiz = ((map.avgsiz * map.nalloc) + siz) / (map.nalloc + 1);
562        map.nalloc++;
563        return(ret);
564}
565
566
567
568
569/* pretend we are realloc() */
570mall_t
571mnem_realloc(ptr,siz,lab,lin)
572mall_t          ptr;
573unsigned        siz;
574char            *lab;
575int             lin;
576{
577        mall_t ret;
578
579        if(!(rec_state & REC_INITTED))
580                initmap();
581
582        if((ret = realloc(ptr,siz)) == (mall_t)0) {
583                pmsg("realloc returned null pointer at");
584                ploc(lab,lin,(int)siz);
585                pmsg("\n");
586                return(ret);
587        }
588
589        if((rec_state & REC_ON) && !(rec_state & REC_ERR)) {
590                if(!freeptr(ptr,lab,lin))
591                        storeptr(ret,(int)siz,lab,lin);
592        }
593
594        map.nrlloc++;
595        return(ret);
596}
597
598
599
600
601
602/* pretend we are free() */
603void
604mnem_free(ptr,lab,lin)
605mall_t          ptr;
606char            *lab;
607int             lin;
608{
609        if(!(rec_state & REC_INITTED))
610                initmap();
611
612        if((rec_state & REC_ON) && !(rec_state & REC_ERR))
613                if(freeptr(ptr,lab,lin) == 0) {
614                        (void)free(ptr);
615                        map.nfree++;
616                } else
617                        map.nbfree++;
618}
619
620
621
622
623/* dump everything we know about nothing in particular */
624int
625mnem_writestats()
626{
627        register struct sym     *s;
628        register int            x;
629
630        if(map.fp == (FILE *)0)
631                return(-1);
632
633        (void)fseek(map.fp,0L,0);
634
635        /* dump our life's story */
636        (void)fprintf(map.fp,"#total allocations:%ld\n",map.nalloc);
637        (void)fprintf(map.fp,"#total re-allocations:%ld\n",map.nrlloc);
638        (void)fprintf(map.fp,"#total frees:%ld\n",map.nfree);
639
640        if(map.nbfree != 0L)
641                (void)fprintf(map.fp,"#bad/dup frees:%ld\n",map.nbfree);
642
643        (void)fprintf(map.fp,"#total allocated never freed:%ld\n",map.ninuse);
644
645        (void)fprintf(map.fp,"#average size of allocations:%.1f\n",map.avgsiz);
646
647        /* note if we detected an internal error */
648        if(rec_state & REC_ERR)
649                (void)fprintf(map.fp,
650                        "#(figures likely inaccurate due to error)\n");
651
652        /* note if the system was on all the time ? */
653        if(!(rec_state & REC_ON) || (rec_state & REC_ONOFF))
654                (void)fprintf(map.fp,
655                        "#(figures likely inaccurate as recording was off)\n");
656
657        /* write the legend */
658        (void)fprintf(map.fp,"#map#\tcalls\tave\tline#\tfile\n");
659
660        for(x = 0; x < HASHSIZ; x++) {
661                s = map.shash[x];
662                while(s != (struct sym *)0) {
663                        savesym(s);
664                        s = s->next;
665                }
666        }
667
668        (void)fflush(map.fp);
669        return(0);
670}
Note: See TracBrowser for help on using the repository browser.