1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
22 #if defined(_UWIN) && defined(_BLD_ast)
24 void _STUB_vmprofile(){}
30 /* Method to profile space usage.
32 ** Written by Kiem-Phong Vo, kpv@research.att.com, 03/23/94.
35 #define PFHASH(pf) ((pf)->data.data.hash)
36 #define PFVM(pf) ((pf)->data.data.vm)
37 #define PFFILE(pf) ((pf)->data.data.fm.file)
38 #define PFLINE(pf) ((pf)->line)
39 #define PFNAME(pf) ((pf)->data.f)
40 #define PFNALLOC(pf) ((pf)->data.data.nalloc)
41 #define PFALLOC(pf) ((pf)->data.data.alloc)
42 #define PFNFREE(pf) ((pf)->data.data.nfree)
43 #define PFFREE(pf) ((pf)->data.data.free)
44 #define PFREGION(pf) ((pf)->data.data.region)
45 #define PFMAX(pf) ((pf)->data.data.fm.max)
47 typedef struct _pfdata_s Pfdata_t
;
49 { Vmulong_t hash
; /* hash value */
51 { char* file
; /* file name */
52 Vmulong_t max
; /* max busy space for region */
54 Vmalloc_t
* vm
; /* region alloc from */
55 Pfobj_t
* region
; /* pointer to region record */
56 Vmulong_t nalloc
; /* number of alloc calls */
57 Vmulong_t alloc
; /* amount allocated */
58 Vmulong_t nfree
; /* number of free calls */
59 Vmulong_t free
; /* amount freed */
62 { Pfobj_t
* next
; /* next in linked list */
63 int line
; /* line #, 0 for name holder */
67 char f
[1]; /* actual file name */
71 static Pfobj_t
** Pftable
; /* hash table */
72 #define PFTABLE 1019 /* table size */
73 static Vmalloc_t
* Vmpf
; /* heap for our own use */
76 static Pfobj_t
* pfsearch(Vmalloc_t
* vm
, const char* file
, int line
)
78 static Pfobj_t
* pfsearch(vm
, file
, line
)
79 Vmalloc_t
* vm
; /* region allocating from */
80 const char* file
; /* the file issuing the allocation request */
81 int line
; /* line number */
84 reg Pfobj_t
*pf
, *last
;
89 if(!Vmpf
&& !(Vmpf
= vmopen(Vmdcheap
,Vmpool
,0)) )
92 /* make hash table; PFTABLE'th slot hold regions' records */
94 { if(!(Pftable
= (Pfobj_t
**)vmalloc(Vmheap
,(PFTABLE
+1)*sizeof(Pfobj_t
*))) )
96 for(n
= PFTABLE
; n
>= 0; --n
)
97 Pftable
[n
] = NIL(Pfobj_t
*);
100 /* see if it's there with a combined hash value of vm,file,line */
101 h
= line
+ (((Vmulong_t
)vm
)>>4);
102 for(cp
= file
; *cp
; ++cp
)
103 h
+= (h
<<7) + ((*cp
)&0377) + 987654321L;
104 n
= (int)(h
%PFTABLE
);
105 for(last
= NIL(Pfobj_t
*), pf
= Pftable
[n
]; pf
; last
= pf
, pf
= pf
->next
)
106 if(PFLINE(pf
) == line
&& PFVM(pf
) == vm
&& strcmp(PFFILE(pf
),file
) == 0)
109 /* insert if not there yet */
115 /* first get/construct the file name slot */
117 for(cp
= file
; *cp
; ++cp
)
118 hn
+= (hn
<<7) + ((*cp
)&0377) + 987654321L;
119 n
= (int)(hn
%PFTABLE
);
120 for(fn
= Pftable
[n
]; fn
; fn
= fn
->next
)
121 if(PFLINE(fn
) < 0 && strcmp(PFNAME(fn
),file
) == 0)
125 s
= sizeof(Pfobj_t
) - sizeof(Pfdata_t
) + strlen(file
) + 1;
126 if(!(fn
= (Pfobj_t
*)vmalloc(Vmheap
,s
)) )
127 return NIL(Pfobj_t
*);
128 fn
->next
= Pftable
[n
];
131 strcpy(PFNAME(fn
),file
);
134 /* get region record; note that these are ordered by vm */
135 last
= NIL(Pfobj_t
*);
136 for(pfvm
= Pftable
[PFTABLE
]; pfvm
; last
= pfvm
, pfvm
= pfvm
->next
)
139 if(!pfvm
|| PFVM(pfvm
) > vm
)
140 { if(!(pfvm
= (Pfobj_t
*)vmalloc(Vmpf
,sizeof(Pfobj_t
))) )
141 return NIL(Pfobj_t
*);
143 { pfvm
->next
= last
->next
;
147 { pfvm
->next
= Pftable
[PFTABLE
];
148 Pftable
[PFTABLE
] = pfvm
;
150 PFNALLOC(pfvm
) = PFALLOC(pfvm
) = 0;
151 PFNFREE(pfvm
) = PFFREE(pfvm
) = 0;
157 if(!(pf
= (Pfobj_t
*)vmalloc(Vmpf
,sizeof(Pfobj_t
))) )
158 return NIL(Pfobj_t
*);
159 n
= (int)(h
%PFTABLE
);
160 pf
->next
= Pftable
[n
];
163 PFFILE(pf
) = PFNAME(fn
);
172 else if(last
) /* do a move-to-front */
173 { last
->next
= pf
->next
;
174 pf
->next
= Pftable
[n
];
182 static void pfclose(Vmalloc_t
* vm
)
184 static void pfclose(vm
)
189 reg Pfobj_t
*pf
, *next
, *last
;
191 /* free all records related to region vm */
192 for(n
= PFTABLE
; n
>= 0; --n
)
193 { for(last
= NIL(Pfobj_t
*), pf
= Pftable
[n
]; pf
; )
196 if(PFLINE(pf
) >= 0 && PFVM(pf
) == vm
)
199 else Pftable
[n
] = next
;
210 static void pfsetinfo(Vmalloc_t
* vm
, Vmuchar_t
* data
, size_t size
, const char* file
, int line
)
212 static void pfsetinfo(vm
, data
, size
, file
, line
)
223 /* let vmclose knows that there are records for region vm */
224 _Vmpfclose
= pfclose
;
226 if(!file
|| line
<= 0)
231 if((pf
= pfsearch(vm
,file
,line
)) )
232 { PFALLOC(pf
) += size
;
239 { /* update region statistics */
243 if((s
= PFALLOC(pf
) - PFFREE(pf
)) > PFMAX(pf
) )
248 /* sort by file names and line numbers */
250 static Pfobj_t
* pfsort(Pfobj_t
* pf
)
252 static Pfobj_t
* pfsort(pf
)
256 reg Pfobj_t
*one
, *two
, *next
;
262 /* partition to two equal size lists */
263 one
= two
= NIL(Pfobj_t
*);
277 /* sort and merge the lists */
280 for(pf
= next
= NIL(Pfobj_t
*);; )
281 { /* make sure that the "<>" file comes first */
282 if(PFLINE(one
) == 0 && PFLINE(two
) == 0)
283 cmp
= PFVM(one
) > PFVM(two
) ? 1 : -1;
284 else if(PFLINE(one
) == 0)
286 else if(PFLINE(two
) == 0)
288 else if((cmp
= strcmp(PFFILE(one
),PFFILE(two
))) == 0)
289 { cmp
= PFLINE(one
) - PFLINE(two
);
291 cmp
= PFVM(one
) > PFVM(two
) ? 1 : -1;
297 else next
->next
= one
;
299 if(!(one
= one
->next
) )
308 else next
->next
= two
;
310 if(!(two
= two
->next
) )
320 static char* pfsummary(char* buf
, Vmulong_t na
, Vmulong_t sa
,
321 Vmulong_t nf
, Vmulong_t sf
, Vmulong_t max
, Vmulong_t size
)
323 static char* pfsummary(buf
, na
, sa
, nf
, sf
, max
, size
)
333 buf
= (*_Vmstrcpy
)(buf
,"n_alloc", '=');
334 buf
= (*_Vmstrcpy
)(buf
, (*_Vmitoa
)(na
,-1), ':');
335 buf
= (*_Vmstrcpy
)(buf
,"n_free", '=');
336 buf
= (*_Vmstrcpy
)(buf
, (*_Vmitoa
)(nf
,-1), ':');
337 buf
= (*_Vmstrcpy
)(buf
,"s_alloc", '=');
338 buf
= (*_Vmstrcpy
)(buf
, (*_Vmitoa
)(sa
,-1), ':');
339 buf
= (*_Vmstrcpy
)(buf
,"s_free", '=');
340 buf
= (*_Vmstrcpy
)(buf
, (*_Vmitoa
)(sf
,-1), ':');
342 { buf
= (*_Vmstrcpy
)(buf
,"max_busy", '=');
343 buf
= (*_Vmstrcpy
)(buf
, (*_Vmitoa
)(max
,-1), ':');
344 buf
= (*_Vmstrcpy
)(buf
,"extent", '=');
345 buf
= (*_Vmstrcpy
)(buf
, (*_Vmitoa
)(size
,-1), ':');
352 /* print profile data */
354 int vmprofile(Vmalloc_t
* vm
, int fd
)
356 int vmprofile(vm
, fd
)
361 reg Pfobj_t
*pf
, *list
, *next
, *last
;
363 reg Vmulong_t nalloc
, alloc
, nfree
, free
;
365 char buf
[1024], *bufp
, *endbuf
;
366 #define INITBUF() (bufp = buf, endbuf = buf+sizeof(buf)-128)
367 #define CHKBUF() (bufp >= endbuf ? (write(fd,buf,bufp-buf), bufp=buf) : bufp)
368 #define FLSBUF() (bufp > buf ? write(fd,buf,bufp-buf) : 0)
373 /* initialize functions from vmtrace.c that we use below */
374 if((n
= vmtrace(-1)) >= 0)
377 alloc
= free
= nalloc
= nfree
= 0;
378 list
= NIL(Pfobj_t
*);
379 for(n
= PFTABLE
-1; n
>= 0; --n
)
380 { for(pf
= Pftable
[n
], last
= NIL(Pfobj_t
*); pf
; )
383 if(PFLINE(pf
) < 0 || (vm
&& vm
!= PFVM(pf
)) )
388 /* remove from hash table */
391 else Pftable
[n
] = next
;
393 /* put on output list */
396 nalloc
+= PFNALLOC(pf
);
397 alloc
+= PFALLOC(pf
);
398 nfree
+= PFNFREE(pf
);
407 bufp
= (*_Vmstrcpy
)(bufp
,"ALLOCATION USAGE SUMMARY", ':');
408 bufp
= pfsummary(bufp
,nalloc
,alloc
,nfree
,free
,0,0);
410 /* print regions' summary data */
411 for(pf
= Pftable
[PFTABLE
]; pf
; pf
= pf
->next
)
412 { if(vm
&& PFVM(pf
) != vm
)
415 for(seg
= PFVM(pf
)->data
->seg
; seg
; seg
= seg
->next
)
416 alloc
+= seg
->extent
;
417 bufp
= (*_Vmstrcpy
)(bufp
,"region", '=');
418 bufp
= (*_Vmstrcpy
)(bufp
, (*_Vmitoa
)(VLONG(PFVM(pf
)),0), ':');
419 bufp
= pfsummary(bufp
,PFNALLOC(pf
),PFALLOC(pf
),
420 PFNFREE(pf
),PFFREE(pf
),PFMAX(pf
),alloc
);
423 /* sort then output detailed profile */
426 { /* compute summary for file */
427 alloc
= free
= nalloc
= nfree
= 0;
428 for(last
= pf
; last
; last
= last
->next
)
429 { if(strcmp(PFFILE(last
),PFFILE(pf
)) != 0)
431 nalloc
+= PFNALLOC(pf
);
432 alloc
+= PFALLOC(last
);
433 nfree
+= PFNFREE(last
);
434 free
+= PFFREE(last
);
437 bufp
= (*_Vmstrcpy
)(bufp
,"file",'=');
438 bufp
= (*_Vmstrcpy
)(bufp
,PFFILE(pf
)[0] ? PFFILE(pf
) : "<>" ,':');
439 bufp
= pfsummary(bufp
,nalloc
,alloc
,nfree
,free
,0,0);
441 while(pf
!= last
) /* detailed data */
443 bufp
= (*_Vmstrcpy
)(bufp
,"\tline",'=');
444 bufp
= (*_Vmstrcpy
)(bufp
, (*_Vmitoa
)(PFLINE(pf
),-1), ':');
445 bufp
= (*_Vmstrcpy
)(bufp
, "region", '=');
446 bufp
= (*_Vmstrcpy
)(bufp
, (*_Vmitoa
)(VLONG(PFVM(pf
)),0), ':');
447 bufp
= pfsummary(bufp
,PFNALLOC(pf
),PFALLOC(pf
),
448 PFNFREE(pf
),PFFREE(pf
),0,0);
450 /* reinsert into hash table */
452 n
= (int)(PFHASH(pf
)%PFTABLE
);
453 pf
->next
= Pftable
[n
];
464 static Void_t
* pfalloc(Vmalloc_t
* vm
, size_t size
)
466 static Void_t
* pfalloc(vm
, size
)
474 reg
int line
, local
, inuse
;
476 reg Vmdata_t
* vd
= vm
->data
;
478 VMFLF(vm
,file
,line
,func
);
480 if(!(local
= vd
->mode
&VM_TRUST
) )
481 { GETLOCAL(vd
, local
);
482 if(ISLOCK(vd
, local
))
483 { CLRINUSE(vd
, inuse
);
489 s
= ROUND(size
,ALIGN
) + PF_EXTRA
;
490 if(!(data
= KPVALLOC(vm
,s
,(*(Vmbest
->allocf
))) ) )
493 pfsetinfo(vm
,(Vmuchar_t
*)data
,size
,file
,line
);
495 if(!local
&& (vd
->mode
&VM_TRACE
) && _Vmtrace
)
496 { vm
->file
= file
; vm
->line
= line
; vm
->func
= func
;
497 (*_Vmtrace
)(vm
,NIL(Vmuchar_t
*),(Vmuchar_t
*)data
,size
,0);
501 ANNOUNCE(local
, vm
, VM_ALLOC
, (Void_t
*)data
, vm
->disc
);
507 static int pffree(Vmalloc_t
* vm
, Void_t
* data
)
509 static int pffree(vm
, data
)
517 reg
int line
, rv
, local
, inuse
;
519 reg Vmdata_t
* vd
= vm
->data
;
521 VMFLF(vm
,file
,line
,func
);
527 if(!(local
= vd
->mode
&VM_TRUST
) )
528 { GETLOCAL(vd
,local
);
530 { CLRINUSE(vd
, inuse
);
536 if(KPVADDR(vm
,data
,Vmbest
->addrf
) != 0 )
537 { if(vm
->disc
->exceptf
)
538 (void)(*vm
->disc
->exceptf
)(vm
,VM_BADADDR
,data
,vm
->disc
);
554 if(!local
&& (vd
->mode
&VM_TRACE
) && _Vmtrace
)
555 { vm
->file
= file
; vm
->line
= line
; vm
->func
= func
;
556 (*_Vmtrace
)(vm
,(Vmuchar_t
*)data
,NIL(Vmuchar_t
*),s
,0);
559 rv
= KPVFREE((vm
), (Void_t
*)data
, (*Vmbest
->freef
));
561 ANNOUNCE(local
, vm
, VM_FREE
, data
, vm
->disc
);
567 static Void_t
* pfresize(Vmalloc_t
* vm
, Void_t
* data
, size_t size
, int type
)
569 static Void_t
* pfresize(vm
, data
, size
, type
)
581 reg
int line
, local
, inuse
;
584 reg Vmdata_t
* vd
= vm
->data
;
589 addr
= pfalloc(vm
,size
);
593 { (void)pffree(vm
,data
);
598 VMFLF(vm
,file
,line
,func
);
599 if(!(local
= vd
->mode
&VM_TRUST
))
600 { GETLOCAL(vd
, local
);
601 if(ISLOCK(vd
, local
))
602 { CLRINUSE(vd
, inuse
);
608 if(KPVADDR(vm
,data
,Vmbest
->addrf
) != 0 )
609 { if(vm
->disc
->exceptf
)
610 (void)(*vm
->disc
->exceptf
)(vm
,VM_BADADDR
,data
,vm
->disc
);
617 s
= oldsize
= PFSIZE(data
);
619 news
= ROUND(size
,ALIGN
) + PF_EXTRA
;
620 if((addr
= KPVRESIZE(vm
,data
,news
,(type
&~VM_RSZERO
),Vmbest
->resizef
)) )
627 pfsetinfo(vm
,(Vmuchar_t
*)addr
,size
,file
,line
);
630 if(!local
&& (vd
->mode
&VM_TRACE
) && _Vmtrace
)
631 { vm
->file
= file
; vm
->line
= line
; vm
->func
= func
;
632 (*_Vmtrace
)(vm
,(Vmuchar_t
*)data
,(Vmuchar_t
*)addr
,size
,0);
635 else if(pf
) /* reset old info */
643 pfsetinfo(vm
,(Vmuchar_t
*)data
,s
,file
,line
);
647 ANNOUNCE(local
, vm
, VM_RESIZE
, (Void_t
*)addr
, vm
->disc
);
649 done
: if(addr
&& (type
&VM_RSZERO
) && oldsize
< size
)
650 { reg Vmuchar_t
*d
= (Vmuchar_t
*)addr
+oldsize
, *ed
= (Vmuchar_t
*)addr
+size
;
651 do { *d
++ = 0; } while(d
< ed
);
659 static long pfsize(Vmalloc_t
* vm
, Void_t
* addr
)
661 static long pfsize(vm
, addr
)
666 return (*Vmbest
->addrf
)(vm
,addr
) != 0 ? -1L : (long)PFSIZE(addr
);
670 static long pfaddr(Vmalloc_t
* vm
, Void_t
* addr
)
672 static long pfaddr(vm
, addr
)
677 return (*Vmbest
->addrf
)(vm
,addr
);
681 static int pfcompact(Vmalloc_t
* vm
)
683 static int pfcompact(vm
)
687 return (*Vmbest
->compactf
)(vm
);
691 static Void_t
* pfalign(Vmalloc_t
* vm
, size_t size
, size_t align
)
693 static Void_t
* pfalign(vm
, size
, align
)
702 reg
int line
, local
, inuse
;
704 reg Vmdata_t
* vd
= vm
->data
;
706 VMFLF(vm
,file
,line
,func
);
709 if(!(local
= vd
->mode
&VM_TRUST
) )
710 { GETLOCAL(vd
,local
);
711 if(ISLOCK(vd
, local
))
712 { CLRINUSE(vd
, inuse
);
718 s
= (size
<= TINYSIZE
? TINYSIZE
: ROUND(size
,ALIGN
)) + PF_EXTRA
;
719 if(!(data
= KPVALIGN(vm
,s
,align
,Vmbest
->alignf
)) )
722 pfsetinfo(vm
,(Vmuchar_t
*)data
,size
,file
,line
);
724 if(!local
&& (vd
->mode
&VM_TRACE
) && _Vmtrace
)
725 { vm
->file
= file
; vm
->line
= line
; vm
->func
= func
;
726 (*_Vmtrace
)(vm
,NIL(Vmuchar_t
*),(Vmuchar_t
*)data
,size
,align
);
730 ANNOUNCE(local
, vm
, VM_ALLOC
, data
, vm
->disc
);
735 static Vmethod_t _Vmprofile
=
747 __DEFINE__(Vmethod_t
*,Vmprofile
,&_Vmprofile
);