xref: /csrg-svn/sys/kern/subr_prof.c (revision 54137)
123380Smckusick /*
229100Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
341966Smckusick  * All rights reserved.
423380Smckusick  *
541966Smckusick  * %sccs.include.redist.c%
641966Smckusick  *
7*54137Smckusick  *	@(#)subr_prof.c	7.14 (Berkeley) 06/20/92
823380Smckusick  */
97332Ssam 
107332Ssam #ifdef GPROF
1117094Sbloom #include "gprof.h"
1217094Sbloom #include "param.h"
1317094Sbloom #include "systm.h"
1453015Smckusick #include "kernel.h"
1531433Smckusick #include "malloc.h"
167332Ssam 
177332Ssam /*
187332Ssam  * Froms is actually a bunch of unsigned shorts indexing tos
197332Ssam  */
2029946Skarels int	profiling = 3;
2129946Skarels u_short	*froms;
2229946Skarels struct	tostruct *tos = 0;
2329946Skarels long	tolimit = 0;
2444774Swilliam char	*s_lowpc = (char *)KERNBASE;
2529946Skarels extern	char etext;
2629946Skarels char	*s_highpc = &etext;
277332Ssam u_long	s_textsize = 0;
2829946Skarels int	ssiz;
297332Ssam u_short	*sbuf;
307332Ssam u_short	*kcount;
317332Ssam 
327332Ssam kmstartup()
337332Ssam {
3429946Skarels 	u_long fromssize, tossize;
357332Ssam 
3610292Smckusick 	/*
3729946Skarels 	 * Round lowpc and highpc to multiples of the density we're using
3829946Skarels 	 * so the rest of the scaling (here and in gprof) stays in ints.
3910292Smckusick 	 */
4010292Smckusick 	s_lowpc = (char *)
4129946Skarels 	    ROUNDDOWN((unsigned)s_lowpc, HISTFRACTION*sizeof (HISTCOUNTER));
4210292Smckusick 	s_highpc = (char *)
4329946Skarels 	    ROUNDUP((unsigned)s_highpc, HISTFRACTION*sizeof (HISTCOUNTER));
447332Ssam 	s_textsize = s_highpc - s_lowpc;
457332Ssam 	printf("Profiling kernel, s_textsize=%d [%x..%x]\n",
467332Ssam 		s_textsize, s_lowpc, s_highpc);
4729946Skarels 	ssiz = (s_textsize / HISTFRACTION) + sizeof (struct phdr);
4831433Smckusick 	sbuf = (u_short *)malloc(ssiz, M_GPROF, M_WAITOK);
497332Ssam 	if (sbuf == 0) {
507332Ssam 		printf("No space for monitor buffer(s)\n");
517332Ssam 		return;
527332Ssam 	}
5331922Smckusick 	bzero(sbuf, ssiz);
5410292Smckusick 	fromssize = s_textsize / HASHFRACTION;
5549283Shibler 	froms = (u_short *)malloc(fromssize, M_GPROF, M_NOWAIT);
567332Ssam 	if (froms == 0) {
577332Ssam 		printf("No space for monitor buffer(s)\n");
5831433Smckusick 		free(sbuf, M_GPROF);
597332Ssam 		sbuf = 0;
607332Ssam 		return;
617332Ssam 	}
6237535Smckusick 	bzero(froms, fromssize);
6310292Smckusick 	tolimit = s_textsize * ARCDENSITY / 100;
6429946Skarels 	if (tolimit < MINARCS)
6510292Smckusick 		tolimit = MINARCS;
6629946Skarels 	else if (tolimit > (0xffff - 1))
6729946Skarels 		tolimit = 0xffff - 1;
6829946Skarels 	tossize = tolimit * sizeof (struct tostruct);
6931433Smckusick 	tos = (struct tostruct *)malloc(tossize, M_GPROF, M_WAITOK);
707332Ssam 	if (tos == 0) {
717332Ssam 		printf("No space for monitor buffer(s)\n");
7231433Smckusick 		free(sbuf, M_GPROF), sbuf = 0;
7331433Smckusick 		free(froms, M_GPROF), froms = 0;
747332Ssam 		return;
757332Ssam 	}
7631922Smckusick 	bzero(tos, tossize);
777332Ssam 	tos[0].link = 0;
787332Ssam 	((struct phdr *)sbuf)->lpc = s_lowpc;
797332Ssam 	((struct phdr *)sbuf)->hpc = s_highpc;
807332Ssam 	((struct phdr *)sbuf)->ncnt = ssiz;
8153015Smckusick 	((struct phdr *)sbuf)->version = GMONVERSION;
82*54137Smckusick 	startprofclock(&proc0);
8353015Smckusick 	((struct phdr *)sbuf)->profrate = profhz;
8429946Skarels 	kcount = (u_short *)(((int)sbuf) + sizeof (struct phdr));
857332Ssam }
867332Ssam 
877332Ssam /*
8829946Skarels  * This routine is massaged so that it may be jsb'ed to on vax.
897332Ssam  */
907332Ssam mcount()
917332Ssam {
9229946Skarels 	register char *selfpc;			/* r11 => r5 */
9329946Skarels 	register u_short *frompcindex;		/* r10 => r4 */
9429946Skarels 	register struct tostruct *top;		/* r9  => r3 */
9529946Skarels 	register struct tostruct *prevtop;	/* r8  => r2 */
9629946Skarels 	register long toindex;			/* r7  => r1 */
9716924Smckusick 	static int s;
987332Ssam 
9929946Skarels 	/*
10029946Skarels 	 * Check that we are profiling.
10129946Skarels 	 */
10229946Skarels 	if (profiling)
10329946Skarels 		goto out;
10429946Skarels 	/*
10529946Skarels 	 * Find the return address for mcount,
10629946Skarels 	 * and the return address for mcount's caller.
10729946Skarels 	 */
1087332Ssam #ifdef lint
10910292Smckusick 	selfpc = (char *)0;
1107332Ssam 	frompcindex = 0;
11129946Skarels #else
11233366Smckusick 	;				/* avoid label botch */
11341966Smckusick #ifdef __GNUC__
11429946Skarels #if defined(vax)
11541966Smckusick 	Fix Me!!
11641966Smckusick #endif
11741966Smckusick #if defined(tahoe)
11841966Smckusick 	Fix Me!!
11941966Smckusick #endif
12053872Smckusick #if defined(hp300) || defined(luna68k)
12141966Smckusick 	/*
12241966Smckusick 	 * selfpc = pc pushed by mcount jsr,
12341966Smckusick 	 * frompcindex = pc pushed by jsr into self.
12441966Smckusick 	 * In GCC the caller's stack frame has already been built so we
12541966Smckusick 	 * have to chase a6 to find caller's raddr.  This assumes that all
12641966Smckusick 	 * routines we are profiling were built with GCC and that all
12741966Smckusick 	 * profiled routines use link/unlk.
12841966Smckusick 	 */
12941966Smckusick 	asm("movl a6@(4),%0" : "=r" (selfpc));
13041966Smckusick 	asm("movl a6@(0)@(4),%0" : "=r" (frompcindex));
13141966Smckusick #endif
13241966Smckusick #else
13341966Smckusick #if defined(vax)
1347332Ssam 	asm("	movl (sp), r11");	/* selfpc = ... (jsb frame) */
1357332Ssam 	asm("	movl 16(fp), r10");	/* frompcindex =     (calls frame) */
13629946Skarels #endif
13729946Skarels #if defined(tahoe)
13829946Skarels 	asm("	movl -8(fp),r12");	/* selfpc = callf frame */
13929946Skarels 	asm("	movl (fp),r11");
14029946Skarels 	asm("	movl -8(r11),r11");	/* frompcindex = 1 callf frame back */
14129946Skarels #endif
14253872Smckusick #if defined(hp300) || defined(luna68k)
14349283Shibler 	Fix Me!!
14429946Skarels #endif
14541966Smckusick #endif /* not __GNUC__ */
14641966Smckusick #endif /* not lint */
1477332Ssam 	/*
14829946Skarels 	 * Insure that we cannot be recursively invoked.
14929946Skarels 	 * this requires that splhigh() and splx() below
15029946Skarels 	 * do NOT call mcount!
1517332Ssam 	 */
15253872Smckusick #if defined(hp300) || defined(luna68k)
15342348Smckusick 	asm("movw	sr,%0" : "=g" (s));
15442348Smckusick 	asm("movw	#0x2700,sr");
15542348Smckusick #else
15616924Smckusick 	s = splhigh();
15742348Smckusick #endif
15816924Smckusick 	/*
15929946Skarels 	 * Check that frompcindex is a reasonable pc value.
16029946Skarels 	 * For example:	signal catchers get called from the stack,
16129946Skarels 	 *	not from text space.  too bad.
1627332Ssam 	 */
16329946Skarels 	frompcindex = (u_short *)((long)frompcindex - (long)s_lowpc);
16429946Skarels 	if ((u_long)frompcindex > s_textsize)
1657332Ssam 		goto done;
16610292Smckusick 	frompcindex =
16729946Skarels 	    &froms[((long)frompcindex) / (HASHFRACTION * sizeof (*froms))];
16810292Smckusick 	toindex = *frompcindex;
16910292Smckusick 	if (toindex == 0) {
17010292Smckusick 		/*
17129946Skarels 		 * First time traversing this arc
17210292Smckusick 		 */
17310292Smckusick 		toindex = ++tos[0].link;
17429946Skarels 		if (toindex >= tolimit)
1757332Ssam 			goto overflow;
17610292Smckusick 		*frompcindex = toindex;
17710292Smckusick 		top = &tos[toindex];
1787332Ssam 		top->selfpc = selfpc;
17910292Smckusick 		top->count = 1;
1807332Ssam 		top->link = 0;
18110292Smckusick 		goto done;
1827332Ssam 	}
18310292Smckusick 	top = &tos[toindex];
18410292Smckusick 	if (top->selfpc == selfpc) {
18510292Smckusick 		/*
18629946Skarels 		 * Arc at front of chain; usual case.
18710292Smckusick 		 */
18810292Smckusick 		top->count++;
18910292Smckusick 		goto done;
19010292Smckusick 	}
19110292Smckusick 	/*
19229946Skarels 	 * Have to go looking down chain for it.
19329946Skarels 	 * Top points to what we are looking at,
19429946Skarels 	 * prevtop points to previous top.
19529946Skarels 	 * We know it is not at the head of the chain.
19610292Smckusick 	 */
19710292Smckusick 	for (; /* goto done */; ) {
19810292Smckusick 		if (top->link == 0) {
19910292Smckusick 			/*
20029946Skarels 			 * Top is end of the chain and none of the chain
20129946Skarels 			 * had top->selfpc == selfpc.
20229946Skarels 			 * So we allocate a new tostruct
20329946Skarels 			 * and link it to the head of the chain.
20410292Smckusick 			 */
20510292Smckusick 			toindex = ++tos[0].link;
20629946Skarels 			if (toindex >= tolimit)
20710292Smckusick 				goto overflow;
20810292Smckusick 			top = &tos[toindex];
20910292Smckusick 			top->selfpc = selfpc;
21010292Smckusick 			top->count = 1;
21110292Smckusick 			top->link = *frompcindex;
21210292Smckusick 			*frompcindex = toindex;
21310292Smckusick 			goto done;
21410292Smckusick 		}
21510292Smckusick 		/*
21629946Skarels 		 * Otherwise, check the next arc on the chain.
21710292Smckusick 		 */
21810292Smckusick 		prevtop = top;
21910292Smckusick 		top = &tos[top->link];
2207332Ssam 		if (top->selfpc == selfpc) {
22110292Smckusick 			/*
22229946Skarels 			 * There it is, increment its count and
22329946Skarels 			 * move it to the head of the chain.
22410292Smckusick 			 */
2257332Ssam 			top->count++;
22610292Smckusick 			toindex = prevtop->link;
22710292Smckusick 			prevtop->link = top->link;
22810292Smckusick 			top->link = *frompcindex;
22910292Smckusick 			*frompcindex = toindex;
23010292Smckusick 			goto done;
2317332Ssam 		}
23210292Smckusick 
2337332Ssam 	}
2347332Ssam done:
23553872Smckusick #if defined(hp300) || defined(luna68k)
23642348Smckusick 	asm("movw	%0,sr" : : "g" (s));
23742348Smckusick #else
23816924Smckusick 	splx(s);
23942348Smckusick #endif
2407332Ssam 	/* and fall through */
2417332Ssam out:
24229946Skarels #if defined(vax)
2437332Ssam 	asm("	rsb");
24429946Skarels #endif
24529946Skarels 	return;
2467332Ssam overflow:
24710292Smckusick 	profiling = 3;
2487332Ssam 	printf("mcount: tos overflow\n");
2497332Ssam 	goto out;
2507332Ssam }
25110292Smckusick asm(".text");
25210292Smckusick asm("#the end of mcount()");
25310292Smckusick asm(".data");
25429946Skarels #endif
255