diff options
Diffstat (limited to 'lib/libc/gmon')
-rw-r--r-- | lib/libc/gmon/Makefile.inc | 17 | ||||
-rw-r--r-- | lib/libc/gmon/gmon.c | 261 | ||||
-rw-r--r-- | lib/libc/gmon/mcount.c | 325 | ||||
-rw-r--r-- | lib/libc/gmon/moncontrol.3 | 106 |
4 files changed, 709 insertions, 0 deletions
diff --git a/lib/libc/gmon/Makefile.inc b/lib/libc/gmon/Makefile.inc new file mode 100644 index 0000000..1b8a906 --- /dev/null +++ b/lib/libc/gmon/Makefile.inc @@ -0,0 +1,17 @@ +# from @(#)Makefile.inc 8.1 (Berkeley) 6/4/93 +# $FreeBSD$ + +# gmon sources +.PATH: ${.CURDIR}/../libc/gmon + +SRCS+= gmon.c mcount.c + +.if ${LIB} == "c" +MAN3+= moncontrol.3 + +MLINKS+=moncontrol.3 monstartup.3 +.endif + +# mcount cannot be compiled with profiling +mcount.po: mcount.o + cp mcount.o mcount.po diff --git a/lib/libc/gmon/gmon.c b/lib/libc/gmon/gmon.c new file mode 100644 index 0000000..267a469 --- /dev/null +++ b/lib/libc/gmon/gmon.c @@ -0,0 +1,261 @@ +/*- + * Copyright (c) 1983, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if !defined(lint) && defined(LIBC_SCCS) +static char sccsid[] = "@(#)gmon.c 8.1 (Berkeley) 6/4/93"; +#endif + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/gmon.h> +#include <sys/sysctl.h> + +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> + +#if defined(__ELF__) && defined(i386) +extern char *minbrk asm (".minbrk"); +#else +extern char *minbrk asm ("minbrk"); +#endif + +extern char *__progname; + +struct gmonparam _gmonparam = { GMON_PROF_OFF }; + +static int s_scale; +/* see profil(2) where this is describe (incorrectly) */ +#define SCALE_1_TO_1 0x10000L + +#define ERR(s) write(2, s, sizeof(s)) + +void moncontrol __P((int)); +static int hertz __P((void)); + +void +monstartup(lowpc, highpc) + u_long lowpc; + u_long highpc; +{ + register int o; + char *cp; + struct gmonparam *p = &_gmonparam; + + /* + * round lowpc and highpc to multiples of the density we're using + * so the rest of the scaling (here and in gprof) stays in ints. + */ + p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); + p->textsize = p->highpc - p->lowpc; + p->kcountsize = p->textsize / HISTFRACTION; + p->hashfraction = HASHFRACTION; + p->fromssize = p->textsize / HASHFRACTION; + p->tolimit = p->textsize * ARCDENSITY / 100; + if (p->tolimit < MINARCS) + p->tolimit = MINARCS; + else if (p->tolimit > MAXARCS) + p->tolimit = MAXARCS; + p->tossize = p->tolimit * sizeof(struct tostruct); + + cp = sbrk(p->kcountsize + p->fromssize + p->tossize); + if (cp == (char *)-1) { + ERR("monstartup: out of memory\n"); + return; + } +#ifdef notdef + bzero(cp, p->kcountsize + p->fromssize + p->tossize); +#endif + p->tos = (struct tostruct *)cp; + cp += p->tossize; + p->kcount = (u_short *)cp; + cp += p->kcountsize; + p->froms = (u_short *)cp; + + minbrk = sbrk(0); + p->tos[0].link = 0; + + o = p->highpc - p->lowpc; + if (p->kcountsize < o) { +#ifndef hp300 + 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) + s_scale = 0x10000 / quot; + else if (o >= 0x800000) + s_scale = 0x1000000 / (o / (p->kcountsize >> 8)); + else + s_scale = 0x1000000 / ((o << 8) / p->kcountsize); +#endif + } else + s_scale = SCALE_1_TO_1; + + moncontrol(1); +} + +void +_mcleanup() +{ + int fd; + int fromindex; + int endfrom; + u_long frompc; + int toindex; + struct rawarc rawarc; + struct gmonparam *p = &_gmonparam; + struct gmonhdr gmonhdr, *hdr; + struct clockinfo clockinfo; + char outname[128]; + int mib[2]; + size_t size; +#ifdef DEBUG + int log, len; + char buf[200]; +#endif + + if (p->state == GMON_PROF_ERROR) + ERR("_mcleanup: tos overflow\n"); + + size = sizeof(clockinfo); + mib[0] = CTL_KERN; + mib[1] = KERN_CLOCKRATE; + if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) { + /* + * Best guess + */ + clockinfo.profhz = hertz(); + } else if (clockinfo.profhz == 0) { + if (clockinfo.hz != 0) + clockinfo.profhz = clockinfo.hz; + else + clockinfo.profhz = hertz(); + } + + moncontrol(0); + snprintf(outname,sizeof(outname),"%s.gmon",__progname); + fd = open(outname, O_CREAT|O_TRUNC|O_WRONLY, 0666); + if (fd < 0) { + warnx("_mcleanup: %s - %s",outname,strerror(errno)); + return; + } +#ifdef DEBUG + log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664); + if (log < 0) { + perror("_mcleanup: gmon.log"); + return; + } + len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n", + p->kcount, p->kcountsize); + write(log, buf, len); +#endif + hdr = (struct gmonhdr *)&gmonhdr; + hdr->lpc = p->lowpc; + hdr->hpc = p->highpc; + hdr->ncnt = p->kcountsize + sizeof(gmonhdr); + hdr->version = GMONVERSION; + hdr->profrate = clockinfo.profhz; + write(fd, (char *)hdr, sizeof *hdr); + write(fd, p->kcount, p->kcountsize); + endfrom = p->fromssize / sizeof(*p->froms); + for (fromindex = 0; fromindex < endfrom; fromindex++) { + if (p->froms[fromindex] == 0) + continue; + + frompc = p->lowpc; + frompc += fromindex * p->hashfraction * sizeof(*p->froms); + for (toindex = p->froms[fromindex]; toindex != 0; + toindex = p->tos[toindex].link) { +#ifdef DEBUG + len = sprintf(buf, + "[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" , + frompc, p->tos[toindex].selfpc, + p->tos[toindex].count); + write(log, buf, len); +#endif + rawarc.raw_frompc = frompc; + rawarc.raw_selfpc = p->tos[toindex].selfpc; + rawarc.raw_count = p->tos[toindex].count; + write(fd, &rawarc, sizeof rawarc); + } + } + close(fd); +} + +/* + * Control profiling + * profiling is what mcount checks to see if + * all the data structures are ready. + */ +void +moncontrol(mode) + int mode; +{ + struct gmonparam *p = &_gmonparam; + + if (mode) { + /* start */ + profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale); + p->state = GMON_PROF_ON; + } else { + /* stop */ + profil((char *)0, 0, 0, 0); + p->state = GMON_PROF_OFF; + } +} + +/* + * discover the tick frequency of the machine + * if something goes wrong, we return 0, an impossible hertz. + */ +static int +hertz() +{ + struct itimerval tim; + + tim.it_interval.tv_sec = 0; + tim.it_interval.tv_usec = 1; + tim.it_value.tv_sec = 0; + tim.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &tim, 0); + setitimer(ITIMER_REAL, 0, &tim); + if (tim.it_interval.tv_usec < 2) + return(0); + return (1000000 / tim.it_interval.tv_usec); +} diff --git a/lib/libc/gmon/mcount.c b/lib/libc/gmon/mcount.c new file mode 100644 index 0000000..b27b386 --- /dev/null +++ b/lib/libc/gmon/mcount.c @@ -0,0 +1,325 @@ +/*- + * Copyright (c) 1983, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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[] = + "$FreeBSD$"; +#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 + * switch set. _mcount(), which is declared in a machine-dependent way + * with _MCOUNT_DECL, does the actual work and is either inlined into a + * C routine or called by an assembly stub. In any case, this magic is + * taken care of by the MCOUNT definition in <machine/profile.h>. + * + * _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 uintfptr_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 + 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(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 + >= (uintfptr_t)(VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE)) + goto done; + frompci = (uintfptr_t)user - p->lowpc; + if (frompci >= p->textsize) + goto done; + } +#endif /* KERNEL */ + +#ifdef GUPROF + if (p->state != GMON_PROF_HIRES) + goto skip_guprof_stuff; + /* + * 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 ((uintfptr_t)selfpc >= (uintfptr_t)btrap + && (uintfptr_t)selfpc < (uintfptr_t)eintr) { + if ((uintfptr_t)selfpc >= (uintfptr_t)bintr) + frompci = (uintfptr_t)bintr - p->lowpc; + else + frompci = (uintfptr_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. + */ + if (frompci >= p->textsize) + goto done; + + frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))]; + toindex = *frompcindex; + if (toindex == 0) { + /* + * first time traversing this arc + */ + toindex = ++p->tos[0].link; + if (toindex >= p->tolimit) + /* halt further profiling */ + goto overflow; + + *frompcindex = toindex; + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = 0; + goto done; + } + top = &p->tos[toindex]; + if (top->selfpc == selfpc) { + /* + * arc at front of chain; usual case. + */ + top->count++; + goto done; + } + /* + * have to go looking down chain for it. + * top points to what we are looking at, + * prevtop points to previous top. + * we know it is not at the head of the chain. + */ + for (; /* goto done */; ) { + if (top->link == 0) { + /* + * top is end of the chain and none of the chain + * had top->selfpc == selfpc. + * so we allocate a new tostruct + * and link it to the head of the chain. + */ + toindex = ++p->tos[0].link; + if (toindex >= p->tolimit) + goto overflow; + + top = &p->tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = *frompcindex; + *frompcindex = toindex; + goto done; + } + /* + * otherwise, check the next arc on the chain. + */ + prevtop = top; + top = &p->tos[top->link]; + if (top->selfpc == selfpc) { + /* + * there it is. + * increment its count + * move it to the head of the chain. + */ + top->count++; + toindex = prevtop->link; + prevtop->link = top->link; + top->link = *frompcindex; + *frompcindex = toindex; + goto done; + } + + } +done: +#ifdef KERNEL + MCOUNT_EXIT(s); +#else + p->state = GMON_PROF_ON; +#endif + return; +overflow: + p->state = GMON_PROF_ERROR; +#ifdef KERNEL + MCOUNT_EXIT(s); +#endif + return; +} + +/* + * Actual definition of mcount function. Defined in <machine/profile.h>, + * which is included by <sys/gmon.h>. + */ +MCOUNT + +#ifdef GUPROF +void +mexitcount(selfpc) + uintfptr_t selfpc; +{ + struct gmonparam *p; + uintfptr_t selfpcdiff; + + p = &_gmonparam; + selfpcdiff = selfpc - (uintfptr_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 new file mode 100644 index 0000000..f608f8f --- /dev/null +++ b/lib/libc/gmon/moncontrol.3 @@ -0,0 +1,106 @@ +.\" Copyright (c) 1980, 1991, 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)moncontrol.3 8.1 (Berkeley) 6/4/93 +.\" $FreeBSD$ +.\" +.Dd June 4, 1993 +.Dt MONCONTROL 3 +.Os BSD 4 +.Sh NAME +.Nm moncontrol , +.Nm monstartup +.Nd control execution profile +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Ft int +.Fn moncontrol "int mode" +.Ft int +.Fn monstartup "u_long *lowpc" "u_long *highpc" +.Sh DESCRIPTION +An executable program compiled using the +.Fl pg +option to +.Xr cc 1 +automatically includes calls to collect statistics for the +.Xr gprof 1 +call-graph execution profiler. +In typical operation, profiling begins at program startup +and ends when the program calls exit. +When the program exits, the profiling data are written to the file +.Em progname.gmon , +where progname is the name of the program, then +.Xr gprof 1 +can be used to examine the results. +.Pp +.Fn moncontrol +selectively controls profiling within a program. +When the program starts, profiling begins. +To stop the collection of histogram ticks and call counts use +.Fn moncontrol 0 ; +to resume the collection of histogram ticks and call counts use +.Fn moncontrol 1 . +This feature allows the cost of particular operations to be measured. +Note that an output file will be produced on program exit +regardless of the state of +.Fn moncontrol . +.Pp +Programs that are not loaded with +.Fl pg +may selectively collect profiling statistics by calling +.Fn monstartup +with the range of addresses to be profiled. +.Fa lowpc +and +.Fa highpc +specify the address range that is to be sampled; +the lowest address sampled is that of +.Fa lowpc +and the highest is just below +.Fa highpc . +Only functions in that range that have been compiled with the +.Fl pg +option to +.Xr cc 1 +will appear in the call graph part of the output; +however, all functions in that address range will +have their execution time measured. +Profiling begins on return from +.Fn monstartup . +.Sh FILES +.Bl -tag -width Pa -compact +.It Pa progname.gmon execution data file +.El +.Sh SEE ALSO +.Xr cc 1 , +.Xr gprof 1 , +.Xr profil 2 , +.Xr clocks 7 |