try to make display narrower
[unix-history] / usr / src / lib / libc / gmon / gmon.c
index c19654e..76a6d61 100644 (file)
-static char *sccsid = "@(#)gmon.c      1.3 (Berkeley) %G%";
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
 
 
-#include <stdio.h>
-
-#include "gmcrt0.h"
-
-    /*
-     * C start up routines, for monitoring
-     * Robert Henry, UCB, 20 Oct 81
-     *
-     * We make the following (true) assumptions:
-     * 1) when the kernel calls start, it does a jump to location 2,
-     * and thus avoids the register save mask.  We are NOT called
-     * with a calls!  see sys1.c:setregs().
-     * 2) The only register variable that we can trust is sp,
-     * which points to the base of the kernel calling frame.
-     * Do NOT believe the documentation in exec(2) regarding the
-     * values of fp and ap.
-     * 3) We can allocate as many register variables as we want,
-     * and don't have to save them for anybody.
-     * 4) Because of the ways that asm's work, we can't have
-     * any automatic variables allocated on the stack, because
-     * we must catch the value of sp before any automatics are
-     * allocated.
-     */
-
-char **environ;
-extern unsigned char   etext;
-asm( "#define _eprol eprol" );
-extern unsigned char   eprol;
-
-asm( "#define _start start" );
-start()
-{
-    struct kframe {
-       int     kargc;
-       char    *kargv[1];              /* size depends on kargc */
-       char    kargstr[1];             /* size varies */
-       char    kenvstr[1];             /* size varies */
-    };
-       /*
-        *      ALL REGISTER VARIABLES!!!
-        */
-    register struct kframe     *kfp;           /* r11 */
-    register char              **targv;
-    register char              **argv;
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)gmon.c     5.4 (Berkeley) %G%";
+#endif LIBC_SCCS and not lint
 
 
-#ifdef lint
-    kfp = 0;
-#else not lint
-    asm( "     movl    sp,r11" );              /* catch it quick */
-#endif not lint
-    for ( argv = targv = &kfp -> kargv[0] ; *targv++ ; /* void */ )
-       /* VOID */ ;
-    if ( targv >= (char **) ( *argv ) )
-       --targv;
-    environ = targv;
-asm("eprol:");
-    _mstartup( &eprol , &etext );
-    exit( main( kfp -> kargc , argv , environ ) );
-}
-asm( "#undef _start" );
-asm( "#undef _eprol" );
-
-exit( code )
-       /* ARGSUSED */
-    register int       code;   /* r11 */
-{
+#ifdef DEBUG
+#include <stdio.h>
+#endif DEBUG
 
 
-    fflush( stdout );
-    _mcleanup();
-    _cleanup();
-    asm( "     movl r11, r0" );
-    asm( "     chmk $1" );
-}
+#include "gmon.h"
 
     /*
      * froms is actually a bunch of unsigned shorts indexing tos
      */
 
     /*
      * froms is actually a bunch of unsigned shorts indexing tos
      */
+static int             profiling = 3;
 static unsigned short  *froms;
 static struct tostruct *tos = 0;
 static unsigned short  *froms;
 static struct tostruct *tos = 0;
-static unsigned short  tolimit = 0;
+static long            tolimit = 0;
 static char            *s_lowpc = 0;
 static char            *s_highpc = 0;
 static char            *s_lowpc = 0;
 static char            *s_highpc = 0;
+static unsigned long   s_textsize = 0;
 
 static int     ssiz;
 
 static int     ssiz;
-static int     *sbuf;
+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 monitor buffer(s)\n"
 
 
 #define        MSG "No space for monitor buffer(s)\n"
 
