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 * 4. Neither the name of the University nor the names of its contributors
1413116Sbde *    may be used to endorse or promote products derived from this software
1513116Sbde *    without specific prior written permission.
1613116Sbde *
1713116Sbde * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1813116Sbde * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1913116Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2013116Sbde * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2113116Sbde * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2213116Sbde * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2313116Sbde * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2413116Sbde * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2513116Sbde * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2613116Sbde * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2713116Sbde * SUCH DAMAGE.
2813116Sbde */
291541Srgrimes
30116189Sobrien#include <sys/cdefs.h>
31116189Sobrien__FBSDID("$FreeBSD$");
32116189Sobrien
3313116Sbde#include <sys/param.h>
3413116Sbde#include <sys/gmon.h>
3555206Speter#ifdef _KERNEL
3619169Sbde#ifndef GUPROF
3719169Sbde#include <sys/systm.h>
3819169Sbde#endif
3913116Sbde#include <vm/vm.h>
4013116Sbde#include <vm/vm_param.h>
4113116Sbde#include <vm/pmap.h>
4213116Sbde#endif
4313116Sbde
4413116Sbde/*
4513116Sbde * mcount is called on entry to each function compiled with the profiling
4613116Sbde * switch set.  _mcount(), which is declared in a machine-dependent way
4713116Sbde * with _MCOUNT_DECL, does the actual work and is either inlined into a
4813116Sbde * C routine or called by an assembly stub.  In any case, this magic is
4913116Sbde * taken care of by the MCOUNT definition in <machine/profile.h>.
5013116Sbde *
5113116Sbde * _mcount updates data structures that represent traversals of the
5213116Sbde * program's call graph edges.  frompc and selfpc are the return
5313116Sbde * address and function address that represents the given call graph edge.
5413116Sbde *
5513116Sbde * Note: the original BSD code used the same variable (frompcindex) for
5613116Sbde * both frompcindex and frompc.  Any reasonable, modern compiler will
5713116Sbde * perform this optimization.
5813116Sbde */
5913116Sbde_MCOUNT_DECL(frompc, selfpc)	/* _mcount; may be static, inline, etc */
60134398Smarcel	uintfptr_t frompc, selfpc;
6113116Sbde{
6213116Sbde#ifdef GUPROF
6319000Sbde	int delta;
6413116Sbde#endif
65134398Smarcel	fptrdiff_t frompci;
66134398Smarcel	u_short *frompcindex;
67134398Smarcel	struct tostruct *top, *prevtop;
68134398Smarcel	struct gmonparam *p;
69134398Smarcel	long toindex;
7055206Speter#ifdef _KERNEL
7117879Sbde	MCOUNT_DECL(s)
7213116Sbde#endif
7313116Sbde
7413116Sbde	p = &_gmonparam;
7513116Sbde#ifndef GUPROF			/* XXX */
7613116Sbde	/*
7713116Sbde	 * check that we are profiling
7813116Sbde	 * and that we aren't recursively invoked.
7913116Sbde	 */
8013116Sbde	if (p->state != GMON_PROF_ON)
8113116Sbde		return;
8213116Sbde#endif
8355206Speter#ifdef _KERNEL
8417879Sbde	MCOUNT_ENTER(s);
8513116Sbde#else
8613116Sbde	p->state = GMON_PROF_BUSY;
8713116Sbde#endif
8813116Sbde
8955206Speter#ifdef _KERNEL
9013116Sbde	/*
91134398Smarcel	 * When we are called from an exception handler, frompc may be
92134398Smarcel	 * a user address.  Convert such frompc's to some representation
93134398Smarcel	 * in kernel address space.
9413116Sbde	 */
95134398Smarcel	frompc = MCOUNT_FROMPC_USER(frompc);
9655206Speter#endif
9713116Sbde
98134398Smarcel	frompci = frompc - p->lowpc;
99134398Smarcel	if (frompci >= p->textsize)
100134398Smarcel		goto done;
101134398Smarcel
10213116Sbde#ifdef GUPROF
10319000Sbde	if (p->state == GMON_PROF_HIRES) {
10419000Sbde		/*
10519000Sbde		 * Count the time since cputime() was previously called
10619000Sbde		 * against `frompc'.  Compensate for overheads.
10719000Sbde		 *
10819000Sbde		 * cputime() sets its prev_count variable to the count when
10919000Sbde		 * it is called.  This in effect starts a counter for
11019000Sbde		 * the next period of execution (normally from now until
11119000Sbde		 * the next call to mcount() or mexitcount()).  We set
11219000Sbde		 * cputime_bias to compensate for our own overhead.
11319000Sbde		 *
11419000Sbde		 * We use the usual sampling counters since they can be
11519000Sbde		 * located efficiently.  4-byte counters are usually
11619000Sbde		 * necessary.  gprof will add up the scattered counts
11719000Sbde		 * just like it does for statistical profiling.  All
11819000Sbde		 * counts are signed so that underflow in the subtractions
11919000Sbde		 * doesn't matter much (negative counts are normally
12019000Sbde		 * compensated for by larger counts elsewhere).  Underflow
12119000Sbde		 * shouldn't occur, but may be caused by slightly wrong
12219000Sbde		 * calibrations or from not clearing cputime_bias.
12319000Sbde		 */
12419000Sbde		delta = cputime() - cputime_bias - p->mcount_pre_overhead;
12519000Sbde		cputime_bias = p->mcount_post_overhead;
12619000Sbde		KCOUNT(p, frompci) += delta;
12719000Sbde		*p->cputime_count += p->cputime_overhead;
12819000Sbde		*p->mcount_count += p->mcount_overhead;
12913116Sbde	}
13013116Sbde#endif /* GUPROF */
13113116Sbde
13255206Speter#ifdef _KERNEL
13313116Sbde	/*
13413116Sbde	 * When we are called from an exception handler, frompc is faked
13513116Sbde	 * to be for where the exception occurred.  We've just solidified
136134398Smarcel	 * the count for there.  Now convert frompci to an index that
137134398Smarcel	 * represents the kind of exception so that interruptions appear
138134398Smarcel	 * in the call graph as calls from those index instead of calls
139134398Smarcel	 * from all over.
14013116Sbde	 */
141134398Smarcel	frompc = MCOUNT_FROMPC_INTR(selfpc);
142134398Smarcel	if ((frompc - p->lowpc) < p->textsize)
143134398Smarcel		frompci = frompc - p->lowpc;
14455206Speter#endif
14513116Sbde
14613116Sbde	/*
14713116Sbde	 * check that frompc is a reasonable pc value.
14813116Sbde	 * for example:	signal catchers get called from the stack,
14913116Sbde	 *		not from text space.  too bad.
15013116Sbde	 */
15113116Sbde	if (frompci >= p->textsize)
15213116Sbde		goto done;
15313116Sbde
15413116Sbde	frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))];
15513116Sbde	toindex = *frompcindex;
15613116Sbde	if (toindex == 0) {
15713116Sbde		/*
15813116Sbde		 *	first time traversing this arc
15913116Sbde		 */
16013116Sbde		toindex = ++p->tos[0].link;
16113116Sbde		if (toindex >= p->tolimit)
16213116Sbde			/* halt further profiling */
16313116Sbde			goto overflow;
16413116Sbde
16513116Sbde		*frompcindex = toindex;
16613116Sbde		top = &p->tos[toindex];
16713116Sbde		top->selfpc = selfpc;
16813116Sbde		top->count = 1;
16913116Sbde		top->link = 0;
17013116Sbde		goto done;
17113116Sbde	}
17213116Sbde	top = &p->tos[toindex];
17313116Sbde	if (top->selfpc == selfpc) {
17413116Sbde		/*
17513116Sbde		 * arc at front of chain; usual case.
17613116Sbde		 */
17713116Sbde		top->count++;
17813116Sbde		goto done;
17913116Sbde	}
18013116Sbde	/*
18113116Sbde	 * have to go looking down chain for it.
18213116Sbde	 * top points to what we are looking at,
18313116Sbde	 * prevtop points to previous top.
18413116Sbde	 * we know it is not at the head of the chain.
18513116Sbde	 */
18613116Sbde	for (; /* goto done */; ) {
18713116Sbde		if (top->link == 0) {
18813116Sbde			/*
18913116Sbde			 * top is end of the chain and none of the chain
19013116Sbde			 * had top->selfpc == selfpc.
19113116Sbde			 * so we allocate a new tostruct
19213116Sbde			 * and link it to the head of the chain.
19313116Sbde			 */
19413116Sbde			toindex = ++p->tos[0].link;
19513116Sbde			if (toindex >= p->tolimit)
19613116Sbde				goto overflow;
19713116Sbde
19813116Sbde			top = &p->tos[toindex];
19913116Sbde			top->selfpc = selfpc;
20013116Sbde			top->count = 1;
20113116Sbde			top->link = *frompcindex;
20213116Sbde			*frompcindex = toindex;
20313116Sbde			goto done;
20413116Sbde		}
20513116Sbde		/*
20613116Sbde		 * otherwise, check the next arc on the chain.
20713116Sbde		 */
20813116Sbde		prevtop = top;
20913116Sbde		top = &p->tos[top->link];
21013116Sbde		if (top->selfpc == selfpc) {
21113116Sbde			/*
21213116Sbde			 * there it is.
21313116Sbde			 * increment its count
21413116Sbde			 * move it to the head of the chain.
21513116Sbde			 */
21613116Sbde			top->count++;
21713116Sbde			toindex = prevtop->link;
21813116Sbde			prevtop->link = top->link;
21913116Sbde			top->link = *frompcindex;
22013116Sbde			*frompcindex = toindex;
22113116Sbde			goto done;
22213116Sbde		}
22313116Sbde
22413116Sbde	}
22513116Sbdedone:
22655206Speter#ifdef _KERNEL
22717879Sbde	MCOUNT_EXIT(s);
22813116Sbde#else
22913116Sbde	p->state = GMON_PROF_ON;
23013116Sbde#endif
23113116Sbde	return;
23213116Sbdeoverflow:
23313116Sbde	p->state = GMON_PROF_ERROR;
23455206Speter#ifdef _KERNEL
23517879Sbde	MCOUNT_EXIT(s);
23613116Sbde#endif
23713116Sbde	return;
23813116Sbde}
23913116Sbde
24013116Sbde/*
24113116Sbde * Actual definition of mcount function.  Defined in <machine/profile.h>,
24213116Sbde * which is included by <sys/gmon.h>.
24313116Sbde */
24413116SbdeMCOUNT
24513116Sbde
24613116Sbde#ifdef GUPROF
24713116Sbdevoid
24813116Sbdemexitcount(selfpc)
24937629Sbde	uintfptr_t selfpc;
25013116Sbde{
25113116Sbde	struct gmonparam *p;
25237629Sbde	uintfptr_t selfpcdiff;
25313116Sbde
25413116Sbde	p = &_gmonparam;
25537629Sbde	selfpcdiff = selfpc - (uintfptr_t)p->lowpc;
25613116Sbde	if (selfpcdiff < p->textsize) {
25719000Sbde		int delta;
25813116Sbde
25913116Sbde		/*
26019000Sbde		 * Count the time since cputime() was previously called
26119000Sbde		 * against `selfpc'.  Compensate for overheads.
26213116Sbde		 */
26319000Sbde		delta = cputime() - cputime_bias - p->mexitcount_pre_overhead;
26419000Sbde		cputime_bias = p->mexitcount_post_overhead;
26519000Sbde		KCOUNT(p, selfpcdiff) += delta;
26613116Sbde		*p->cputime_count += p->cputime_overhead;
26719000Sbde		*p->mexitcount_count += p->mexitcount_overhead;
26813116Sbde	}
26913116Sbde}
27019000Sbde
271170659Sbde#ifndef __GNUCLIKE_ASM
272170659Sbde#error "This file uses null asms to prevent timing loops being optimized away."
273170659Sbde#endif
274170659Sbde
27519000Sbdevoid
27619000Sbdeempty_loop()
27719000Sbde{
27819000Sbde	int i;
27919000Sbde
28019000Sbde	for (i = 0; i < CALIB_SCALE; i++)
281170659Sbde		__asm __volatile("");
28219000Sbde}
28319000Sbde
28419000Sbdevoid
28519000Sbdenullfunc()
28619000Sbde{
287170659Sbde	__asm __volatile("");
28819000Sbde}
28919000Sbde
29019000Sbdevoid
29119000Sbdenullfunc_loop()
29219000Sbde{
29319000Sbde	int i;
29419000Sbde
29519000Sbde	for (i = 0; i < CALIB_SCALE; i++)
29619000Sbde		nullfunc();
29719000Sbde}
29813116Sbde#endif /* GUPROF */
299