xref: /csrg-svn/sys/kern/subr_prof.c (revision 41966)
123380Smckusick /*
229100Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
3*41966Smckusick  * All rights reserved.
423380Smckusick  *
5*41966Smckusick  * %sccs.include.redist.c%
6*41966Smckusick  *
7*41966Smckusick  *	@(#)subr_prof.c	7.7 (Berkeley) 05/15/90
823380Smckusick  */
97332Ssam 
107332Ssam #ifdef GPROF
1117094Sbloom #include "gprof.h"
1217094Sbloom #include "param.h"
1317094Sbloom #include "systm.h"
1431433Smckusick #include "malloc.h"
157332Ssam 
167332Ssam /*
177332Ssam  * Froms is actually a bunch of unsigned shorts indexing tos
187332Ssam  */
1929946Skarels int	profiling = 3;
2029946Skarels u_short	*froms;
2129946Skarels struct	tostruct *tos = 0;
2229946Skarels long	tolimit = 0;
2329946Skarels #if defined(vax)
247332Ssam char	*s_lowpc = (char *)0x80000000;
259758Ssam #endif
2629946Skarels #if defined(tahoe)
2729946Skarels char	*s_lowpc = (char *)0xc0000000;
2829946Skarels #endif
29*41966Smckusick #if defined(hp300)
30*41966Smckusick char	*s_lowpc = (char *)0x00000000;
31*41966Smckusick #endif
3229946Skarels extern	char etext;
3329946Skarels char	*s_highpc = &etext;
347332Ssam u_long	s_textsize = 0;
3529946Skarels int	ssiz;
367332Ssam u_short	*sbuf;
377332Ssam u_short	*kcount;
387332Ssam 
397332Ssam kmstartup()
407332Ssam {
4129946Skarels 	u_long fromssize, tossize;
427332Ssam 
4310292Smckusick 	/*
4429946Skarels 	 * Round lowpc and highpc to multiples of the density we're using
4529946Skarels 	 * so the rest of the scaling (here and in gprof) stays in ints.
4610292Smckusick 	 */
4710292Smckusick 	s_lowpc = (char *)
4829946Skarels 	    ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof (HISTCOUNTER));
4910292Smckusick 	s_highpc = (char *)
5029946Skarels 	    ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof (HISTCOUNTER));
517332Ssam 	s_textsize = s_highpc - s_lowpc;
527332Ssam 	printf("Profiling kernel, s_textsize=%d [%x..%x]\n",
537332Ssam 		s_textsize, s_lowpc, s_highpc);
5429946Skarels 	ssiz = (s_textsize / HISTFRACTION) + sizeof (struct phdr);
5531433Smckusick 	sbuf = (u_short *)malloc(ssiz, M_GPROF, M_WAITOK);
567332Ssam 	if (sbuf == 0) {
577332Ssam 		printf("No space for monitor buffer(s)\n");
587332Ssam 		return;
597332Ssam 	}
6031922Smckusick 	bzero(sbuf, ssiz);
6110292Smckusick 	fromssize = s_textsize / HASHFRACTION;
6231433Smckusick 	froms = (u_short *)malloc(fromssize, M_GPROF, M_WAITOK);
637332Ssam 	if (froms == 0) {
647332Ssam 		printf("No space for monitor buffer(s)\n");
6531433Smckusick 		free(sbuf, M_GPROF);
667332Ssam 		sbuf = 0;
677332Ssam 		return;
687332Ssam 	}
6937535Smckusick 	bzero(froms, fromssize);
7010292Smckusick 	tolimit = s_textsize * ARCDENSITY / 100;
7129946Skarels 	if (tolimit < MINARCS)
7210292Smckusick 		tolimit = MINARCS;
7329946Skarels 	else if (tolimit > (0xffff - 1))
7429946Skarels 		tolimit = 0xffff - 1;
7529946Skarels 	tossize = tolimit * sizeof (struct tostruct);
7631433Smckusick 	tos = (struct tostruct *)malloc(tossize, M_GPROF, M_WAITOK);
777332Ssam 	if (tos == 0) {
787332Ssam 		printf("No space for monitor buffer(s)\n");
7931433Smckusick 		free(sbuf, M_GPROF), sbuf = 0;
8031433Smckusick 		free(froms, M_GPROF), froms = 0;
817332Ssam 		return;
827332Ssam 	}
8331922Smckusick 	bzero(tos, tossize);
847332Ssam 	tos[0].link = 0;
857332Ssam 	((struct phdr *)sbuf)->lpc = s_lowpc;
867332Ssam 	((struct phdr *)sbuf)->hpc = s_highpc;
877332Ssam 	((struct phdr *)sbuf)->ncnt = ssiz;
8829946Skarels 	kcount = (u_short *)(((int)sbuf) + sizeof (struct phdr));
897332Ssam }
907332Ssam 
917332Ssam /*
92*41966Smckusick  * Special, non-profiled versions
93*41966Smckusick  */
94*41966Smckusick #if defined(hp300)
95*41966Smckusick #define splhigh	_splhigh
96*41966Smckusick #define splx	_splx
97*41966Smckusick #endif
98*41966Smckusick 
99*41966Smckusick /*
10029946Skarels  * This routine is massaged so that it may be jsb'ed to on vax.
1017332Ssam  */
10210292Smckusick asm(".text");
10310292Smckusick asm("#the beginning of mcount()");
10410292Smckusick asm(".data");
1057332Ssam mcount()
1067332Ssam {
10729946Skarels 	register char *selfpc;			/* r11 => r5 */
10829946Skarels 	register u_short *frompcindex;		/* r10 => r4 */
10929946Skarels 	register struct tostruct *top;		/* r9  => r3 */
11029946Skarels 	register struct tostruct *prevtop;	/* r8  => r2 */
11129946Skarels 	register long toindex;			/* r7  => r1 */
11216924Smckusick 	static int s;
1137332Ssam 
11429946Skarels 	asm("	.text");		/* make sure we're in text space */
11529946Skarels 	/*
11629946Skarels 	 * Check that we are profiling.
11729946Skarels 	 */
11829946Skarels 	if (profiling)
11929946Skarels 		goto out;
12029946Skarels 	/*
12129946Skarels 	 * Find the return address for mcount,
12229946Skarels 	 * and the return address for mcount's caller.
12329946Skarels 	 */
1247332Ssam #ifdef lint
12510292Smckusick 	selfpc = (char *)0;
1267332Ssam 	frompcindex = 0;
12729946Skarels #else
12833366Smckusick 	;				/* avoid label botch */
129*41966Smckusick #ifdef __GNUC__
13029946Skarels #if defined(vax)
131*41966Smckusick 	Fix Me!!
132*41966Smckusick #endif
133*41966Smckusick #if defined(tahoe)
134*41966Smckusick 	Fix Me!!
135*41966Smckusick #endif
136*41966Smckusick #if defined(hp300)
137*41966Smckusick 	/*
138*41966Smckusick 	 * selfpc = pc pushed by mcount jsr,
139*41966Smckusick 	 * frompcindex = pc pushed by jsr into self.
140*41966Smckusick 	 * In GCC the caller's stack frame has already been built so we
141*41966Smckusick 	 * have to chase a6 to find caller's raddr.  This assumes that all
142*41966Smckusick 	 * routines we are profiling were built with GCC and that all
143*41966Smckusick 	 * profiled routines use link/unlk.
144*41966Smckusick 	 */
145*41966Smckusick 	asm("movl a6@(4),%0" : "=r" (selfpc));
146*41966Smckusick 	asm("movl a6@(0)@(4),%0" : "=r" (frompcindex));
147*41966Smckusick #endif
148*41966Smckusick #else
149*41966Smckusick #if defined(vax)
1507332Ssam 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
1517332Ssam 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
15229946Skarels #endif
15329946Skarels #if defined(tahoe)
15429946Skarels 	asm("	movl -8(fp),r12");	/* selfpc = callf frame */
15529946Skarels 	asm("	movl (fp),r11");
15629946Skarels 	asm("	movl -8(r11),r11");	/* frompcindex = 1 callf frame back */
15729946Skarels #endif
158*41966Smckusick #if defined(hp300)
159*41966Smckusick 	asm("	.text");		/* make sure we're in text space */
160*41966Smckusick 	asm("	movl a6@(4),a5");	/* selfpc = pc pushed by mcount jsr */
161*41966Smckusick 	asm("	movl a6@(8),a4");	/* frompcindex = pc pushed by jsr into
162*41966Smckusick 					   self, stack frame not yet built */
16329946Skarels #endif
164*41966Smckusick #endif /* not __GNUC__ */
165*41966Smckusick #endif /* not lint */
1667332Ssam 	/*
16729946Skarels 	 * Insure that we cannot be recursively invoked.
16829946Skarels 	 * this requires that splhigh() and splx() below
16929946Skarels 	 * do NOT call mcount!
1707332Ssam 	 */
17116924Smckusick 	s = splhigh();
17216924Smckusick 	/*
17329946Skarels 	 * Check that frompcindex is a reasonable pc value.
17429946Skarels 	 * For example:	signal catchers get called from the stack,
17529946Skarels 	 *	not from text space.  too bad.
1767332Ssam 	 */
17729946Skarels 	frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc);
17829946Skarels 	if ((u_long)frompcindex > s_textsize)
1797332Ssam 		goto done;
18010292Smckusick 	frompcindex =
18129946Skarels 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))];
18210292Smckusick 	toindex = *frompcindex;
18310292Smckusick 	if (toindex == 0) {
18410292Smckusick 		/*
18529946Skarels 		 * First time traversing this arc
18610292Smckusick 		 */
18710292Smckusick 		toindex = ++tos[0].link;
18829946Skarels 		if (toindex >= tolimit)
1897332Ssam 			goto overflow;
19010292Smckusick 		*frompcindex = toindex;
19110292Smckusick 		top = &tos[toindex];
1927332Ssam 		top->selfpc = selfpc;
19310292Smckusick 		top->count = 1;
1947332Ssam 		top->link = 0;
19510292Smckusick 		goto done;
1967332Ssam 	}
19710292Smckusick 	top = &tos[toindex];
19810292Smckusick 	if (top->selfpc == selfpc) {
19910292Smckusick 		/*
20029946Skarels 		 * Arc at front of chain; usual case.
20110292Smckusick 		 */
20210292Smckusick 		top->count++;
20310292Smckusick 		goto done;
20410292Smckusick 	}
20510292Smckusick 	/*
20629946Skarels 	 * Have to go looking down chain for it.
20729946Skarels 	 * Top points to what we are looking at,
20829946Skarels 	 * prevtop points to previous top.
20929946Skarels 	 * We know it is not at the head of the chain.
21010292Smckusick 	 */
21110292Smckusick 	for (; /* goto done */; ) {
21210292Smckusick 		if (top->link == 0) {
21310292Smckusick 			/*
21429946Skarels 			 * Top is end of the chain and none of the chain
21529946Skarels 			 * had top->selfpc == selfpc.
21629946Skarels 			 * So we allocate a new tostruct
21729946Skarels 			 * and link it to the head of the chain.
21810292Smckusick 			 */
21910292Smckusick 			toindex = ++tos[0].link;
22029946Skarels 			if (toindex >= tolimit)
22110292Smckusick 				goto overflow;
22210292Smckusick 			top = &tos[toindex];
22310292Smckusick 			top->selfpc = selfpc;
22410292Smckusick 			top->count = 1;
22510292Smckusick 			top->link = *frompcindex;
22610292Smckusick 			*frompcindex = toindex;
22710292Smckusick 			goto done;
22810292Smckusick 		}
22910292Smckusick 		/*
23029946Skarels 		 * Otherwise, check the next arc on the chain.
23110292Smckusick 		 */
23210292Smckusick 		prevtop = top;
23310292Smckusick 		top = &tos[top->link];
2347332Ssam 		if (top->selfpc == selfpc) {
23510292Smckusick 			/*
23629946Skarels 			 * There it is, increment its count and
23729946Skarels 			 * move it to the head of the chain.
23810292Smckusick 			 */
2397332Ssam 			top->count++;
24010292Smckusick 			toindex = prevtop->link;
24110292Smckusick 			prevtop->link = top->link;
24210292Smckusick 			top->link = *frompcindex;
24310292Smckusick 			*frompcindex = toindex;
24410292Smckusick 			goto done;
2457332Ssam 		}
24610292Smckusick 
2477332Ssam 	}
2487332Ssam done:
24916924Smckusick 	splx(s);
2507332Ssam 	/* and fall through */
2517332Ssam out:
25229946Skarels #if defined(vax)
2537332Ssam 	asm("	rsb");
25429946Skarels #endif
25529946Skarels 	return;
2567332Ssam overflow:
25710292Smckusick 	profiling = 3;
2587332Ssam 	printf("mcount: tos overflow\n");
2597332Ssam 	goto out;
2607332Ssam }
26110292Smckusick asm(".text");
26210292Smckusick asm("#the end of mcount()");
26310292Smckusick asm(".data");
26429946Skarels #endif
265