xref: /csrg-svn/sys/kern/subr_prof.c (revision 29100)
123380Smckusick /*
2*29100Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
323380Smckusick  * All rights reserved.  The Berkeley software License Agreement
423380Smckusick  * specifies the terms and conditions for redistribution.
523380Smckusick  *
6*29100Smckusick  *	@(#)subr_prof.c	7.1 (Berkeley) 06/05/86
723380Smckusick  */
87332Ssam 
910292Smckusick /* last integrated from: gmon.c	4.10 (Berkeley) 1/14/83 */
1010292Smckusick 
117332Ssam #ifdef GPROF
1217094Sbloom #include "gprof.h"
1317094Sbloom #include "param.h"
1417094Sbloom #include "systm.h"
157332Ssam 
167332Ssam /*
177332Ssam  * Froms is actually a bunch of unsigned shorts indexing tos
187332Ssam  */
1910292Smckusick int profiling = 3;
2010292Smckusick u_short *froms;
2110292Smckusick struct tostruct *tos = 0;
2210292Smckusick long tolimit = 0;
239758Ssam #ifdef vax
247332Ssam char	*s_lowpc = (char *)0x80000000;
259758Ssam #endif
2610292Smckusick extern char etext;
2710292Smckusick char *s_highpc = &etext;
287332Ssam u_long	s_textsize = 0;
2910292Smckusick int ssiz;
307332Ssam u_short	*sbuf;
317332Ssam u_short	*kcount;
327332Ssam 
337332Ssam kmstartup()
347332Ssam {
3510292Smckusick 	u_long	fromssize, tossize;
367332Ssam 
3710292Smckusick 	/*
3810292Smckusick 	 *	round lowpc and highpc to multiples of the density we're using
3910292Smckusick 	 *	so the rest of the scaling (here and in gprof) stays in ints.
4010292Smckusick 	 */
4110292Smckusick 	s_lowpc = (char *)
4210292Smckusick 	    ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof(HISTCOUNTER));
4310292Smckusick 	s_highpc = (char *)
4410292Smckusick 	    ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof(HISTCOUNTER));
457332Ssam 	s_textsize = s_highpc - s_lowpc;
467332Ssam 	printf("Profiling kernel, s_textsize=%d [%x..%x]\n",
477332Ssam 		s_textsize, s_lowpc, s_highpc);
4810292Smckusick 	ssiz = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
4916781Smckusick 	sbuf = (u_short *)calloc(ssiz);
507332Ssam 	if (sbuf == 0) {
517332Ssam 		printf("No space for monitor buffer(s)\n");
527332Ssam 		return;
537332Ssam 	}
547332Ssam 	blkclr((caddr_t)sbuf, ssiz);
5510292Smckusick 	fromssize = s_textsize / HASHFRACTION;
5616781Smckusick 	froms = (u_short *)calloc(fromssize);
577332Ssam 	if (froms == 0) {
587332Ssam 		printf("No space for monitor buffer(s)\n");
5916781Smckusick 		cfreemem(sbuf, ssiz);
607332Ssam 		sbuf = 0;
617332Ssam 		return;
627332Ssam 	}
6310292Smckusick 	blkclr((caddr_t)froms, fromssize);
6410292Smckusick 	tolimit = s_textsize * ARCDENSITY / 100;
6510292Smckusick 	if (tolimit < MINARCS) {
6610292Smckusick 		tolimit = MINARCS;
6710292Smckusick 	} else if (tolimit > 65534) {
6810292Smckusick 		tolimit = 65534;
6910292Smckusick 	}
7010292Smckusick 	tossize = tolimit * sizeof(struct tostruct);
7116781Smckusick 	tos = (struct tostruct *)calloc(tossize);
727332Ssam 	if (tos == 0) {
737332Ssam 		printf("No space for monitor buffer(s)\n");
7416781Smckusick 		cfreemem(sbuf, ssiz);
757332Ssam 		sbuf = 0;
7616781Smckusick 		cfreemem(froms, fromssize);
777332Ssam 		froms = 0;
787332Ssam 		return;
797332Ssam 	}
8010292Smckusick 	blkclr((caddr_t)tos, tossize);
817332Ssam 	tos[0].link = 0;
827332Ssam 	((struct phdr *)sbuf)->lpc = s_lowpc;
837332Ssam 	((struct phdr *)sbuf)->hpc = s_highpc;
847332Ssam 	((struct phdr *)sbuf)->ncnt = ssiz;
857332Ssam 	kcount = (u_short *)(((int)sbuf) + sizeof(struct phdr));
867332Ssam #ifdef notdef
8710292Smckusick 	/*
8810292Smckusick 	 *	profiling is what mcount checks to see if
8910292Smckusick 	 *	all the data structures are ready!!!
9010292Smckusick 	 */
917332Ssam 	profiling = 0;		/* patch by hand when you're ready */
927332Ssam #endif
937332Ssam }
947332Ssam 
959758Ssam #ifdef vax
967332Ssam /*
977332Ssam  * This routine is massaged so that it may be jsb'ed to
987332Ssam  */
9910292Smckusick asm(".text");
10010292Smckusick asm("#the beginning of mcount()");
10110292Smckusick asm(".data");
1027332Ssam mcount()
1037332Ssam {
10410292Smckusick 	register char			*selfpc;	/* r11 => r5 */
10510292Smckusick 	register unsigned short		*frompcindex;	/* r10 => r4 */
10610292Smckusick 	register struct tostruct	*top;		/* r9  => r3 */
10710292Smckusick 	register struct tostruct	*prevtop;	/* r8  => r2 */
10810292Smckusick 	register long			toindex;	/* r7  => r1 */
10916924Smckusick 	static int s;
1107332Ssam 
1117332Ssam #ifdef lint
11210292Smckusick 	selfpc = (char *)0;
1137332Ssam 	frompcindex = 0;
1147332Ssam #else not lint
1157332Ssam 	/*
11610292Smckusick 	 *	find the return address for mcount,
11710292Smckusick 	 *	and the return address for mcount's caller.
1187332Ssam 	 */
11910292Smckusick 	asm("	.text");		/* make sure we're in text space */
1207332Ssam 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
1217332Ssam 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
1227332Ssam #endif not lint
1237332Ssam 	/*
12410292Smckusick 	 *	check that we are profiling
1257332Ssam 	 */
12610292Smckusick 	if (profiling) {
1277332Ssam 		goto out;
12810292Smckusick 	}
1297332Ssam 	/*
13016924Smckusick 	 *	insure that we cannot be recursively invoked.
13116924Smckusick 	 *	this requires that splhigh() and splx() below
13216924Smckusick 	 *	do NOT call mcount!
13316924Smckusick 	 */
13416924Smckusick 	s = splhigh();
13516924Smckusick 	/*
13610292Smckusick 	 *	check that frompcindex is a reasonable pc value.
13710292Smckusick 	 *	for example:	signal catchers get called from the stack,
13810292Smckusick 	 *			not from text space.  too bad.
1397332Ssam 	 */
14010292Smckusick 	frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
14110292Smckusick 	if ((unsigned long)frompcindex > s_textsize) {
1427332Ssam 		goto done;
14310292Smckusick 	}
14410292Smckusick 	frompcindex =
14510292Smckusick 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))];
14610292Smckusick 	toindex = *frompcindex;
14710292Smckusick 	if (toindex == 0) {
14810292Smckusick 		/*
14910292Smckusick 		 *	first time traversing this arc
15010292Smckusick 		 */
15110292Smckusick 		toindex = ++tos[0].link;
15210292Smckusick 		if (toindex >= tolimit) {
1537332Ssam 			goto overflow;
15410292Smckusick 		}
15510292Smckusick 		*frompcindex = toindex;
15610292Smckusick 		top = &tos[toindex];
1577332Ssam 		top->selfpc = selfpc;
15810292Smckusick 		top->count = 1;
1597332Ssam 		top->link = 0;
16010292Smckusick 		goto done;
1617332Ssam 	}
16210292Smckusick 	top = &tos[toindex];
16310292Smckusick 	if (top->selfpc == selfpc) {
16410292Smckusick 		/*
16510292Smckusick 		 *	arc at front of chain; usual case.
16610292Smckusick 		 */
16710292Smckusick 		top->count++;
16810292Smckusick 		goto done;
16910292Smckusick 	}
17010292Smckusick 	/*
17110292Smckusick 	 *	have to go looking down chain for it.
17210292Smckusick 	 *	top points to what we are looking at,
17310292Smckusick 	 *	prevtop points to previous top.
17410292Smckusick 	 *	we know it is not at the head of the chain.
17510292Smckusick 	 */
17610292Smckusick 	for (; /* goto done */; ) {
17710292Smckusick 		if (top->link == 0) {
17810292Smckusick 			/*
17910292Smckusick 			 *	top is end of the chain and none of the chain
18010292Smckusick 			 *	had top->selfpc == selfpc.
18110292Smckusick 			 *	so we allocate a new tostruct
18210292Smckusick 			 *	and link it to the head of the chain.
18310292Smckusick 			 */
18410292Smckusick 			toindex = ++tos[0].link;
18510292Smckusick 			if (toindex >= tolimit) {
18610292Smckusick 				goto overflow;
18710292Smckusick 			}
18810292Smckusick 			top = &tos[toindex];
18910292Smckusick 			top->selfpc = selfpc;
19010292Smckusick 			top->count = 1;
19110292Smckusick 			top->link = *frompcindex;
19210292Smckusick 			*frompcindex = toindex;
19310292Smckusick 			goto done;
19410292Smckusick 		}
19510292Smckusick 		/*
19610292Smckusick 		 *	otherwise, check the next arc on the chain.
19710292Smckusick 		 */
19810292Smckusick 		prevtop = top;
19910292Smckusick 		top = &tos[top->link];
2007332Ssam 		if (top->selfpc == selfpc) {
20110292Smckusick 			/*
20210292Smckusick 			 *	there it is.
20310292Smckusick 			 *	increment its count
20410292Smckusick 			 *	move it to the head of the chain.
20510292Smckusick 			 */
2067332Ssam 			top->count++;
20710292Smckusick 			toindex = prevtop->link;
20810292Smckusick 			prevtop->link = top->link;
20910292Smckusick 			top->link = *frompcindex;
21010292Smckusick 			*frompcindex = toindex;
21110292Smckusick 			goto done;
2127332Ssam 		}
21310292Smckusick 
2147332Ssam 	}
2157332Ssam done:
21616924Smckusick 	splx(s);
2177332Ssam 	/* and fall through */
2187332Ssam out:
2197332Ssam 	asm("	rsb");
2207332Ssam 
2217332Ssam overflow:
22210292Smckusick 	profiling = 3;
2237332Ssam 	printf("mcount: tos overflow\n");
2247332Ssam 	goto out;
2257332Ssam }
22610292Smckusick asm(".text");
22710292Smckusick asm("#the end of mcount()");
22810292Smckusick asm(".data");
22910292Smckusick #endif vax
2307332Ssam #endif GPROF
231