diff options
Diffstat (limited to 'libgloss/mep/mep-gmon.c')
-rw-r--r-- | libgloss/mep/mep-gmon.c | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/libgloss/mep/mep-gmon.c b/libgloss/mep/mep-gmon.c new file mode 100644 index 000000000..72d6369a3 --- /dev/null +++ b/libgloss/mep/mep-gmon.c @@ -0,0 +1,411 @@ +/*- + * Copyright (c) 1991, 1998, 2001 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. [rescinded 22 July 1999] + * 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. + */ + +#ifndef lint +static char sccsid[] = "@(#)gmon.c 5.3 (Berkeley) 5/22/91"; +#endif /* not lint */ + +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#define GMON_PTR_SIZE 4 + +struct phdr + { + char *lpc; /* base pc address of sample buffer */ + char *hpc; /* max pc address of sampled buffer */ + int ncnt; /* size of sample buffer (plus this header) */ + + char version[4]; /* version number */ + char profrate[4]; /* profiling clock rate */ + char spare[3*4]; /* reserved */ + }; + +#define GMONVERSION 0x00051879 + +/* + * Histogram counters are unsigned shorts: + */ +#define HISTCOUNTER unsigned short + +/* + * Fraction of text space to allocate for histogram counters here, 1/2: + */ +#define HISTFRACTION 2 + +/* + * Fraction of text space to allocate for from hash buckets. The + * value of HASHFRACTION is based on the minimum number of bytes of + * separation between two subroutine call points in the object code. + * Given MIN_SUBR_SEPARATION bytes of separation the value of + * HASHFRACTION is calculated as: + * + * HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1); + * + * For the VAX, the shortest two call sequence is: + * + * calls $0,(r0) + * calls $0,(r0) + * + * which is separated by only three bytes, thus HASHFRACTION is + * calculated as: + * + * HASHFRACTION = 3 / (2 * 2 - 1) = 1 + * + * Note that the division above rounds down, thus if MIN_SUBR_FRACTION + * is less than three, this algorithm will not work! + */ +#define HASHFRACTION 1 + +/* + * Percent of text space to allocate for tostructs with a minimum: + */ +#define ARCDENSITY 2 +#define MINARCS 50 + +struct tostruct + { + char *selfpc; + int count; + unsigned short link; + }; + +/* + * A raw arc, with pointers to the calling site and the called site + * and a count. Everything is defined in terms of characters so + * as to get a packed representation (otherwise, different compilers + * might introduce different padding): + */ +struct rawarc + { + unsigned long raw_frompc; + unsigned long raw_selfpc; + int raw_count; + }; + +/* + * General rounding functions: + */ +#define ROUNDDOWN(x,y) (((x)/(y))*(y)) +#define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y)) + + +#ifdef __alpha +extern char *sbrk (); +#endif + + /* + * froms is actually a bunch of unsigned shorts indexing tos + */ +static int profiling = 3; +static unsigned short *froms; +static struct tostruct *tos = 0; +static long tolimit = 0; +static char *s_lowpc = 0; +static char *s_highpc = 0; +static unsigned long s_textsize = 0; + +static int ssiz; +static char *sbuf; +static int s_scale; + /* see profil(2) where this is describe (incorrectly) */ +#define SCALE_1_TO_1 0x10000L + +#define MSG "No space for profiling buffer(s)\n" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +static void +moncleanup () +{ + int fd; + int fromindex; + int endfrom; + char *frompc; + int toindex; + struct rawarc rawarc; + + profiling = 1; + fd = open ("gmon.out", O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, 0666); + if (fd < 0) + { + perror ("mcount: gmon.out"); + return; + } +#ifdef DEBUG + fprintf (stderr, "[mcleanup] sbuf 0x%x ssiz %d\n", sbuf, ssiz); +#endif /* DEBUG */ + write (fd, sbuf, ssiz); + endfrom = s_textsize / (HASHFRACTION * sizeof (*froms)); + for (fromindex = 0; fromindex < endfrom; fromindex++) + { + if (froms[fromindex] == 0) + { + continue; + } + frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof (*froms)); + for (toindex = froms[fromindex]; toindex != 0; + toindex = tos[toindex].link) + { +#ifdef DEBUG + fprintf (stderr, + "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n", + frompc, tos[toindex].selfpc, tos[toindex].count); +#endif /* DEBUG */ + rawarc.raw_frompc = (unsigned long) frompc; + rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; + rawarc.raw_count = tos[toindex].count; + write (fd, &rawarc, sizeof rawarc); + } + } + close (fd); +} + +static void +monstartup (lowpc, highpc) + char *lowpc; + char *highpc; +{ + int monsize; + char *buffer; + register int o; + + atexit (moncleanup); + + /* + * 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. + */ + lowpc = (char *) + ROUNDDOWN ((unsigned) lowpc, HISTFRACTION * sizeof (HISTCOUNTER)); + s_lowpc = lowpc; + highpc = (char *) + ROUNDUP ((unsigned) highpc, HISTFRACTION * sizeof (HISTCOUNTER)); + s_highpc = highpc; + s_textsize = highpc - lowpc; + monsize = (s_textsize / HISTFRACTION) + sizeof (struct phdr); + buffer = sbrk (monsize); + if (buffer == (char *) -1) + { + write (2, MSG, sizeof (MSG)); + return; + } + froms = (unsigned short *) sbrk (s_textsize / HASHFRACTION); + if (froms == (unsigned short *) -1) + { + write (2, MSG, sizeof (MSG)); + froms = 0; + return; + } + tolimit = s_textsize * ARCDENSITY / 100; + if (tolimit < MINARCS) + { + tolimit = MINARCS; + } + else if (tolimit > 65534) + { + tolimit = 65534; + } + tos = (struct tostruct *) sbrk (tolimit * sizeof (struct tostruct)); + if (tos == (struct tostruct *) -1) + { + write (2, MSG, sizeof (MSG)); + froms = 0; + tos = 0; + return; + } + tos[0].link = 0; + sbuf = buffer; + ssiz = monsize; + ((struct phdr *) buffer)->lpc = lowpc; + ((struct phdr *) buffer)->hpc = highpc; + ((struct phdr *) buffer)->ncnt = ssiz; + monsize -= sizeof (struct phdr); + if (monsize <= 0) + return; + o = highpc - lowpc; + if (monsize < o) +#if 0 + s_scale = ((float) monsize / o) * SCALE_1_TO_1; +#else /* avoid floating point */ + { + int quot = o / monsize; + + if (quot >= 0x10000) + s_scale = 1; + else if (quot >= 0x100) + s_scale = 0x10000 / quot; + else if (o >= 0x800000) + s_scale = 0x1000000 / (o / (monsize >> 8)); + else + s_scale = 0x1000000 / ((o << 8) / monsize); + } +#endif + else + s_scale = SCALE_1_TO_1; + profiling = 0; +} + +/* These happen to be in the right place because of how crt0 works */ +extern char __attribute__((far)) _start; +extern char __attribute__((far)) _etext; + +void +__mep_mcount_2 (selfpc, frompcindex) + char *selfpc; + unsigned short *frompcindex; +{ + struct tostruct *top; + struct tostruct *prevtop; + long toindex; + static int initialized = 0; + + if (!initialized) + { + initialized = 1; + monstartup (&_start, &_etext); + } + + /* + * check that we are profiling + * and that we aren't recursively invoked. + */ + if (profiling) + { + goto out; + } + profiling++; + /* + * check that frompcindex is a reasonable pc value. + * for example: signal catchers get called from the stack, + * not from text space. too bad. + */ + frompcindex = (unsigned short *) ((long) frompcindex - (long) s_lowpc); + if ((unsigned long) frompcindex > s_textsize) + { + goto done; + } + frompcindex = + &froms[((long) frompcindex) / (HASHFRACTION * sizeof (*froms))]; + toindex = *frompcindex; + if (toindex == 0) + { + /* + * first time traversing this arc + */ + toindex = ++tos[0].link; + if (toindex >= tolimit) + { + goto overflow; + } + *frompcindex = toindex; + top = &tos[toindex]; + top->selfpc = selfpc; + top->count = 1; + top->link = 0; + goto done; + } + top = &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 = ++tos[0].link; + if (toindex >= tolimit) + { + goto overflow; + } + top = &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 = &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: + profiling--; + /* and fall through */ +out: + return; /* normal return restores saved registers */ + +overflow: + profiling++; /* halt further profiling */ +# define TOLIMIT "mcount: tos overflow\n" + write (2, TOLIMIT, sizeof (TOLIMIT)); + goto out; +} + + + |