xref: /titanic_41/usr/src/lib/libast/common/vmalloc/vmprofile.c (revision bdb9230ac765cb7af3fc1f4119caf2c5720dceb3)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2008 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 #if defined(_UWIN) && defined(_BLD_ast)
23 
24 void _STUB_vmprofile(){}
25 
26 #else
27 
28 #include	"vmhdr.h"
29 
30 /*	Method to profile space usage.
31 **
32 **	Written by Kiem-Phong Vo, kpv@research.att.com, 03/23/94.
33 */
34 
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)
46 
47 typedef struct _pfdata_s	Pfdata_t;
48 struct _pfdata_s
49 {	Vmulong_t	hash;	/* hash value			*/
50 	union
51 	{ char*		file;	/* file name			*/
52 	  Vmulong_t	max;	/* max busy space for region	*/
53 	} fm;
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			*/
60 };
61 struct _pfobj_s
62 {	Pfobj_t*	next;	/* next in linked list	*/
63 	int		line;	/* line #, 0 for name holder	*/
64 	union
65 	{
66 	Pfdata_t	data;
67 	char		f[1];	/* actual file name		*/
68 	} data;
69 };
70 
71 static Pfobj_t**	Pftable;	/* hash table		*/
72 #define PFTABLE		1019		/* table size		*/
73 static Vmalloc_t*	Vmpf;		/* heap for our own use	*/
74 
75 #if __STD_C
76 static Pfobj_t* pfsearch(Vmalloc_t* vm, const char* file, int line)
77 #else
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					*/
82 #endif
83 {
84 	reg Pfobj_t		*pf, *last;
85 	reg Vmulong_t		h;
86 	reg int			n;
87 	reg const char*		cp;
88 
89 	if(!Vmpf && !(Vmpf = vmopen(Vmdcheap,Vmpool,0)) )
90 		return NIL(Pfobj_t*);
91 
92 	/* make hash table; PFTABLE'th slot hold regions' records */
93 	if(!Pftable)
94 	{	if(!(Pftable = (Pfobj_t**)vmalloc(Vmheap,(PFTABLE+1)*sizeof(Pfobj_t*))) )
95 			return NIL(Pfobj_t*);
96 		for(n = PFTABLE; n >= 0; --n)
97 			Pftable[n] = NIL(Pfobj_t*);
98 	}
99 
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)
107 			break;
108 
109 	/* insert if not there yet */
110 	if(!pf)
111 	{	reg Pfobj_t*	fn;
112 		reg Pfobj_t*	pfvm;
113 		reg Vmulong_t	hn;
114 
115 		/* first get/construct the file name slot */
116 		hn = 0;
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)
122 				break;
123 		if(!fn)
124 		{	reg size_t	s;
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];
129 			Pftable[n] = fn;
130 			PFLINE(fn) = -1;
131 			strcpy(PFNAME(fn),file);
132 		}
133 
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)
137 			if(vm >= PFVM(pfvm))
138 				break;
139 		if(!pfvm || PFVM(pfvm) > vm)
140 		{	if(!(pfvm = (Pfobj_t*)vmalloc(Vmpf,sizeof(Pfobj_t))) )
141 				return NIL(Pfobj_t*);
142 			if(last)
143 			{	pfvm->next = last->next;
144 				last->next = pfvm;
145 			}
146 			else
147 			{	pfvm->next = Pftable[PFTABLE];
148 				Pftable[PFTABLE] = pfvm;
149 			}
150 			PFNALLOC(pfvm) = PFALLOC(pfvm) = 0;
151 			PFNFREE(pfvm) = PFFREE(pfvm) = 0;
152 			PFMAX(pfvm) = 0;
153 			PFVM(pfvm) = vm;
154 			PFLINE(pfvm) = 0;
155 		}
156 
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];
161 		Pftable[n] = pf;
162 		PFLINE(pf) = line;
163 		PFFILE(pf) = PFNAME(fn);
164 		PFREGION(pf) = pfvm;
165 		PFVM(pf) = vm;
166 		PFNALLOC(pf) = 0;
167 		PFALLOC(pf) = 0;
168 		PFNFREE(pf) = 0;
169 		PFFREE(pf) = 0;
170 		PFHASH(pf) = h;
171 	}
172 	else if(last)	/* do a move-to-front */
173 	{	last->next = pf->next;
174 		pf->next = Pftable[n];
175 		Pftable[n] = pf;
176 	}
177 
178 	return pf;
179 }
180 
181 #if __STD_C
182 static void pfclose(Vmalloc_t* vm)
183 #else
184 static void pfclose(vm)
185 Vmalloc_t*	vm;
186 #endif
187 {
188 	reg int		n;
189 	reg Pfobj_t	*pf, *next, *last;
190 
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; )
194 		{	next = pf->next;
195 
196 			if(PFLINE(pf) >= 0 && PFVM(pf) == vm)
197 			{	if(last)
198 					last->next = next;
199 				else	Pftable[n] = next;
200 				vmfree(Vmpf,pf);
201 			}
202 			else	last = pf;
203 
204 			pf = next;
205 		}
206 	}
207 }
208 
209 #if __STD_C
210 static void pfsetinfo(Vmalloc_t* vm, Vmuchar_t* data, size_t size, const char* file, int line)
211 #else
212 static void pfsetinfo(vm, data, size, file, line)
213 Vmalloc_t*	vm;
214 Vmuchar_t*	data;
215 size_t		size;
216 const char*	file;
217 int		line;
218 #endif
219 {
220 	reg Pfobj_t*	pf;
221 	reg Vmulong_t	s;
222 
223 	/* let vmclose knows that there are records for region vm */
224 	_Vmpfclose = pfclose;
225 
226 	if(!file || line <= 0)
227 	{	file = "";
228 		line = 0;
229 	}
230 
231 	if((pf = pfsearch(vm,file,line)) )
232 	{	PFALLOC(pf) += size;
233 		PFNALLOC(pf) += 1;
234 	}
235 	PFOBJ(data) = pf;
236 	PFSIZE(data) = size;
237 
238 	if(pf)
239 	{	/* update region statistics */
240 		pf = PFREGION(pf);
241 		PFALLOC(pf) += size;
242 		PFNALLOC(pf) += 1;
243 		if((s = PFALLOC(pf) - PFFREE(pf)) > PFMAX(pf) )
244 			PFMAX(pf) = s;
245 	}
246 }
247 
248 /* sort by file names and line numbers */
249 #if __STD_C
250 static Pfobj_t* pfsort(Pfobj_t* pf)
251 #else
252 static Pfobj_t* pfsort(pf)
253 Pfobj_t*	pf;
254 #endif
255 {
256 	reg Pfobj_t	*one, *two, *next;
257 	reg int		cmp;
258 
259 	if(!pf->next)
260 		return pf;
261 
262 	/* partition to two equal size lists */
263 	one = two = NIL(Pfobj_t*);
264 	while(pf)
265 	{	next = pf->next;
266 		pf->next = one;
267 		one = pf;
268 
269 		if((pf = next) )
270 		{	next = pf->next;
271 			pf->next = two;
272 			two = pf;
273 			pf = next;
274 		}
275 	}
276 
277 	/* sort and merge the lists */
278 	one = pfsort(one);
279 	two = pfsort(two);
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)
285 			cmp = -1;
286 		else if(PFLINE(two) == 0)
287 			cmp = 1;
288 		else if((cmp = strcmp(PFFILE(one),PFFILE(two))) == 0)
289 		{	cmp = PFLINE(one) - PFLINE(two);
290 			if(cmp == 0)
291 				cmp = PFVM(one) > PFVM(two) ? 1 : -1;
292 		}
293 
294 		if(cmp < 0)
295 		{	if(!pf)
296 				pf = one;
297 			else	next->next = one;
298 			next = one;
299 			if(!(one = one->next) )
300 			{	if(two)
301 					next->next = two;
302 				return pf;
303 			}
304 		}
305 		else
306 		{	if(!pf)
307 				pf = two;
308 			else	next->next = two;
309 			next = two;
310 			if(!(two = two->next) )
311 			{	if(one)
312 					next->next = one;
313 				return pf;
314 			}
315 		}
316 	}
317 }
318 
319 #if __STD_C
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)
322 #else
323 static char* pfsummary(buf, na, sa, nf, sf, max, size)
324 char*		buf;
325 Vmulong_t	na;
326 Vmulong_t	sa;
327 Vmulong_t	nf;
328 Vmulong_t	sf;
329 Vmulong_t	max;
330 Vmulong_t	size;
331 #endif
332 {
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), ':');
341 	if(max > 0)
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), ':');
346 	}
347 	*buf++ = '\n';
348 
349 	return buf;
350 }
351 
352 /* print profile data */
353 #if __STD_C
354 int vmprofile(Vmalloc_t* vm, int fd)
355 #else
356 int vmprofile(vm, fd)
357 Vmalloc_t*	vm;
358 int		fd;
359 #endif
360 {
361 	reg Pfobj_t	*pf, *list, *next, *last;
362 	reg int		n;
363 	reg Vmulong_t	nalloc, alloc, nfree, free;
364 	reg Seg_t*	seg;
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)
369 
370 	if(fd < 0)
371 		return -1;
372 
373 	/* initialize functions from vmtrace.c that we use below */
374 	if((n = vmtrace(-1)) >= 0)
375 		vmtrace(n);
376 
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; )
381 		{	next = pf->next;
382 
383 			if(PFLINE(pf) < 0  || (vm && vm != PFVM(pf)) )
384 			{	last = pf;
385 				goto next_pf;
386 			}
387 
388 			/* remove from hash table */
389 			if(last)
390 				last->next = next;
391 			else	Pftable[n] = next;
392 
393 			/* put on output list */
394 			pf->next = list;
395 			list = pf;
396 			nalloc += PFNALLOC(pf);
397 			alloc += PFALLOC(pf);
398 			nfree += PFNFREE(pf);
399 			free += PFFREE(pf);
400 
401 		next_pf:
402 			pf = next;
403 		}
404 	}
405 
406 	INITBUF();
407 	bufp = (*_Vmstrcpy)(bufp,"ALLOCATION USAGE SUMMARY", ':');
408 	bufp = pfsummary(bufp,nalloc,alloc,nfree,free,0,0);
409 
410 	/* print regions' summary data */
411 	for(pf = Pftable[PFTABLE]; pf; pf = pf->next)
412 	{	if(vm && PFVM(pf) != vm)
413 			continue;
414 		alloc = 0;
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);
421 	}
422 
423 	/* sort then output detailed profile */
424 	list = pfsort(list);
425 	for(pf = list; pf; )
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)
430 				break;
431 			nalloc += PFNALLOC(pf);
432 			alloc += PFALLOC(last);
433 			nfree += PFNFREE(last);
434 			free += PFFREE(last);
435 		}
436 		CHKBUF();
437 		bufp = (*_Vmstrcpy)(bufp,"file",'=');
438 		bufp = (*_Vmstrcpy)(bufp,PFFILE(pf)[0] ? PFFILE(pf) : "<>" ,':');
439 		bufp = pfsummary(bufp,nalloc,alloc,nfree,free,0,0);
440 
441 		while(pf != last)	/* detailed data */
442 		{	CHKBUF();
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);
449 
450 			/* reinsert into hash table */
451 			next = pf->next;
452 			n = (int)(PFHASH(pf)%PFTABLE);
453 			pf->next = Pftable[n];
454 			Pftable[n] = pf;
455 			pf = next;
456 		}
457 	}
458 
459 	FLSBUF();
460 	return 0;
461 }
462 
463 #if __STD_C
464 static Void_t* pfalloc(Vmalloc_t* vm, size_t size)
465 #else
466 static Void_t* pfalloc(vm, size)
467 Vmalloc_t*	vm;
468 size_t		size;
469 #endif
470 {
471 	reg size_t		s;
472 	reg Void_t*		data;
473 	reg char*		file;
474 	reg int			line, local, inuse;
475 	reg Void_t*		func;
476 	reg Vmdata_t*		vd = vm->data;
477 
478 	VMFLF(vm,file,line,func);
479 	SETINUSE(vd, inuse);
480 	if(!(local = vd->mode&VM_TRUST) )
481 	{	GETLOCAL(vd, local);
482 		if(ISLOCK(vd, local))
483 		{	CLRINUSE(vd, inuse);
484 			return NIL(Void_t*);
485 		}
486 		SETLOCK(vd, local);
487 	}
488 
489 	s = ROUND(size,ALIGN) + PF_EXTRA;
490 	if(!(data = KPVALLOC(vm,s,(*(Vmbest->allocf))) ) )
491 		goto done;
492 
493 	pfsetinfo(vm,(Vmuchar_t*)data,size,file,line);
494 
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);
498 	}
499 done:
500 	CLRLOCK(vd, local);
501 	ANNOUNCE(local, vm, VM_ALLOC, (Void_t*)data, vm->disc);
502 	CLRINUSE(vd, inuse);
503 	return data;
504 }
505 
506 #if __STD_C
507 static int pffree(Vmalloc_t* vm, Void_t* data)
508 #else
509 static int pffree(vm, data)
510 Vmalloc_t*	vm;
511 Void_t*		data;
512 #endif
513 {
514 	reg Pfobj_t*		pf;
515 	reg size_t		s;
516 	reg char*		file;
517 	reg int			line, rv, local, inuse;
518 	reg Void_t*		func;
519 	reg Vmdata_t*		vd = vm->data;
520 
521 	VMFLF(vm,file,line,func);
522 
523 	if(!data)
524 		return 0;
525 
526 	SETINUSE(vd, inuse);
527 	if(!(local = vd->mode&VM_TRUST) )
528 	{	GETLOCAL(vd,local);
529 		if(ISLOCK(vd,local))
530 		{	CLRINUSE(vd, inuse);
531 			return -1;
532 		}
533 		SETLOCK(vd,local);
534 	}
535 
536 	if(KPVADDR(vm,data,Vmbest->addrf) != 0 )
537 	{	if(vm->disc->exceptf)
538 			(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
539 		CLRLOCK(vd,0);
540 		CLRINUSE(vd, inuse);
541 		return -1;
542 	}
543 
544 	pf = PFOBJ(data);
545 	s = PFSIZE(data);
546 	if(pf)
547 	{	PFNFREE(pf) += 1;
548 		PFFREE(pf) += s;
549 		pf = PFREGION(pf);
550 		PFNFREE(pf) += 1;
551 		PFFREE(pf) += s;
552 	}
553 
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);
557 	}
558 
559 	rv = KPVFREE((vm), (Void_t*)data, (*Vmbest->freef));
560         CLRLOCK(vd,local);
561         ANNOUNCE(local, vm, VM_FREE, data, vm->disc);
562 	CLRINUSE(vd, inuse);
563 	return rv;
564 }
565 
566 #if __STD_C
567 static Void_t* pfresize(Vmalloc_t* vm, Void_t* data, size_t size, int type)
568 #else
569 static Void_t* pfresize(vm, data, size, type)
570 Vmalloc_t*	vm;
571 Void_t*		data;
572 size_t		size;
573 int		type;
574 #endif
575 {
576 	reg Pfobj_t*		pf;
577 	reg size_t		s;
578 	reg size_t		news;
579 	reg Void_t*		addr;
580 	reg char*		file;
581 	reg int			line, local, inuse;
582 	reg Void_t*		func;
583 	reg size_t		oldsize;
584 	reg Vmdata_t*		vd = vm->data;
585 
586 	SETINUSE(vd, inuse);
587 	if(!data)
588 	{	oldsize = 0;
589 		addr = pfalloc(vm,size);
590 		goto done;
591 	}
592 	if(size == 0)
593 	{	(void)pffree(vm,data);
594 		CLRINUSE(vd, inuse);
595 		return NIL(Void_t*);
596 	}
597 
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);
603 			return NIL(Void_t*);
604 		}
605 		SETLOCK(vd, local);
606 	}
607 
608 	if(KPVADDR(vm,data,Vmbest->addrf) != 0 )
609 	{	if(vm->disc->exceptf)
610 			(void)(*vm->disc->exceptf)(vm,VM_BADADDR,data,vm->disc);
611 		CLRLOCK(vd, local);
612 		CLRINUSE(vd, inuse);
613 		return NIL(Void_t*);
614 	}
615 
616 	pf = PFOBJ(data);
617 	s = oldsize = PFSIZE(data);
618 
619 	news = ROUND(size,ALIGN) + PF_EXTRA;
620 	if((addr = KPVRESIZE(vm,data,news,(type&~VM_RSZERO),Vmbest->resizef)) )
621 	{	if(pf)
622 		{	PFFREE(pf) += s;
623 			PFNFREE(pf) += 1;
624 			pf = PFREGION(pf);
625 			PFFREE(pf) += s;
626 			PFNFREE(pf) += 1;
627 			pfsetinfo(vm,(Vmuchar_t*)addr,size,file,line);
628 		}
629 
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);
633 		}
634 	}
635 	else if(pf)	/* reset old info */
636 	{	PFALLOC(pf) -= s;
637 		PFNALLOC(pf) -= 1;
638 		pf = PFREGION(pf);
639 		PFALLOC(pf) -= s;
640 		PFNALLOC(pf) -= 1;
641 		file = PFFILE(pf);
642 		line = PFLINE(pf);
643 		pfsetinfo(vm,(Vmuchar_t*)data,s,file,line);
644 	}
645 
646 	CLRLOCK(vd, local);
647 	ANNOUNCE(local, vm, VM_RESIZE, (Void_t*)addr, vm->disc);
648 
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);
652 	}
653 
654 	CLRINUSE(vd, inuse);
655 	return addr;
656 }
657 
658 #if __STD_C
659 static long pfsize(Vmalloc_t* vm, Void_t* addr)
660 #else
661 static long pfsize(vm, addr)
662 Vmalloc_t*	vm;
663 Void_t*		addr;
664 #endif
665 {
666 	return (*Vmbest->addrf)(vm,addr) != 0 ? -1L : (long)PFSIZE(addr);
667 }
668 
669 #if __STD_C
670 static long pfaddr(Vmalloc_t* vm, Void_t* addr)
671 #else
672 static long pfaddr(vm, addr)
673 Vmalloc_t*	vm;
674 Void_t*		addr;
675 #endif
676 {
677 	return (*Vmbest->addrf)(vm,addr);
678 }
679 
680 #if __STD_C
681 static int pfcompact(Vmalloc_t* vm)
682 #else
683 static int pfcompact(vm)
684 Vmalloc_t*	vm;
685 #endif
686 {
687 	return (*Vmbest->compactf)(vm);
688 }
689 
690 #if __STD_C
691 static Void_t* pfalign(Vmalloc_t* vm, size_t size, size_t align)
692 #else
693 static Void_t* pfalign(vm, size, align)
694 Vmalloc_t*	vm;
695 size_t		size;
696 size_t		align;
697 #endif
698 {
699 	reg size_t		s;
700 	reg Void_t*		data;
701 	reg char*		file;
702 	reg int			line, local, inuse;
703 	reg Void_t*		func;
704 	reg Vmdata_t*		vd = vm->data;
705 
706 	VMFLF(vm,file,line,func);
707 
708 	SETINUSE(vd, inuse);
709 	if(!(local = vd->mode&VM_TRUST) )
710 	{	GETLOCAL(vd,local);
711 		if(ISLOCK(vd, local))
712 		{	CLRINUSE(vd, inuse);
713 			return NIL(Void_t*);
714 		}
715 		SETLOCK(vd, local);
716 	}
717 
718 	s = (size <= TINYSIZE ? TINYSIZE : ROUND(size,ALIGN)) + PF_EXTRA;
719 	if(!(data = KPVALIGN(vm,s,align,Vmbest->alignf)) )
720 		goto done;
721 
722 	pfsetinfo(vm,(Vmuchar_t*)data,size,file,line);
723 
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);
727 	}
728 done:
729 	CLRLOCK(vd, local);
730 	ANNOUNCE(local, vm, VM_ALLOC, data, vm->disc);
731 	CLRINUSE(vd, inuse);
732 	return data;
733 }
734 
735 static Vmethod_t _Vmprofile =
736 {
737 	pfalloc,
738 	pfresize,
739 	pffree,
740 	pfaddr,
741 	pfsize,
742 	pfcompact,
743 	pfalign,
744 	VM_MTPROFILE
745 };
746 
747 __DEFINE__(Vmethod_t*,Vmprofile,&_Vmprofile);
748 
749 #ifdef NoF
750 NoF(vmprofile)
751 #endif
752 
753 #endif
754