-_mstartup(lowpc, highpc)
+monstartup(lowpc, highpc)
     char       *lowpc;
     char       *highpc;
 {
     char       *lowpc;
     char       *highpc;
 {
-    int                monsize;
-    char       *buffer;
-    int                textsize;
-    char       *sbrk();
+    int                        monsize;
+    char               *buffer;
+    char               *sbrk();
+    extern char                *minbrk;
 
 
+       /*
+        *      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;
     s_lowpc = lowpc;
+    highpc = (char *)
+           ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER));
     s_highpc = highpc;
     s_highpc = highpc;
-    textsize = ( (char *) highpc - (char *) lowpc );
-    monsize = textsize + sizeof(struct phdr);
+    s_textsize = highpc - lowpc;
+    monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr);
     buffer = sbrk( monsize );
     if ( buffer == (char *) -1 ) {
     buffer = sbrk( monsize );
     if ( buffer == (char *) -1 ) {
-       write( 2 , MSG , sizeof(MSG) );
+       write( 2 , MSG , sizeof(MSG) - 1 );
        return;
     }
        return;
     }
-    froms = (unsigned short *) sbrk( textsize );
+    froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION );
     if ( froms == (unsigned short *) -1 ) {
     if ( froms == (unsigned short *) -1 ) {
-       write( 2 , MSG , sizeof(MSG) );
+       write( 2 , MSG , sizeof(MSG) - 1 );
        froms = 0;
        return;
     }
        froms = 0;
        return;
     }
-    tos = (struct tostruct *) sbrk(textsize);
+    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 ) {
     if ( tos == (struct tostruct *) -1 ) {
-       write( 2 , MSG , sizeof(MSG) );
+       write( 2 , MSG , sizeof(MSG) - 1 );
        froms = 0;
        tos = 0;
        return;
     }
        froms = 0;
        tos = 0;
        return;
     }
-    tolimit = textsize / sizeof(struct tostruct);
+    minbrk = sbrk(0);
     tos[0].link = 0;
     tos[0].link = 0;
-    monitor( lowpc , highpc , buffer , monsize );
+    monitor( lowpc , highpc , buffer , monsize , tolimit );
 }
 
 _mcleanup()
 {
 }
 
 _mcleanup()
 {
-    FILE       *fd;
-    int                fromindex;
-    char       *frompc;
-    int                toindex;
-    int                textsize;
+    int                        fd;
+    int                        fromindex;
+    int                        endfrom;
+    char               *frompc;
+    int                        toindex;
+    struct rawarc      rawarc;
 
 
-    monitor( (int (*)()) 0 );
-    fd = fopen( "gmon.out" , "w" );
-    if ( fd == NULL ) {
+    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
        perror( "mcount: gmon.out" );
        return;
     }
 #   ifdef DEBUG
        fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz );
 #   endif DEBUG
-    fwrite( sbuf , 1 , ssiz , fd );
-    textsize = s_highpc - s_lowpc;
-    for ( fromindex = 0 ; fromindex < textsize>>1 ; fromindex++ ) {
+    write( fd , sbuf , ssiz );
+    endfrom = s_textsize / (HASHFRACTION * sizeof(*froms));
+    for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) {
        if ( froms[fromindex] == 0 ) {
            continue;
        }
        if ( froms[fromindex] == 0 ) {
            continue;
        }
-       frompc = s_lowpc + (fromindex<<1);
+       frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms));
        for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
 #          ifdef DEBUG
        for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) {
 #          ifdef DEBUG
-               fprintf( stderr , "[mcleanup] frompc %d selfpc %d count %d\n" ,
+               fprintf( stderr ,
+                       "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" ,
                        frompc , tos[toindex].selfpc , tos[toindex].count );
 #          endif DEBUG
                        frompc , tos[toindex].selfpc , tos[toindex].count );
 #          endif DEBUG
-           fwrite( &frompc, 1, sizeof frompc, fd );
-           fwrite( &tos[toindex].selfpc, 1, sizeof tos[toindex].selfpc, fd );
-           fwrite( &tos[toindex].count, 1, sizeof tos[toindex].count, fd );
+           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 );
        }
     }
        }
     }
-    fclose( fd );
+    close( fd );
 }
 
 }
 
-    /*
-     * This routine is massaged so that it may be jsb'ed to
-     */
-asm("#define _mcount mcount");
+asm(".text");
+asm(".align 2");
+asm("#the beginning of mcount()");
+asm(".data");
 mcount()
 {
 mcount()
 {
-    register char              *selfpc;        /* r11 */
-    register unsigned short    *frompcindex;   /* r10 */
-    register struct tostruct   *top;           /* r9 */
-    static int                 profiling = 0;
+       register char                   *selfpc;        /* r11 => r5 */
+       register unsigned short         *frompcindex;   /* r10 => r4 */
+       register struct tostruct        *top;           /* r9  => r3 */
+       register struct tostruct        *prevtop;       /* r8  => r2 */
+       register long                   toindex;        /* r7  => r1 */
 
 
-    asm( "     forgot to run ex script on gmcrt0.s" );
-    asm( "#define r11 r5" );
-    asm( "#define r10 r4" );
-    asm( "#define r9 r3" );
-#ifdef lint
-    selfpc = (char *) 0;
-    frompcindex = 0;
-#else not lint
        /*
         *      find the return address for mcount,
         *      and the return address for mcount's caller.
         */
        /*
         *      find the return address for mcount,
         *      and the return address for mcount's caller.
         */
-    asm("      movl (sp), r11");       /* selfpc = ... (jsb frame) */
-    asm("      movl 16(fp), r10");     /* frompcindex =     (calls frame) */
-#endif not lint
+       asm("   .text");                /* make sure we're in text space */
+       asm("   movl (sp), r11");       /* selfpc = ... (jsb frame) */
+       asm("   movl 16(fp), r10");     /* frompcindex =     (calls frame) */
        /*
         *      check that we are profiling
         *      and that we aren't recursively invoked.
         */
        /*
         *      check that we are profiling
         *      and that we aren't recursively invoked.
         */
-    if ( tos == 0 ) {
-       goto out;
-    }
-    if ( profiling ) {
-       goto out;
-    }
-    profiling = 1;
+       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.
         */
        /*
         *      check that frompcindex is a reasonable pc value.
         *      for example:    signal catchers get called from the stack,
         *                      not from text space.  too bad.
         */
-    if ( (char *) frompcindex < s_lowpc || (char *) frompcindex > s_highpc ) {
-       goto done;
-    }
-    frompcindex = &froms[ ( (long) frompcindex - (long) s_lowpc ) >> 1 ];
-    if ( *frompcindex == 0 ) {
-       *frompcindex = ++tos[0].link;
-       if ( *frompcindex >= tolimit ) {
-           goto overflow;
+       frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc);
+       if ((unsigned long)frompcindex > s_textsize) {
+               goto done;
        }
        }
-       top = &tos[ *frompcindex ];
-       top->selfpc = selfpc;
-       top->count = 0;
-       top->link = 0;
-    } else {
-       top = &tos[ *frompcindex ];
-    }
-    for ( ; /* goto done */ ; top = &tos[ top -> link ] ) {
-       if ( top -> selfpc == selfpc ) {
-           top -> count++;
-           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;
        }
        }
-       if ( top -> link == 0 ) {
-           top -> link = ++tos[0].link;
-           if ( top -> link >= tolimit )
-               goto overflow;
-           top = &tos[ top -> link ];
-           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:
 done:
-    profiling = 0;
-    /* and fall through */
+       profiling--;
+       /* and fall through */
 out:
 out:
-    asm( "     rsb" );
-    asm( "#undef r11" );
-    asm( "#undef r10" );
-    asm( "#undef r9" );
-    asm( "#undef _mcount");
+       asm("   rsb");
 
 overflow:
 
 overflow:
+       profiling++; /* halt further profiling */
 #   define     TOLIMIT "mcount: tos overflow\n"
 #   define     TOLIMIT "mcount: tos overflow\n"
-    write( 2 , TOLIMIT , sizeof( TOLIMIT ) );
-    tos = 0;
-    froms = 0;
-    goto out;
+       write(2, TOLIMIT, sizeof(TOLIMIT) - 1);
+       goto out;
 }
 }
+asm(".text");
+asm("#the end of mcount()");
+asm(".data");
 
 
-monitor( lowpc , highpc , buf , bufsiz )
+/*VARARGS1*/
+monitor( lowpc , highpc , buf , bufsiz , nfunc )
     char       *lowpc;
     char       *lowpc;
-    /* VARARGS1 */
     char       *highpc;
     char       *highpc;
-    int                *buf, bufsiz;
+    char       *buf;   /* declared ``short buffer[]'' in monitor(3) */
+    int                bufsiz;
+    int                nfunc;  /* not used, available for compatability only */
 {
     register o;
 
     if ( lowpc == 0 ) {
 {
     register o;
 
     if ( lowpc == 0 ) {
-       profil( (char *) 0 , 0 , 0 , 0 );
+       moncontrol(0);
+       _mcleanup();
        return;
     }
     sbuf = buf;
        return;
     }
     sbuf = buf;
@@ -270,15 +265,33 @@ monitor( lowpc , highpc , buf , bufsiz )
     ( (struct phdr *) buf ) -> lpc = lowpc;
     ( (struct phdr *) buf ) -> hpc = highpc;
     ( (struct phdr *) buf ) -> ncnt = ssiz;
     ( (struct phdr *) buf ) -> lpc = lowpc;
     ( (struct phdr *) buf ) -> hpc = highpc;
     ( (struct phdr *) buf ) -> ncnt = ssiz;
-    o = sizeof(struct phdr);
-    buf = (int *) ( ( (int) buf ) + o );
-    bufsiz -= o;
+    bufsiz -= sizeof(struct phdr);
     if ( bufsiz <= 0 )
        return;
     if ( bufsiz <= 0 )
        return;
-    o = ( ( (char *) highpc - (char *) lowpc) >> 1 );
+    o = highpc - lowpc;
     if( bufsiz < o )
     if( bufsiz < o )
-       o = ( (float) bufsiz / o ) * 32768;
+       s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1;
     else
     else
-       o = 0177777;
-    profil( buf , bufsiz , lowpc , o );
+       s_scale = SCALE_1_TO_1;
+    moncontrol(1);
+}
+
+/*
+ * 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),
+               s_lowpc, s_scale);
+       profiling = 0;
+    } else {
+       /* stop */
+       profil((char *)0, 0, 0, 0);
+       profiling = 3;
+    }
 }
 }