mcount.c revision 116189
113116Sbde/*-
213116Sbde * Copyright (c) 1983, 1992, 1993
313116Sbde *	The Regents of the University of California.  All rights reserved.
413116Sbde *
513116Sbde * Redistribution and use in source and binary forms, with or without
613116Sbde * modification, are permitted provided that the following conditions
713116Sbde * are met:
813116Sbde * 1. Redistributions of source code must retain the above copyright
913116Sbde *    notice, this list of conditions and the following disclaimer.
1013116Sbde * 2. Redistributions in binary form must reproduce the above copyright
1113116Sbde *    notice, this list of conditions and the following disclaimer in the
1213116Sbde *    documentation and/or other materials provided with the distribution.
1313116Sbde * 3. All advertising materials mentioning features or use of this software
1413116Sbde *    must display the following acknowledgement:
1513116Sbde *	This product includes software developed by the University of
1613116Sbde *	California, Berkeley and its contributors.
1713116Sbde * 4. Neither the name of the University nor the names of its contributors
1813116Sbde *    may be used to endorse or promote products derived from this software
1913116Sbde *    without specific prior written permission.
2013116Sbde *
2113116Sbde * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2213116Sbde * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2313116Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2413116Sbde * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2513116Sbde * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2613116Sbde * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2713116Sbde * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2813116Sbde * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2913116Sbde * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3013116Sbde * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3113116Sbde * SUCH DAMAGE.
3213116Sbde */
331541Srgrimes
34116189Sobrien#include <sys/cdefs.h>
35116189Sobrien__FBSDID("$FreeBSD: head/sys/libkern/mcount.c 116189 2003-06-11 05:37:42Z obrien $");
36116189Sobrien
3713116Sbde#include <sys/param.h>
3813116Sbde#include <sys/gmon.h>
3955206Speter#ifdef _KERNEL
4019169Sbde#ifndef GUPROF
4119169Sbde#include <sys/systm.h>
4219169Sbde#endif
4313116Sbde#include <vm/vm.h>
4413116Sbde#include <vm/vm_param.h>
4513116Sbde#include <vm/pmap.h>
4692741Salfredvoid	bintr(void);
4792741Salfredvoid	btrap(void);
4892741Salfredvoid	eintr(void);
4992741Salfredvoid	user(void);
5013116Sbde#endif
5113116Sbde
5213116Sbde/*
5313116Sbde * mcount is called on entry to each function compiled with the profiling
5413116Sbde * switch set.  _mcount(), which is declared in a machine-dependent way
5513116Sbde * with _MCOUNT_DECL, does the actual work and is either inlined into a
5613116Sbde * C routine or called by an assembly stub.  In any case, this magic is
5713116Sbde * taken care of by the MCOUNT definition in <machine/profile.h>.
5813116Sbde *
5913116Sbde * _mcount updates data structures that represent traversals of the
6013116Sbde * program's call graph edges.  frompc and selfpc are the return
6113116Sbde * address and function address that represents the given call graph edge.
6213116Sbde *
6313116Sbde * Note: the original BSD code used the same variable (frompcindex) for
6413116Sbde * both frompcindex and frompc.  Any reasonable, modern compiler will
6513116Sbde * perform this optimization.
6613116Sbde */
6713116Sbde_MCOUNT_DECL(frompc, selfpc)	/* _mcount; may be static, inline, etc */
6837629Sbde	register uintfptr_t frompc, selfpc;
6913116Sbde{
7013116Sbde#ifdef GUPROF
7119000Sbde	int delta;
7213116Sbde#endif
7313116Sbde	register fptrdiff_t frompci;
7413116Sbde	register u_short *frompcindex;
7513116Sbde	register struct tostruct *top, *prevtop;
7613116Sbde	register struct gmonparam *p;
7713116Sbde	register long toindex;
7855206Speter#ifdef _KERNEL
7917879Sbde	MCOUNT_DECL(s)
8013116Sbde#endif
8113116Sbde
8213116Sbde	p = &_gmonparam;
8313116Sbde#ifndef GUPROF			/* XXX */
8413116Sbde	/*
8513116Sbde	 * check that we are profiling
8613116Sbde	 * and that we aren't recursively invoked.
8713116Sbde	 */
8813116Sbde	if (p->state != GMON_PROF_ON)
8913116Sbde		return;
9013116Sbde#endif
9155206Speter#ifdef _KERNEL
9217879Sbde	MCOUNT_ENTER(s);
9313116Sbde#else
9413116Sbde	p->state = GMON_PROF_BUSY;
9513116Sbde#endif
9613116Sbde	frompci = frompc - p->lowpc;
9713116Sbde
9855206Speter#ifdef _KERNEL
9913116Sbde	/*
10013116Sbde	 * When we are called from an exception handler, frompci may be
10113116Sbde	 * for a user address.  Convert such frompci's to the index of
10213116Sbde	 * user() to merge all user counts.
10313116Sbde	 */
10413116Sbde	if (frompci >= p->textsize) {
10513116Sbde		if (frompci + p->lowpc
10681264Speter		    >= (uintfptr_t)(VM_MAXUSER_ADDRESS))
10713116Sbde			goto done;
10837629Sbde		frompci = (uintfptr_t)user - p->lowpc;
10913116Sbde		if (frompci >= p->textsize)
11013116Sbde		    goto done;
11113116Sbde	}
11255206Speter#endif
11313116Sbde
11413116Sbde#ifdef GUPROF
11519000Sbde	if (p->state == GMON_PROF_HIRES) {
11619000Sbde		/*
11719000Sbde		 * Count the time since cputime() was previously called
11819000Sbde		 * against `frompc'.  Compensate for overheads.
11919000Sbde		 *
12019000Sbde		 * cputime() sets its prev_count variable to the count when
12119000Sbde		 * it is called.  This in effect starts a counter for
12219000Sbde		 * the next period of execution (normally from now until
12319000Sbde		 * the next call to mcount() or mexitcount()).  We set
12419000Sbde		 * cputime_bias to compensate for our own overhead.
12519000Sbde		 *
12619000Sbde		 * We use the usual sampling counters since they can be
12719000Sbde		 * located efficiently.  4-byte counters are usually
12819000Sbde		 * necessary.  gprof will add up the scattered counts
12919000Sbde		 * just like it does for statistical profiling.  All
13019000Sbde		 * counts are signed so that underflow in the subtractions
13119000Sbde		 * doesn't matter much (negative counts are normally
13219000Sbde		 * compensated for by larger counts elsewhere).  Underflow
13319000Sbde		 * shouldn't occur, but may be caused by slightly wrong
13419000Sbde		 * calibrations or from not clearing cputime_bias.
13519000Sbde		 */
13619000Sbde		delta = cputime() - cputime_bias - p->mcount_pre_overhead;
13719000Sbde		cputime_bias = p->mcount_post_overhead;
13819000Sbde		KCOUNT(p, frompci) += delta;
13919000Sbde		*p->cputime_count += p->cputime_overhead;
14019000Sbde		*p->mcount_count += p->mcount_overhead;
14113116Sbde	}
14213116Sbde#endif /* GUPROF */
14313116Sbde
14455206Speter#ifdef _KERNEL
14513116Sbde	/*
14613116Sbde	 * When we are called from an exception handler, frompc is faked
14713116Sbde	 * to be for where the exception occurred.  We've just solidified
14813116Sbde	 * the count for there.  Now convert frompci to the index of btrap()
14913116Sbde	 * for trap handlers and bintr() for interrupt handlers to make
15013116Sbde	 * exceptions appear in the call graph as calls from btrap() and
15113116Sbde	 * bintr() instead of calls from all over.
15213116Sbde	 */
15337629Sbde	if ((uintfptr_t)selfpc >= (uintfptr_t)btrap
15437629Sbde	    && (uintfptr_t)selfpc < (uintfptr_t)eintr) {
15537629Sbde		if ((uintfptr_t)selfpc >= (uintfptr_t)bintr)
15637629Sbde			frompci = (uintfptr_t)bintr - p->lowpc;
15713116Sbde		else
15837629Sbde			frompci = (uintfptr_t)btrap - p->lowpc;
15913116Sbde	}
16055206Speter#endif
16113116Sbde
16213116Sbde	/*
16313116Sbde	 * check that frompc is a reasonable pc value.
16413116Sbde	 * for example:	signal catchers get called from the stack,
16513116Sbde	 *		not from text space.  too bad.
16613116Sbde	 */
16713116Sbde	if (frompci >= p->textsize)
16813116Sbde		goto done;
16913116Sbde
17013116Sbde	frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))];
17113116Sbde	toindex = *frompcindex;
17213116Sbde	if (toindex == 0) {
17313116Sbde		/*
17413116Sbde		 *	first time traversing this arc
17513116Sbde		 */
17613116Sbde		toindex = ++p->tos[0].link;
17713116Sbde		if (toindex >= p->tolimit)
17813116Sbde			/* halt further profiling */
17913116Sbde			goto overflow;
18013116Sbde
18113116Sbde		*frompcindex = toindex;
18213116Sbde		top = &p->tos[toindex];
18313116Sbde		top->selfpc = selfpc;
18413116Sbde		top->count = 1;
18513116Sbde		top->link = 0;
18613116Sbde		goto done;
18713116Sbde	}
18813116Sbde	top = &p->tos[toindex];
18913116Sbde	if (top->selfpc == selfpc) {
19013116Sbde		/*
19113116Sbde		 * arc at front of chain; usual case.
19213116Sbde		 */
19313116Sbde		top->count++;
19413116Sbde		goto done;
19513116Sbde	}
19613116Sbde	/*
19713116Sbde	 * have to go looking down chain for it.
19813116Sbde	 * top points to what we are looking at,
19913116Sbde	 * prevtop points to previous top.
20013116Sbde	 * we know it is not at the head of the chain.
20113116Sbde	 */
20213116Sbde	for (; /* goto done */; ) {
20313116Sbde		if (top->link == 0) {
20413116Sbde			/*
20513116Sbde			 * top is end of the chain and none of the chain
20613116Sbde			 * had top->selfpc == selfpc.
20713116Sbde			 * so we allocate a new tostruct
20813116Sbde			 * and link it to the head of the chain.
20913116Sbde			 */
21013116Sbde			toindex = ++p->tos[0].link;
21113116Sbde			if (toindex >= p->tolimit)
21213116Sbde				goto overflow;
21313116Sbde
21413116Sbde			top = &p->tos[toindex];
21513116Sbde			top->selfpc = selfpc;
21613116Sbde			top->count = 1;
21713116Sbde			top->link = *frompcindex;
21813116Sbde			*frompcindex = toindex;
21913116Sbde			goto done;
22013116Sbde		}
22113116Sbde		/*
22213116Sbde		 * otherwise, check the next arc on the chain.
22313116Sbde		 */
22413116Sbde		prevtop = top;
22513116Sbde		top = &p->tos[top->link];
22613116Sbde		if (top->selfpc == selfpc) {
22713116Sbde			/*
22813116Sbde			 * there it is.
22913116Sbde			 * increment its count
23013116Sbde			 * move it to the head of the chain.
23113116Sbde			 */
23213116Sbde			top->count++;
23313116Sbde			toindex = prevtop->link;
23413116Sbde			prevtop->link = top->link;
23513116Sbde			top->link = *frompcindex;
23613116Sbde			*frompcindex = toindex;
23713116Sbde			goto done;
23813116Sbde		}
23913116Sbde
24013116Sbde	}
24113116Sbdedone:
24255206Speter#ifdef _KERNEL
24317879Sbde	MCOUNT_EXIT(s);
24413116Sbde#else
24513116Sbde	p->state = GMON_PROF_ON;
24613116Sbde#endif
24713116Sbde	return;
24813116Sbdeoverflow:
24913116Sbde	p->state = GMON_PROF_ERROR;
25055206Speter#ifdef _KERNEL
25117879Sbde	MCOUNT_EXIT(s);
25213116Sbde#endif
25313116Sbde	return;
25413116Sbde}
25513116Sbde
25613116Sbde/*
25713116Sbde * Actual definition of mcount function.  Defined in <machine/profile.h>,
25813116Sbde * which is included by <sys/gmon.h>.
25913116Sbde */
26013116SbdeMCOUNT
26113116Sbde
26213116Sbde#ifdef GUPROF
26313116Sbdevoid
26413116Sbdemexitcount(selfpc)
26537629Sbde	uintfptr_t selfpc;
26613116Sbde{
26713116Sbde	struct gmonparam *p;
26837629Sbde	uintfptr_t selfpcdiff;
26913116Sbde
27013116Sbde	p = &_gmonparam;
27137629Sbde	selfpcdiff = selfpc - (uintfptr_t)p->lowpc;
27213116Sbde	if (selfpcdiff < p->textsize) {
27319000Sbde		int delta;
27413116Sbde
27513116Sbde		/*
27619000Sbde		 * Count the time since cputime() was previously called
27719000Sbde		 * against `selfpc'.  Compensate for overheads.
27813116Sbde		 */
27919000Sbde		delta = cputime() - cputime_bias - p->mexitcount_pre_overhead;
28019000Sbde		cputime_bias = p->mexitcount_post_overhead;
28119000Sbde		KCOUNT(p, selfpcdiff) += delta;
28213116Sbde		*p->cputime_count += p->cputime_overhead;
28319000Sbde		*p->mexitcount_count += p->mexitcount_overhead;
28413116Sbde	}
28513116Sbde}
28619000Sbde
28719000Sbdevoid
28819000Sbdeempty_loop()
28919000Sbde{
29019000Sbde	int i;
29119000Sbde
29219000Sbde	for (i = 0; i < CALIB_SCALE; i++)
29319000Sbde		;
29419000Sbde}
29519000Sbde
29619000Sbdevoid
29719000Sbdenullfunc()
29819000Sbde{
29919000Sbde}
30019000Sbde
30119000Sbdevoid
30219000Sbdenullfunc_loop()
30319000Sbde{
30419000Sbde	int i;
30519000Sbde
30619000Sbde	for (i = 0; i < CALIB_SCALE; i++)
30719000Sbde		nullfunc();
30819000Sbde}
30913116Sbde#endif /* GUPROF */
310