diff options
Diffstat (limited to 'lib/libc/gmon')
-rw-r--r-- | lib/libc/gmon/Makefile.inc | 3 | ||||
-rw-r--r-- | lib/libc/gmon/gmon.c | 8 | ||||
-rw-r--r-- | lib/libc/gmon/mcount.c | 169 | ||||
-rw-r--r-- | lib/libc/gmon/moncontrol.3 | 3 |
4 files changed, 168 insertions, 15 deletions
diff --git a/lib/libc/gmon/Makefile.inc b/lib/libc/gmon/Makefile.inc index 959c3fb..57dc293 100644 --- a/lib/libc/gmon/Makefile.inc +++ b/lib/libc/gmon/Makefile.inc @@ -4,7 +4,8 @@ .PATH: ${.CURDIR}/gmon SRCS+= gmon.c mcount.c -MAN3+= moncontrol.0 +MAN3+= gmon/moncontrol.3 +MLINKS+= moncontrol.3 monstartup.3 # mcount cannot be compiled with profiling mcount.po: mcount.o diff --git a/lib/libc/gmon/gmon.c b/lib/libc/gmon/gmon.c index 022ffb5..81e36dd 100644 --- a/lib/libc/gmon/gmon.c +++ b/lib/libc/gmon/gmon.c @@ -44,7 +44,11 @@ static char sccsid[] = "@(#)gmon.c 8.1 (Berkeley) 6/4/93"; #include <fcntl.h> #include <unistd.h> +#if defined(__ELF__) +extern char *minbrk asm (".minbrk"); +#else extern char *minbrk asm ("minbrk"); +#endif struct gmonparam _gmonparam = { GMON_PROF_OFF }; @@ -106,7 +110,7 @@ monstartup(lowpc, highpc) s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1; #else /* avoid floating point */ int quot = o / p->kcountsize; - + if (quot >= 0x10000) s_scale = 1; else if (quot >= 0x100) @@ -239,7 +243,7 @@ static int hertz() { struct itimerval tim; - + tim.it_interval.tv_sec = 0; tim.it_interval.tv_usec = 1; tim.it_value.tv_sec = 0; diff --git a/lib/libc/gmon/mcount.c b/lib/libc/gmon/mcount.c index 523217d..a48e558 100644 --- a/lib/libc/gmon/mcount.c +++ b/lib/libc/gmon/mcount.c @@ -32,11 +32,25 @@ */ #if !defined(lint) && !defined(KERNEL) && defined(LIBC_SCCS) +#if 0 static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; #endif +static const char rcsid[] = + "$Id$"; +#endif #include <sys/param.h> #include <sys/gmon.h> +#ifdef KERNEL +#include <sys/systm.h> +#include <vm/vm.h> +#include <vm/vm_param.h> +#include <vm/pmap.h> +void bintr __P((void)); +void btrap __P((void)); +void eintr __P((void)); +void user __P((void)); +#endif /* * mcount is called on entry to each function compiled with the profiling @@ -48,44 +62,132 @@ static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93"; * _mcount updates data structures that represent traversals of the * program's call graph edges. frompc and selfpc are the return * address and function address that represents the given call graph edge. - * + * * Note: the original BSD code used the same variable (frompcindex) for * both frompcindex and frompc. Any reasonable, modern compiler will * perform this optimization. */ _MCOUNT_DECL(frompc, selfpc) /* _mcount; may be static, inline, etc */ - register u_long frompc, selfpc; + register fptrint_t frompc, selfpc; { +#ifdef GUPROF + u_int delta; +#endif + register fptrdiff_t frompci; register u_short *frompcindex; register struct tostruct *top, *prevtop; register struct gmonparam *p; register long toindex; #ifdef KERNEL - register int s; + MCOUNT_DECL(s) #endif p = &_gmonparam; +#ifndef GUPROF /* XXX */ /* * check that we are profiling * and that we aren't recursively invoked. */ if (p->state != GMON_PROF_ON) return; +#endif #ifdef KERNEL - MCOUNT_ENTER; + MCOUNT_ENTER(s); #else p->state = GMON_PROF_BUSY; #endif + frompci = frompc - p->lowpc; + +#ifdef KERNEL + /* + * When we are called from an exception handler, frompci may be + * for a user address. Convert such frompci's to the index of + * user() to merge all user counts. + */ + if (frompci >= p->textsize) { + if (frompci + p->lowpc + >= (fptrint_t)(VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE)) + goto done; + frompci = (fptrint_t)user - p->lowpc; + if (frompci >= p->textsize) + goto done; + } +#endif /* KERNEL */ + +#ifdef GUPROF + if (p->state != GMON_PROF_HIRES) + goto skip_guprof_stuff; /* - * check that frompcindex is a reasonable pc value. + * Look at the clock and add the count of clock cycles since the + * clock was last looked at to a counter for frompc. This + * solidifies the count for the function containing frompc and + * effectively starts another clock for the current function. + * The count for the new clock will be solidified when another + * function call is made or the function returns. + * + * We use the usual sampling counters since they can be located + * efficiently. 4-byte counters are usually necessary. + * + * There are many complications for subtracting the profiling + * overheads from the counts for normal functions and adding + * them to the counts for mcount(), mexitcount() and cputime(). + * We attempt to handle fractional cycles, but the overheads + * are usually underestimated because they are calibrated for + * a simpler than usual setup. + */ + delta = cputime() - p->mcount_overhead; + p->cputime_overhead_resid += p->cputime_overhead_frac; + p->mcount_overhead_resid += p->mcount_overhead_frac; + if ((int)delta < 0) + *p->mcount_count += delta + p->mcount_overhead + - p->cputime_overhead; + else if (delta != 0) { + if (p->cputime_overhead_resid >= CALIB_SCALE) { + p->cputime_overhead_resid -= CALIB_SCALE; + ++*p->cputime_count; + --delta; + } + if (delta != 0) { + if (p->mcount_overhead_resid >= CALIB_SCALE) { + p->mcount_overhead_resid -= CALIB_SCALE; + ++*p->mcount_count; + --delta; + } + KCOUNT(p, frompci) += delta; + } + *p->mcount_count += p->mcount_overhead_sub; + } + *p->cputime_count += p->cputime_overhead; +skip_guprof_stuff: +#endif /* GUPROF */ + +#ifdef KERNEL + /* + * When we are called from an exception handler, frompc is faked + * to be for where the exception occurred. We've just solidified + * the count for there. Now convert frompci to the index of btrap() + * for trap handlers and bintr() for interrupt handlers to make + * exceptions appear in the call graph as calls from btrap() and + * bintr() instead of calls from all over. + */ + if ((fptrint_t)selfpc >= (fptrint_t)btrap + && (fptrint_t)selfpc < (fptrint_t)eintr) { + if ((fptrint_t)selfpc >= (fptrint_t)bintr) + frompci = (fptrint_t)bintr - p->lowpc; + else + frompci = (fptrint_t)btrap - p->lowpc; + } +#endif /* KERNEL */ + + /* + * check that frompc is a reasonable pc value. * for example: signal catchers get called from the stack, * not from text space. too bad. */ - frompc -= p->lowpc; - if (frompc > p->textsize) + if (frompci >= p->textsize) goto done; - frompcindex = &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))]; + frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))]; toindex = *frompcindex; if (toindex == 0) { /* @@ -154,11 +256,11 @@ _MCOUNT_DECL(frompc, selfpc) /* _mcount; may be static, inline, etc */ *frompcindex = toindex; goto done; } - + } done: #ifdef KERNEL - MCOUNT_EXIT; + MCOUNT_EXIT(s); #else p->state = GMON_PROF_ON; #endif @@ -166,7 +268,7 @@ done: overflow: p->state = GMON_PROF_ERROR; #ifdef KERNEL - MCOUNT_EXIT; + MCOUNT_EXIT(s); #endif return; } @@ -176,3 +278,48 @@ overflow: * which is included by <sys/gmon.h>. */ MCOUNT + +#ifdef GUPROF +void +mexitcount(selfpc) + fptrint_t selfpc; +{ + struct gmonparam *p; + fptrint_t selfpcdiff; + + p = &_gmonparam; + selfpcdiff = selfpc - (fptrint_t)p->lowpc; + if (selfpcdiff < p->textsize) { + u_int delta; + + /* + * Solidify the count for the current function. + */ + delta = cputime() - p->mexitcount_overhead; + p->cputime_overhead_resid += p->cputime_overhead_frac; + p->mexitcount_overhead_resid += p->mexitcount_overhead_frac; + if ((int)delta < 0) + *p->mexitcount_count += delta + p->mexitcount_overhead + - p->cputime_overhead; + else if (delta != 0) { + if (p->cputime_overhead_resid >= CALIB_SCALE) { + p->cputime_overhead_resid -= CALIB_SCALE; + ++*p->cputime_count; + --delta; + } + if (delta != 0) { + if (p->mexitcount_overhead_resid + >= CALIB_SCALE) { + p->mexitcount_overhead_resid + -= CALIB_SCALE; + ++*p->mexitcount_count; + --delta; + } + KCOUNT(p, selfpcdiff) += delta; + } + *p->mexitcount_count += p->mexitcount_overhead_sub; + } + *p->cputime_count += p->cputime_overhead; + } +} +#endif /* GUPROF */ diff --git a/lib/libc/gmon/moncontrol.3 b/lib/libc/gmon/moncontrol.3 index 9b01f2b..1413bf5 100644 --- a/lib/libc/gmon/moncontrol.3 +++ b/lib/libc/gmon/moncontrol.3 @@ -98,4 +98,5 @@ Profiling begins on return from .Sh SEE ALSO .Xr cc 1 , .Xr gprof 1 , -.Xr profil 2 +.Xr profil 2 , +.Xr clocks 7 |