diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2012-06-24 22:28:35 +0000 |
commit | 3950ffe2a485479f6561c27364d3d7df5a21d124 (patch) | |
tree | 468c6e14449d1b1e279222ec32f676b0311917d2 /src/lib/libast/vmalloc/vmprofile.c | |
download | ksh-upstream.tar.gz |
Imported Upstream version 93u+upstream
Diffstat (limited to 'src/lib/libast/vmalloc/vmprofile.c')
-rw-r--r-- | src/lib/libast/vmalloc/vmprofile.c | 709 |
1 files changed, 709 insertions, 0 deletions
diff --git a/src/lib/libast/vmalloc/vmprofile.c b/src/lib/libast/vmalloc/vmprofile.c new file mode 100644 index 0000000..43191ed --- /dev/null +++ b/src/lib/libast/vmalloc/vmprofile.c @@ -0,0 +1,709 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1985-2011 AT&T Intellectual Property * +* and is licensed under the * +* Eclipse Public License, Version 1.0 * +* by AT&T Intellectual Property * +* * +* A copy of the License is available at * +* http://www.eclipse.org/org/documents/epl-v10.html * +* (with md5 checksum b35adb5213ca9657e911e9befb180842) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* Phong Vo <kpv@research.att.com> * +* * +***********************************************************************/ +#if defined(_UWIN) && defined(_BLD_ast) + +void _STUB_vmprofile(){} + +#else + +#include "vmhdr.h" + +/* Method to profile space usage. +** +** Written by Kiem-Phong Vo, kpv@research.att.com, 03/23/94. +*/ + +#define PFHASH(pf) ((pf)->data.data.hash) +#define PFVM(pf) ((pf)->data.data.vm) +#define PFFILE(pf) ((pf)->data.data.fm.file) +#define PFLINE(pf) ((pf)->line) +#define PFNAME(pf) ((pf)->data.f) +#define PFNALLOC(pf) ((pf)->data.data.nalloc) +#define PFALLOC(pf) ((pf)->data.data.alloc) +#define PFNFREE(pf) ((pf)->data.data.nfree) +#define PFFREE(pf) ((pf)->data.data.free) +#define PFREGION(pf) ((pf)->data.data.region) +#define PFMAX(pf) ((pf)->data.data.fm.max) + +typedef struct _pfdata_s Pfdata_t; +struct _pfdata_s +{ Vmulong_t hash; /* hash value */ + union + { char* file; /* file name */ + Vmulong_t max; /* max busy space for region */ + } fm; + Vmalloc_t* vm; /* region alloc from */ + Pfobj_t* region; /* pointer to region record */ + Vmulong_t nalloc; /* number of alloc calls */ + Vmulong_t alloc; /* amount allocated */ + Vmulong_t nfree; /* number of free calls */ + Vmulong_t free; /* amount freed */ +}; +struct _pfobj_s +{ Pfobj_t* next; /* next in linked list */ + int line; /* line #, 0 for name holder */ + union + { + Pfdata_t data; + char f[1]; /* actual file name */ + } data; +}; + +static Pfobj_t** Pftable; /* hash table */ +#define PFTABLE 1019 /* table size */ +static Vmalloc_t* Vmpf; /* heap for our own use */ + +#if __STD_C +static Pfobj_t* pfsearch(Vmalloc_t* vm, char* file, int line) +#else +static Pfobj_t* pfsearch(vm, file, line) +Vmalloc_t* vm; /* region allocating from */ +char* file; /* the file issuing the allocation request */ +int line; /* line number */ +#endif +{ + reg Pfobj_t *pf, *last; + reg Vmulong_t h; + reg int n; + reg char *cp; + + if(!Vmpf && !(Vmpf = vmopen(Vmdcheap,Vmpool,0)) ) + return NIL(Pfobj_t*); + + /* make hash table; PFTABLE'th slot hold regions' records */ + if(!Pftable) + { if(!(Pftable = (Pfobj_t**)vmalloc(Vmheap,(PFTABLE+1)*sizeof(Pfobj_t*))) ) + return NIL(Pfobj_t*); + for(n = PFTABLE; n >= 0; --n) + Pftable[n] = NIL(Pfobj_t*); + } + + /* see if it's there with a combined hash value of vm,file,line */ + h = line + (((Vmulong_t)vm)>>4); + for(cp = file; *cp; ++cp) + h += (h<<7) + ((*cp)&0377) + 987654321L; + n = (int)(h%PFTABLE); + for(last = NIL(Pfobj_t*), pf = Pftable[n]; pf; last = pf, pf = pf->next) + if(PFLINE(pf) == line && PFVM(pf) == vm && strcmp(PFFILE(pf),file) == 0) + break; + + /* insert if not there yet */ + if(!pf) + { reg Pfobj_t* fn; + reg Pfobj_t* pfvm; + reg Vmulong_t hn; + + /* first get/construct the file name slot */ + hn = 0; + for(cp = file; *cp; ++cp) + hn += (hn<<7) + ((*cp)&0377) + 987654321L; + n = (int)(hn%PFTABLE); + for(fn = Pftable[n]; fn; fn = fn->next) + if(PFLINE(fn) < 0 && strcmp(PFNAME(fn),file) == 0) + break; + if(!fn) + { reg size_t s; + s = sizeof(Pfobj_t) - sizeof(Pfdata_t) + strlen(file) + 1; + if(!(fn = (Pfobj_t*)vmalloc(Vmheap,s)) ) + return NIL(Pfobj_t*); + fn->next = Pftable[n]; + Pftable[n] = fn; + PFLINE(fn) = -1; + strcpy(PFNAME(fn),file); + } + + /* get region record; note that these are ordered by vm */ + last = NIL(Pfobj_t*); + for(pfvm = Pftable[PFTABLE]; pfvm; last = pfvm, pfvm = pfvm->next) + if(vm >= PFVM(pfvm)) + break; + if(!pfvm || PFVM(pfvm) > vm) + { if(!(pfvm = (Pfobj_t*)vmalloc(Vmpf,sizeof(Pfobj_t))) ) + return NIL(Pfobj_t*); + if(last) + { pfvm->next = last->next; + last->next = pfvm; + } + else + { pfvm->next = Pftable[PFTABLE]; + Pftable[PFTABLE] = pfvm; + } + PFNALLOC(pfvm) = PFALLOC(pfvm) = 0; + PFNFREE(pfvm) = PFFREE(pfvm) = 0; + PFMAX(pfvm) = 0; + PFVM(pfvm) = vm; + PFLINE(pfvm) = 0; + } + + if(!(pf = (Pfobj_t*)vmalloc(Vmpf,sizeof(Pfobj_t))) ) + return NIL(Pfobj_t*); + n = (int)(h%PFTABLE); + pf->next = Pftable[n]; + Pftable[n] = pf; + PFLINE(pf) = line; + PFFILE(pf) = PFNAME(fn); + PFREGION(pf) = pfvm; + PFVM(pf) = vm; + PFNALLOC(pf) = 0; + PFALLOC(pf) = 0; + PFNFREE(pf) = 0; + PFFREE(pf) = 0; + PFHASH(pf) = h; + } + else if(last) /* do a move-to-front */ + { last->next = pf->next; + pf->next = Pftable[n]; + Pftable[n] = pf; + } + + return pf; +} + +#if __STD_C +static void pfclose(Vmalloc_t* vm) +#else +static void pfclose(vm) +Vmalloc_t* vm; +#endif +{ + reg int n; + reg Pfobj_t *pf, *next, *last; + + /* free all records related to region vm */ + for(n = PFTABLE; n >= 0; --n) + { for(last = NIL(Pfobj_t*), pf = Pftable[n]; pf; ) + { next = pf->next; + + if(PFLINE(pf) >= 0 && PFVM(pf) == vm) + { if(last) + last->next = next; + else Pftable[n] = next; + vmfree(Vmpf,pf); + } + else last = pf; + + pf = next; + } + } +} + +#if __STD_C +static void pfsetinfo(Vmalloc_t* vm, Vmuchar_t* data, size_t size, char* file, int line) +#else +static void pfsetinfo(vm, data, size, file, line) +Vmalloc_t* vm; +Vmuchar_t* data; +size_t size; +char* file; +int line; +#endif +{ + reg Pfobj_t* pf; + reg Vmulong_t s; + + /* let vmclose knows that there are records for region vm */ + _Vmpfclose = pfclose; + + if(!file || line <= 0) + { file = ""; + line = 0; + } + + if((pf = pfsearch(vm,file,line)) ) + { PFALLOC(pf) += size; + PFNALLOC(pf) += 1; + } + PFOBJ(data) = pf; + PFSIZE(data) = size; + + if(pf) + { /* update region statistics */ + pf = PFREGION(pf); + PFALLOC(pf) += size; + PFNALLOC(pf) += 1; + if((s = PFALLOC(pf) - PFFREE(pf)) > PFMAX(pf) ) + PFMAX(pf) = s; + } +} + +/* sort by file names and line numbers */ +#if __STD_C +static Pfobj_t* pfsort(Pfobj_t* pf) +#else +static Pfobj_t* pfsort(pf) +Pfobj_t* pf; +#endif +{ + reg Pfobj_t *one, *two, *next; + reg int cmp; + + if(!pf->next) + return pf; + + /* partition to two equal size lists */ + one = two = NIL(Pfobj_t*); + while(pf) + { next = pf->next; + pf->next = one; + one = pf; + + if((pf = next) ) + { next = pf->next; + pf->next = two; + two = pf; + pf = next; + } + } + + /* sort and merge the lists */ + one = pfsort(one); + two = pfsort(two); + for(pf = next = NIL(Pfobj_t*);; ) + { /* make sure that the "<>" file comes first */ + if(PFLINE(one) == 0 && PFLINE(two) == 0) + cmp = PFVM(one) > PFVM(two) ? 1 : -1; + else if(PFLINE(one) == 0) + cmp = -1; + else if(PFLINE(two) == 0) + cmp = 1; + else if((cmp = strcmp(PFFILE(one),PFFILE(two))) == 0) + { cmp = PFLINE(one) - PFLINE(two); + if(cmp == 0) + cmp = PFVM(one) > PFVM(two) ? 1 : -1; + } + + if(cmp < 0) + { if(!pf) + pf = one; + else next->next = one; + next = one; + if(!(one = one->next) ) + { if(two) + next->next = two; + return pf; + } + } + else + { if(!pf) + pf = two; + else next->next = two; + next = two; + if(!(two = two->next) ) + { if(one) + next->next = one; + return pf; + } + } + } +} + +#if __STD_C +static char* pfsummary(char* buf, Vmulong_t na, Vmulong_t sa, + Vmulong_t nf, Vmulong_t sf, Vmulong_t max, Vmulong_t size) +#else +static char* pfsummary(buf, na, sa, nf, sf, max, size) +char* buf; +Vmulong_t na; +Vmulong_t sa; +Vmulong_t nf; +Vmulong_t sf; +Vmulong_t max; +Vmulong_t size; +#endif +{ + buf = (*_Vmstrcpy)(buf,"n_alloc", '='); + buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(na,-1), ':'); + buf = (*_Vmstrcpy)(buf,"n_free", '='); + buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(nf,-1), ':'); + buf = (*_Vmstrcpy)(buf,"s_alloc", '='); + buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(sa,-1), ':'); + buf = (*_Vmstrcpy)(buf,"s_free", '='); + buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(sf,-1), ':'); + if(max > 0) + { buf = (*_Vmstrcpy)(buf,"max_busy", '='); + buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(max,-1), ':'); + buf = (*_Vmstrcpy)(buf,"extent", '='); + buf = (*_Vmstrcpy)(buf, (*_Vmitoa)(size,-1), ':'); + } + *buf++ = '\n'; + + return buf; +} + +/* print profile data */ +#if __STD_C +int vmprofile(Vmalloc_t* vm, int fd) +#else +int vmprofile(vm, fd) +Vmalloc_t* vm; +int fd; +#endif +{ + reg Pfobj_t *pf, *list, *next, *last; + reg int n; + reg Vmulong_t nalloc, alloc, nfree, free; + reg Seg_t *seg; + char buf[1024], *bufp, *endbuf; +#define INITBUF() (bufp = buf, endbuf = buf+sizeof(buf)-128) +#define CHKBUF() (bufp >= endbuf ? (write(fd,buf,bufp-buf), bufp=buf) : bufp) +#define FLSBUF() (bufp > buf ? write(fd,buf,bufp-buf) : 0) + + if(fd < 0) + return -1; + + /* initialize functions from vmtrace.c that we use below */ + if((n = vmtrace(-1)) >= 0) + vmtrace(n); + + alloc = free = nalloc = nfree = 0; + list = NIL(Pfobj_t*); + for(n = PFTABLE-1; n >= 0; --n) + { for(pf = Pftable[n], last = NIL(Pfobj_t*); pf; ) + { next = pf->next; + + if(PFLINE(pf) < 0 || (vm && vm != PFVM(pf)) ) + { last = pf; + goto next_pf; + } + + /* remove from hash table */ + if(last) + last->next = next; + else Pftable[n] = next; + + /* put on output list */ + pf->next = list; + list = pf; + nalloc += PFNALLOC(pf); + alloc += PFALLOC(pf); + nfree += PFNFREE(pf); + free += PFFREE(pf); + + next_pf: + pf = next; + } + } + + INITBUF(); + bufp = (*_Vmstrcpy)(bufp,"ALLOCATION USAGE SUMMARY", ':'); + bufp = pfsummary(bufp,nalloc,alloc,nfree,free,0,0); + + /* print regions' summary data */ + for(pf = Pftable[PFTABLE]; pf; pf = pf->next) + { if(vm && PFVM(pf) != vm) + continue; + alloc = 0; + for(seg = PFVM(pf)->data->seg; seg; seg = seg->next) + alloc += seg->extent; + bufp = (*_Vmstrcpy)(bufp,"region", '='); + bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(PFVM(pf)),0), ':'); + bufp = pfsummary(bufp,PFNALLOC(pf),PFALLOC(pf), + PFNFREE(pf),PFFREE(pf),PFMAX(pf),alloc); + } + + /* sort then output detailed profile */ + list = pfsort(list); + for(pf = list; pf; ) + { /* compute summary for file */ + alloc = free = nalloc = nfree = 0; + for(last = pf; last; last = last->next) + { if(strcmp(PFFILE(last),PFFILE(pf)) != 0) + break; + nalloc += PFNALLOC(pf); + alloc += PFALLOC(last); + nfree += PFNFREE(last); + free += PFFREE(last); + } + CHKBUF(); + bufp = (*_Vmstrcpy)(bufp,"file",'='); + bufp = (*_Vmstrcpy)(bufp,PFFILE(pf)[0] ? PFFILE(pf) : "<>" ,':'); + bufp = pfsummary(bufp,nalloc,alloc,nfree,free,0,0); + + while(pf != last) /* detailed data */ + { CHKBUF(); + bufp = (*_Vmstrcpy)(bufp,"\tline",'='); + bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(PFLINE(pf),-1), ':'); + bufp = (*_Vmstrcpy)(bufp, "region", '='); + bufp = (*_Vmstrcpy)(bufp, (*_Vmitoa)(VLONG(PFVM(pf)),0), ':'); + bufp = pfsummary(bufp,PFNALLOC(pf),PFALLOC(pf), + PFNFREE(pf),PFFREE(pf),0,0); + + /* reinsert into hash table */ + next = pf->next; + n = (int)(PFHASH(pf)%PFTABLE); + pf->next = Pftable[n]; + Pftable[n] = pf; + pf = next; + } + } + + FLSBUF(); + return 0; +} + +#if __STD_C +static Void_t* pfalloc(Vmalloc_t* vm, size_t size, int local) +#else +static Void_t* pfalloc(vm, size, local) +Vmalloc_t* vm; +size_t size; +int local; +#endif +{ + reg size_t s; + reg Void_t *data; + reg char *file; + reg int line; + reg Void_t *func; + reg Vmdata_t *vd = vm->data; + + VMFLF(vm,file,line,func); + + SETLOCK(vm, local); + + s = ROUND(size,ALIGN) + PF_EXTRA; + if((data = KPVALLOC(vm,s,(*(Vmbest->allocf))) ) ) + { pfsetinfo(vm,(Vmuchar_t*)data,size,file,line); + + if(!local && (vd->mode&VM_TRACE) && _Vmtrace) + { vm->file = file; vm->line = line; vm->func = func; + (*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)data,size,0); + } + } + + CLRLOCK(vm, local); + + return data; +} + +#if __STD_C +static int pffree(Vmalloc_t* vm, Void_t* data, int local) +#else +static int pffree(vm, data, local) +Vmalloc_t* vm; +Void_t* data; +int local; +#endif +{ + reg Pfobj_t *pf; + reg size_t s; + reg char *file; + reg int line, rv; + reg Void_t *func; + reg Vmdata_t *vd = vm->data; + + VMFLF(vm,file,line,func); + + if(!data) + return 0; + + SETLOCK(vm,local); + + /**/ASSERT(KPVADDR(vm, data, Vmbest->addrf) == 0 ); + pf = PFOBJ(data); + s = PFSIZE(data); + if(pf) + { PFNFREE(pf) += 1; + PFFREE(pf) += s; + pf = PFREGION(pf); + PFNFREE(pf) += 1; + PFFREE(pf) += s; + } + + if(!local && (vd->mode&VM_TRACE) && _Vmtrace) + { vm->file = file; vm->line = line; vm->func = func; + (*_Vmtrace)(vm,(Vmuchar_t*)data,NIL(Vmuchar_t*),s,0); + } + + rv = KPVFREE((vm), (Void_t*)data, (*Vmbest->freef)); + + CLRLOCK(vm, local); + + return rv; +} + +#if __STD_C +static Void_t* pfresize(Vmalloc_t* vm, Void_t* data, size_t size, int type, int local) +#else +static Void_t* pfresize(vm, data, size, type, local) +Vmalloc_t* vm; +Void_t* data; +size_t size; +int type; +int local; +#endif +{ + reg Pfobj_t *pf; + reg size_t s, news; + reg Void_t *addr; + reg char *file; + reg int line; + reg Void_t *func; + reg size_t oldsize; + reg Vmdata_t *vd = vm->data; + + if(!data) + { addr = pfalloc(vm, size, local); + if(addr && (type&VM_RSZERO) ) + memset(addr, 0, size); + return addr; + } + if(size == 0) + { (void)pffree(vm, data, local); + return NIL(Void_t*); + } + + VMFLF(vm,file,line,func); + + SETLOCK(vm, local); + + /**/ASSERT(KPVADDR(vm,data,Vmbest->addrf) == 0 ); + pf = PFOBJ(data); + s = oldsize = PFSIZE(data); + + news = ROUND(size,ALIGN) + PF_EXTRA; + if((addr = KPVRESIZE(vm,data,news,(type&~VM_RSZERO),Vmbest->resizef)) ) + { if(pf) + { PFFREE(pf) += s; + PFNFREE(pf) += 1; + pf = PFREGION(pf); + PFFREE(pf) += s; + PFNFREE(pf) += 1; + pfsetinfo(vm,(Vmuchar_t*)addr,size,file,line); + } + + if(!local && (vd->mode&VM_TRACE) && _Vmtrace) + { vm->file = file; vm->line = line; vm->func = func; + (*_Vmtrace)(vm,(Vmuchar_t*)data,(Vmuchar_t*)addr,size,0); + } + } + else if(pf) /* reset old info */ + { PFALLOC(pf) -= s; + PFNALLOC(pf) -= 1; + pf = PFREGION(pf); + PFALLOC(pf) -= s; + PFNALLOC(pf) -= 1; + file = PFFILE(pf); + line = PFLINE(pf); + pfsetinfo(vm,(Vmuchar_t*)data,s,file,line); + } + + if(addr && (type&VM_RSZERO) && oldsize < size) + { reg Vmuchar_t *d = (Vmuchar_t*)addr+oldsize, *ed = (Vmuchar_t*)addr+size; + do { *d++ = 0; } while(d < ed); + } + + CLRLOCK(vm, local); + + return addr; +} + +#if __STD_C +static long pfsize(Vmalloc_t* vm, Void_t* addr, int local) +#else +static long pfsize(vm, addr, local) +Vmalloc_t* vm; +Void_t* addr; +int local; +#endif +{ + return (*Vmbest->addrf)(vm, addr, local) != 0 ? -1L : (long)PFSIZE(addr); +} + +#if __STD_C +static long pfaddr(Vmalloc_t* vm, Void_t* addr, int local) +#else +static long pfaddr(vm, addr, local) +Vmalloc_t* vm; +Void_t* addr; +int local; +#endif +{ + return (*Vmbest->addrf)(vm, addr, local); +} + +#if __STD_C +static int pfcompact(Vmalloc_t* vm, int local) +#else +static int pfcompact(vm, local) +Vmalloc_t* vm; +int local; +#endif +{ + return (*Vmbest->compactf)(vm, local); +} + +#if __STD_C +static Void_t* pfalign(Vmalloc_t* vm, size_t size, size_t align, int local) +#else +static Void_t* pfalign(vm, size, align, local) +Vmalloc_t* vm; +size_t size; +size_t align; +int local; +#endif +{ + reg size_t s; + reg Void_t *data; + reg char *file; + reg int line, inuse; + reg Void_t *func; + reg Vmdata_t *vd = vm->data; + + VMFLF(vm,file,line,func); + + SETLOCK(vm, local); + + s = (size <= TINYSIZE ? TINYSIZE : ROUND(size,ALIGN)) + PF_EXTRA; + if((data = KPVALIGN(vm,s,align,Vmbest->alignf)) ) + { pfsetinfo(vm,(Vmuchar_t*)data,size,file,line); + + if(!local && (vd->mode&VM_TRACE) && _Vmtrace) + { vm->file = file; vm->line = line; vm->func = func; + (*_Vmtrace)(vm,NIL(Vmuchar_t*),(Vmuchar_t*)data,size,align); + } + } + + CLRLOCK(vm, local); + + return data; +} + +static Vmethod_t _Vmprofile = +{ + pfalloc, + pfresize, + pffree, + pfaddr, + pfsize, + pfcompact, + pfalign, + VM_MTPROFILE +}; + +__DEFINE__(Vmethod_t*,Vmprofile,&_Vmprofile); + +#ifdef NoF +NoF(vmprofile) +#endif + +#endif |