xref: /csrg-svn/sys/kern/subr_prof.c (revision 29946)
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*29946Skarels  *	@(#)subr_prof.c	7.2 (Berkeley) 11/03/86
723380Smckusick  */
87332Ssam 
97332Ssam #ifdef GPROF
1017094Sbloom #include "gprof.h"
1117094Sbloom #include "param.h"
1217094Sbloom #include "systm.h"
137332Ssam 
147332Ssam /*
157332Ssam  * Froms is actually a bunch of unsigned shorts indexing tos
167332Ssam  */
17*29946Skarels int	profiling = 3;
18*29946Skarels u_short	*froms;
19*29946Skarels struct	tostruct *tos = 0;
20*29946Skarels long	tolimit = 0;
21*29946Skarels #if defined(vax)
227332Ssam char	*s_lowpc = (char *)0x80000000;
239758Ssam #endif
24*29946Skarels #if defined(tahoe)
25*29946Skarels char	*s_lowpc = (char *)0xc0000000;
26*29946Skarels #endif
27*29946Skarels extern	char etext;
28*29946Skarels char	*s_highpc = &etext;
297332Ssam u_long	s_textsize = 0;
30*29946Skarels int	ssiz;
317332Ssam u_short	*sbuf;
327332Ssam u_short	*kcount;
337332Ssam 
347332Ssam kmstartup()
357332Ssam {
36*29946Skarels 	u_long fromssize, tossize;
377332Ssam 
3810292Smckusick 	/*
39*29946Skarels 	 * Round lowpc and highpc to multiples of the density we're using
40*29946Skarels 	 * so the rest of the scaling (here and in gprof) stays in ints.
4110292Smckusick 	 */
4210292Smckusick 	s_lowpc = (char *)
43*29946Skarels 	    ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof (HISTCOUNTER));
4410292Smckusick 	s_highpc = (char *)
45*29946Skarels 	    ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof (HISTCOUNTER));
467332Ssam 	s_textsize = s_highpc - s_lowpc;
477332Ssam 	printf("Profiling kernel, s_textsize=%d [%x..%x]\n",
487332Ssam 		s_textsize, s_lowpc, s_highpc);
49*29946Skarels 	ssiz = (s_textsize / HISTFRACTION) + sizeof (struct phdr);
5016781Smckusick 	sbuf = (u_short *)calloc(ssiz);
517332Ssam 	if (sbuf == 0) {
527332Ssam 		printf("No space for monitor buffer(s)\n");
537332Ssam 		return;
547332Ssam 	}
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 	tolimit = s_textsize * ARCDENSITY / 100;
64*29946Skarels 	if (tolimit < MINARCS)
6510292Smckusick 		tolimit = MINARCS;
66*29946Skarels 	else if (tolimit > (0xffff - 1))
67*29946Skarels 		tolimit = 0xffff - 1;
68*29946Skarels 	tossize = tolimit * sizeof (struct tostruct);
6916781Smckusick 	tos = (struct tostruct *)calloc(tossize);
707332Ssam 	if (tos == 0) {
717332Ssam 		printf("No space for monitor buffer(s)\n");
72*29946Skarels 		cfreemem(sbuf, ssiz), sbuf = 0;
73*29946Skarels 		cfreemem(froms, fromssize), froms = 0;
747332Ssam 		return;
757332Ssam 	}
767332Ssam 	tos[0].link = 0;
777332Ssam 	((struct phdr *)sbuf)->lpc = s_lowpc;
787332Ssam 	((struct phdr *)sbuf)->hpc = s_highpc;
797332Ssam 	((struct phdr *)sbuf)->ncnt = ssiz;
80*29946Skarels 	kcount = (u_short *)(((int)sbuf) + sizeof (struct phdr));
817332Ssam #ifdef notdef
8210292Smckusick 	/*
83*29946Skarels 	 * Profiling is what mcount checks to see if
84*29946Skarels 	 * all the data structures are ready!!!
8510292Smckusick 	 */
867332Ssam 	profiling = 0;		/* patch by hand when you're ready */
877332Ssam #endif
887332Ssam }
897332Ssam 
907332Ssam /*
91*29946Skarels  * This routine is massaged so that it may be jsb'ed to on vax.
927332Ssam  */
9310292Smckusick asm(".text");
9410292Smckusick asm("#the beginning of mcount()");
9510292Smckusick asm(".data");
967332Ssam mcount()
977332Ssam {
98*29946Skarels 	register char *selfpc;			/* r11 => r5 */
99*29946Skarels 	register u_short *frompcindex;		/* r10 => r4 */
100*29946Skarels 	register struct tostruct *top;		/* r9  => r3 */
101*29946Skarels 	register struct tostruct *prevtop;	/* r8  => r2 */
102*29946Skarels 	register long toindex;			/* r7  => r1 */
10316924Smckusick 	static int s;
1047332Ssam 
105*29946Skarels 	asm("	.text");		/* make sure we're in text space */
106*29946Skarels 	/*
107*29946Skarels 	 * Check that we are profiling.
108*29946Skarels 	 */
109*29946Skarels 	if (profiling)
110*29946Skarels 		goto out;
111*29946Skarels 	/*
112*29946Skarels 	 * Find the return address for mcount,
113*29946Skarels 	 * and the return address for mcount's caller.
114*29946Skarels 	 */
1157332Ssam #ifdef lint
11610292Smckusick 	selfpc = (char *)0;
1177332Ssam 	frompcindex = 0;
118*29946Skarels #else
119*29946Skarels #if defined(vax)
1207332Ssam 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
1217332Ssam 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
122*29946Skarels #endif
123*29946Skarels #if defined(tahoe)
124*29946Skarels 	;				/* avoid label botch */
125*29946Skarels 	asm("	movl -8(fp),r12");	/* selfpc = callf frame */
126*29946Skarels 	asm("	movl (fp),r11");
127*29946Skarels 	asm("	movl -8(r11),r11");	/* frompcindex = 1 callf frame back */
128*29946Skarels #endif
129*29946Skarels #endif
1307332Ssam 	/*
131*29946Skarels 	 * Insure that we cannot be recursively invoked.
132*29946Skarels 	 * this requires that splhigh() and splx() below
133*29946Skarels 	 * do NOT call mcount!
1347332Ssam 	 */
13516924Smckusick 	s = splhigh();
13616924Smckusick 	/*
137*29946Skarels 	 * Check that frompcindex is a reasonable pc value.
138*29946Skarels 	 * For example:	signal catchers get called from the stack,
139*29946Skarels 	 *	not from text space.  too bad.
1407332Ssam 	 */
141*29946Skarels 	frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc);
142*29946Skarels 	if ((u_long)frompcindex > s_textsize)
1437332Ssam 		goto done;
14410292Smckusick 	frompcindex =
145*29946Skarels 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))];
14610292Smckusick 	toindex = *frompcindex;
14710292Smckusick 	if (toindex == 0) {
14810292Smckusick 		/*
149*29946Skarels 		 * First time traversing this arc
15010292Smckusick 		 */
15110292Smckusick 		toindex = ++tos[0].link;
152*29946Skarels 		if (toindex >= tolimit)
1537332Ssam 			goto overflow;
15410292Smckusick 		*frompcindex = toindex;
15510292Smckusick 		top = &tos[toindex];
1567332Ssam 		top->selfpc = selfpc;
15710292Smckusick 		top->count = 1;
1587332Ssam 		top->link = 0;
15910292Smckusick 		goto done;
1607332Ssam 	}
16110292Smckusick 	top = &tos[toindex];
16210292Smckusick 	if (top->selfpc == selfpc) {
16310292Smckusick 		/*
164*29946Skarels 		 * Arc at front of chain; usual case.
16510292Smckusick 		 */
16610292Smckusick 		top->count++;
16710292Smckusick 		goto done;
16810292Smckusick 	}
16910292Smckusick 	/*
170*29946Skarels 	 * Have to go looking down chain for it.
171*29946Skarels 	 * Top points to what we are looking at,
172*29946Skarels 	 * prevtop points to previous top.
173*29946Skarels 	 * We know it is not at the head of the chain.
17410292Smckusick 	 */
17510292Smckusick 	for (; /* goto done */; ) {
17610292Smckusick 		if (top->link == 0) {
17710292Smckusick 			/*
178*29946Skarels 			 * Top is end of the chain and none of the chain
179*29946Skarels 			 * had top->selfpc == selfpc.
180*29946Skarels 			 * So we allocate a new tostruct
181*29946Skarels 			 * and link it to the head of the chain.
18210292Smckusick 			 */
18310292Smckusick 			toindex = ++tos[0].link;
184*29946Skarels 			if (toindex >= tolimit)
18510292Smckusick 				goto overflow;
18610292Smckusick 			top = &tos[toindex];
18710292Smckusick 			top->selfpc = selfpc;
18810292Smckusick 			top->count = 1;
18910292Smckusick 			top->link = *frompcindex;
19010292Smckusick 			*frompcindex = toindex;
19110292Smckusick 			goto done;
19210292Smckusick 		}
19310292Smckusick 		/*
194*29946Skarels 		 * Otherwise, check the next arc on the chain.
19510292Smckusick 		 */
19610292Smckusick 		prevtop = top;
19710292Smckusick 		top = &tos[top->link];
1987332Ssam 		if (top->selfpc == selfpc) {
19910292Smckusick 			/*
200*29946Skarels 			 * There it is, increment its count and
201*29946Skarels 			 * move it to the head of the chain.
20210292Smckusick 			 */
2037332Ssam 			top->count++;
20410292Smckusick 			toindex = prevtop->link;
20510292Smckusick 			prevtop->link = top->link;
20610292Smckusick 			top->link = *frompcindex;
20710292Smckusick 			*frompcindex = toindex;
20810292Smckusick 			goto done;
2097332Ssam 		}
21010292Smckusick 
2117332Ssam 	}
2127332Ssam done:
21316924Smckusick 	splx(s);
2147332Ssam 	/* and fall through */
2157332Ssam out:
216*29946Skarels #if defined(vax)
2177332Ssam 	asm("	rsb");
218*29946Skarels #endif
219*29946Skarels 	return;
2207332Ssam overflow:
22110292Smckusick 	profiling = 3;
2227332Ssam 	printf("mcount: tos overflow\n");
2237332Ssam 	goto out;
2247332Ssam }
22510292Smckusick asm(".text");
22610292Smckusick asm("#the end of mcount()");
22710292Smckusick asm(".data");
228*29946Skarels #endif
229