xref: /csrg-svn/sys/kern/subr_prof.c (revision 33366)
123380Smckusick /*
229100Smckusick  * 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*33366Smckusick  *	@(#)subr_prof.c	7.5 (Berkeley) 01/19/88
723380Smckusick  */
87332Ssam 
97332Ssam #ifdef GPROF
1017094Sbloom #include "gprof.h"
1117094Sbloom #include "param.h"
1217094Sbloom #include "systm.h"
1331433Smckusick #include "malloc.h"
147332Ssam 
157332Ssam /*
167332Ssam  * Froms is actually a bunch of unsigned shorts indexing tos
177332Ssam  */
1829946Skarels int	profiling = 3;
1929946Skarels u_short	*froms;
2029946Skarels struct	tostruct *tos = 0;
2129946Skarels long	tolimit = 0;
2229946Skarels #if defined(vax)
237332Ssam char	*s_lowpc = (char *)0x80000000;
249758Ssam #endif
2529946Skarels #if defined(tahoe)
2629946Skarels char	*s_lowpc = (char *)0xc0000000;
2729946Skarels #endif
2829946Skarels extern	char etext;
2929946Skarels char	*s_highpc = &etext;
307332Ssam u_long	s_textsize = 0;
3129946Skarels int	ssiz;
327332Ssam u_short	*sbuf;
337332Ssam u_short	*kcount;
347332Ssam 
357332Ssam kmstartup()
367332Ssam {
3729946Skarels 	u_long fromssize, tossize;
387332Ssam 
3910292Smckusick 	/*
4029946Skarels 	 * Round lowpc and highpc to multiples of the density we're using
4129946Skarels 	 * so the rest of the scaling (here and in gprof) stays in ints.
4210292Smckusick 	 */
4310292Smckusick 	s_lowpc = (char *)
4429946Skarels 	    ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof (HISTCOUNTER));
4510292Smckusick 	s_highpc = (char *)
4629946Skarels 	    ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof (HISTCOUNTER));
477332Ssam 	s_textsize = s_highpc - s_lowpc;
487332Ssam 	printf("Profiling kernel, s_textsize=%d [%x..%x]\n",
497332Ssam 		s_textsize, s_lowpc, s_highpc);
5029946Skarels 	ssiz = (s_textsize / HISTFRACTION) + sizeof (struct phdr);
5131433Smckusick 	sbuf = (u_short *)malloc(ssiz, M_GPROF, M_WAITOK);
527332Ssam 	if (sbuf == 0) {
537332Ssam 		printf("No space for monitor buffer(s)\n");
547332Ssam 		return;
557332Ssam 	}
5631922Smckusick 	bzero(sbuf, ssiz);
5710292Smckusick 	fromssize = s_textsize / HASHFRACTION;
5831433Smckusick 	froms = (u_short *)malloc(fromssize, M_GPROF, M_WAITOK);
597332Ssam 	if (froms == 0) {
607332Ssam 		printf("No space for monitor buffer(s)\n");
6131433Smckusick 		free(sbuf, M_GPROF);
627332Ssam 		sbuf = 0;
637332Ssam 		return;
647332Ssam 	}
6531922Smckusick 	bzero(froms, fromsize);
6610292Smckusick 	tolimit = s_textsize * ARCDENSITY / 100;
6729946Skarels 	if (tolimit < MINARCS)
6810292Smckusick 		tolimit = MINARCS;
6929946Skarels 	else if (tolimit > (0xffff - 1))
7029946Skarels 		tolimit = 0xffff - 1;
7129946Skarels 	tossize = tolimit * sizeof (struct tostruct);
7231433Smckusick 	tos = (struct tostruct *)malloc(tossize, M_GPROF, M_WAITOK);
737332Ssam 	if (tos == 0) {
747332Ssam 		printf("No space for monitor buffer(s)\n");
7531433Smckusick 		free(sbuf, M_GPROF), sbuf = 0;
7631433Smckusick 		free(froms, M_GPROF), froms = 0;
777332Ssam 		return;
787332Ssam 	}
7931922Smckusick 	bzero(tos, tossize);
807332Ssam 	tos[0].link = 0;
817332Ssam 	((struct phdr *)sbuf)->lpc = s_lowpc;
827332Ssam 	((struct phdr *)sbuf)->hpc = s_highpc;
837332Ssam 	((struct phdr *)sbuf)->ncnt = ssiz;
8429946Skarels 	kcount = (u_short *)(((int)sbuf) + sizeof (struct phdr));
857332Ssam #ifdef notdef
8610292Smckusick 	/*
8729946Skarels 	 * Profiling is what mcount checks to see if
8829946Skarels 	 * all the data structures are ready!!!
8910292Smckusick 	 */
907332Ssam 	profiling = 0;		/* patch by hand when you're ready */
917332Ssam #endif
927332Ssam }
937332Ssam 
947332Ssam /*
9529946Skarels  * This routine is massaged so that it may be jsb'ed to on vax.
967332Ssam  */
9710292Smckusick asm(".text");
9810292Smckusick asm("#the beginning of mcount()");
9910292Smckusick asm(".data");
1007332Ssam mcount()
1017332Ssam {
10229946Skarels 	register char *selfpc;			/* r11 => r5 */
10329946Skarels 	register u_short *frompcindex;		/* r10 => r4 */
10429946Skarels 	register struct tostruct *top;		/* r9  => r3 */
10529946Skarels 	register struct tostruct *prevtop;	/* r8  => r2 */
10629946Skarels 	register long toindex;			/* r7  => r1 */
10716924Smckusick 	static int s;
1087332Ssam 
10929946Skarels 	asm("	.text");		/* make sure we're in text space */
11029946Skarels 	/*
11129946Skarels 	 * Check that we are profiling.
11229946Skarels 	 */
11329946Skarels 	if (profiling)
11429946Skarels 		goto out;
11529946Skarels 	/*
11629946Skarels 	 * Find the return address for mcount,
11729946Skarels 	 * and the return address for mcount's caller.
11829946Skarels 	 */
1197332Ssam #ifdef lint
12010292Smckusick 	selfpc = (char *)0;
1217332Ssam 	frompcindex = 0;
12229946Skarels #else
123*33366Smckusick 	;				/* avoid label botch */
12429946Skarels #if defined(vax)
1257332Ssam 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
1267332Ssam 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
12729946Skarels #endif
12829946Skarels #if defined(tahoe)
12929946Skarels 	asm("	movl -8(fp),r12");	/* selfpc = callf frame */
13029946Skarels 	asm("	movl (fp),r11");
13129946Skarels 	asm("	movl -8(r11),r11");	/* frompcindex = 1 callf frame back */
13229946Skarels #endif
13329946Skarels #endif
1347332Ssam 	/*
13529946Skarels 	 * Insure that we cannot be recursively invoked.
13629946Skarels 	 * this requires that splhigh() and splx() below
13729946Skarels 	 * do NOT call mcount!
1387332Ssam 	 */
13916924Smckusick 	s = splhigh();
14016924Smckusick 	/*
14129946Skarels 	 * Check that frompcindex is a reasonable pc value.
14229946Skarels 	 * For example:	signal catchers get called from the stack,
14329946Skarels 	 *	not from text space.  too bad.
1447332Ssam 	 */
14529946Skarels 	frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc);
14629946Skarels 	if ((u_long)frompcindex > s_textsize)
1477332Ssam 		goto done;
14810292Smckusick 	frompcindex =
14929946Skarels 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))];
15010292Smckusick 	toindex = *frompcindex;
15110292Smckusick 	if (toindex == 0) {
15210292Smckusick 		/*
15329946Skarels 		 * First time traversing this arc
15410292Smckusick 		 */
15510292Smckusick 		toindex = ++tos[0].link;
15629946Skarels 		if (toindex >= tolimit)
1577332Ssam 			goto overflow;
15810292Smckusick 		*frompcindex = toindex;
15910292Smckusick 		top = &tos[toindex];
1607332Ssam 		top->selfpc = selfpc;
16110292Smckusick 		top->count = 1;
1627332Ssam 		top->link = 0;
16310292Smckusick 		goto done;
1647332Ssam 	}
16510292Smckusick 	top = &tos[toindex];
16610292Smckusick 	if (top->selfpc == selfpc) {
16710292Smckusick 		/*
16829946Skarels 		 * Arc at front of chain; usual case.
16910292Smckusick 		 */
17010292Smckusick 		top->count++;
17110292Smckusick 		goto done;
17210292Smckusick 	}
17310292Smckusick 	/*
17429946Skarels 	 * Have to go looking down chain for it.
17529946Skarels 	 * Top points to what we are looking at,
17629946Skarels 	 * prevtop points to previous top.
17729946Skarels 	 * We know it is not at the head of the chain.
17810292Smckusick 	 */
17910292Smckusick 	for (; /* goto done */; ) {
18010292Smckusick 		if (top->link == 0) {
18110292Smckusick 			/*
18229946Skarels 			 * Top is end of the chain and none of the chain
18329946Skarels 			 * had top->selfpc == selfpc.
18429946Skarels 			 * So we allocate a new tostruct
18529946Skarels 			 * and link it to the head of the chain.
18610292Smckusick 			 */
18710292Smckusick 			toindex = ++tos[0].link;
18829946Skarels 			if (toindex >= tolimit)
18910292Smckusick 				goto overflow;
19010292Smckusick 			top = &tos[toindex];
19110292Smckusick 			top->selfpc = selfpc;
19210292Smckusick 			top->count = 1;
19310292Smckusick 			top->link = *frompcindex;
19410292Smckusick 			*frompcindex = toindex;
19510292Smckusick 			goto done;
19610292Smckusick 		}
19710292Smckusick 		/*
19829946Skarels 		 * Otherwise, check the next arc on the chain.
19910292Smckusick 		 */
20010292Smckusick 		prevtop = top;
20110292Smckusick 		top = &tos[top->link];
2027332Ssam 		if (top->selfpc == selfpc) {
20310292Smckusick 			/*
20429946Skarels 			 * There it is, increment its count and
20529946Skarels 			 * move it to the head of the chain.
20610292Smckusick 			 */
2077332Ssam 			top->count++;
20810292Smckusick 			toindex = prevtop->link;
20910292Smckusick 			prevtop->link = top->link;
21010292Smckusick 			top->link = *frompcindex;
21110292Smckusick 			*frompcindex = toindex;
21210292Smckusick 			goto done;
2137332Ssam 		}
21410292Smckusick 
2157332Ssam 	}
2167332Ssam done:
21716924Smckusick 	splx(s);
2187332Ssam 	/* and fall through */
2197332Ssam out:
22029946Skarels #if defined(vax)
2217332Ssam 	asm("	rsb");
22229946Skarels #endif
22329946Skarels 	return;
2247332Ssam overflow:
22510292Smckusick 	profiling = 3;
2267332Ssam 	printf("mcount: tos overflow\n");
2277332Ssam 	goto out;
2287332Ssam }
22910292Smckusick asm(".text");
23010292Smckusick asm("#the end of mcount()");
23110292Smckusick asm(".data");
23229946Skarels #endif
233