386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Fri, 3 Jul 1992 00:19:23 +0000 (16:19 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Fri, 3 Jul 1992 00:19:23 +0000 (16:19 -0800)
Work on file usr/src/lib/csu.i386/gmon.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/src/lib/csu.i386/gmon.c [new file with mode: 0644]

diff --git a/usr/src/lib/csu.i386/gmon.c b/usr/src/lib/csu.i386/gmon.c
new file mode 100644 (file)
index 0000000..5548688
--- /dev/null
@@ -0,0 +1,329 @@
+/*-
+ * Copyright (c) 1991 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(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gmon.c     5.3 (Berkeley) 5/22/91";
+#endif /* LIBC_SCCS and not lint */
+
+
+#include <unistd.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#include "gmon.h"
+
+extern mcount() asm ("mcount");
+extern char *minbrk asm ("minbrk");
+
+    /*
+     * 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"
+
+monstartup(lowpc, highpc)
+    char       *lowpc;
+    char       *highpc;
+{
+    int                        monsize;
+    char               *buffer;
+    register int       o;
+
+       /*
+        *      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;
+    }
+    minbrk = sbrk(0);
+    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 )
+#ifndef hp300
+       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;
+    moncontrol(1);
+}
+
+_mcleanup()
+{
+    int                        fd;
+    int                        fromindex;
+    int                        endfrom;
+    char               *frompc;
+    int                        toindex;
+    struct rawarc      rawarc;
+
+    moncontrol(0);
+    fd = creat( "gmon.out" , 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 );
+}
+
+mcount()
+{
+       register char                   *selfpc;
+       register unsigned short         *frompcindex;
+       register struct tostruct        *top;
+       register struct tostruct        *prevtop;
+       register long                   toindex;
+
+       /*
+        *      find the return address for mcount,
+        *      and the return address for mcount's caller.
+        */
+       asm(".text");           /* make sure we're in text space */
+       /*
+        * selfpc = pc pushed by mcount call
+        */
+       asm("movl 4(%%ebp),%0" : "=r" (selfpc));
+       /*
+        * frompcindex = pc pushed by jsr into self.
+        * In GCC the caller's stack frame has already been built so we
+        * have to chase a6 to find caller's raddr.
+        */
+       asm("movl (%%ebp),%0" : "=r" (frompcindex));
+       frompcindex = ((unsigned short **)frompcindex)[1];
+       /*
+        *      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;
+}
+
+/*
+ * Control profiling
+ *     profiling is what mcount checks to see if
+ *     all the data structures are ready.
+ */
+moncontrol(mode)
+    int mode;
+{
+    if (mode) {
+       /* start */
+       profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr),
+               (int)s_lowpc, s_scale);
+       profiling = 0;
+    } else {
+       /* stop */
+       profil((char *)0, 0, 0, 0);
+       profiling = 3;
+    }
+}