Initial revision
authorSean Eric Fagan <sef@cygnus>
Thu, 18 Jul 1991 20:19:17 +0000 (20:19 +0000)
committerSean Eric Fagan <sef@cygnus>
Thu, 18 Jul 1991 20:19:17 +0000 (20:19 +0000)
21 files changed:
gprof/Makefile [new file with mode: 0755]
gprof/arcs.c [new file with mode: 0644]
gprof/dfn.c [new file with mode: 0644]
gprof/gmon.h [new file with mode: 0644]
gprof/gprof.1 [new file with mode: 0644]
gprof/gprof.c [new file with mode: 0644]
gprof/gprof.callg [new file with mode: 0644]
gprof/gprof.flat [new file with mode: 0644]
gprof/gprof.h [new file with mode: 0644]
gprof/hertz.c [new file with mode: 0644]
gprof/lookup.c [new file with mode: 0644]
gprof/pathnames.h [new file with mode: 0755]
gprof/printgprof.c [new file with mode: 0644]
gprof/printlist.c [new file with mode: 0644]
gprof/sparc.c [new file with mode: 0644]
gprof/sparc.h [new file with mode: 0644]
gprof/t.c [new file with mode: 0755]
gprof/tahoe.c [new file with mode: 0644]
gprof/tahoe.h [new file with mode: 0644]
gprof/vax.c [new file with mode: 0644]
gprof/vax.h [new file with mode: 0644]

diff --git a/gprof/Makefile b/gprof/Makefile
new file mode 100755 (executable)
index 0000000..9c14d68
--- /dev/null
@@ -0,0 +1,23 @@
+#      @(#)Makefile    5.17 (Berkeley) 5/11/90
+
+CC=    gcc
+MACHINE=       sparc
+PROG=  gprof
+SRCS=  gprof.c arcs.c dfn.c lookup.c ${MACHINE}.c hertz.c \
+       printgprof.c printlist.c
+#CFLAGS+=-I${.CURDIR}/../../lib/csu.${MACHINE}
+CFLAGS=        -I. -O -g -DMACHINE_H=\"${MACHINE}.h\"
+
+OBJS=  gprof.o arcs.o dfn.o lookup.o ${MACHINE}.o hertz.o \
+       printgprof.o printlist.o
+
+all:   ${PROG}
+
+beforeinstall:
+       install -c -o ${BINOWN} -g ${BINGRP} -m ${BINMODE} \
+           ${.CURDIR}/gprof.flat ${.CURDIR}/gprof.callg \
+           ${DESTDIR}/usr/share/misc
+
+#.include <bsd.prog.mk>
+$(PROG):       $(OBJS)
+       $(CC) $(CFLAGS) $(OBJS) -o $(PROG) $(LIBS)
diff --git a/gprof/arcs.c b/gprof/arcs.c
new file mode 100644 (file)
index 0000000..8cb6dad
--- /dev/null
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)arcs.c     5.6 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include "gprof.h"
+
+    /*
+     * add (or just increment) an arc
+     */
+addarc( parentp , childp , count )
+    nltype     *parentp;
+    nltype     *childp;
+    long       count;
+{
+    arctype            *calloc();
+    arctype            *arcp;
+
+#   ifdef DEBUG
+       if ( debug & TALLYDEBUG ) {
+           printf( "[addarc] %d arcs from %s to %s\n" ,
+                   count , parentp -> name , childp -> name );
+       }
+#   endif DEBUG
+    arcp = arclookup( parentp , childp );
+    if ( arcp != 0 ) {
+           /*
+            *  a hit:  just increment the count.
+            */
+#      ifdef DEBUG
+           if ( debug & TALLYDEBUG ) {
+               printf( "[tally] hit %d += %d\n" ,
+                       arcp -> arc_count , count );
+           }
+#      endif DEBUG
+       arcp -> arc_count += count;
+       return;
+    }
+    arcp = calloc( 1 , sizeof *arcp );
+    arcp -> arc_parentp = parentp;
+    arcp -> arc_childp = childp;
+    arcp -> arc_count = count;
+       /*
+        *      prepend this child to the children of this parent
+        */
+    arcp -> arc_childlist = parentp -> children;
+    parentp -> children = arcp;
+       /*
+        *      prepend this parent to the parents of this child
+        */
+    arcp -> arc_parentlist = childp -> parents;
+    childp -> parents = arcp;
+}
+
+    /*
+     * the code below topologically sorts the graph (collapsing cycles),
+     * and propagates time bottom up and flags top down.
+     */
+
+    /*
+     * the topologically sorted name list pointers
+     */
+nltype **topsortnlp;
+
+topcmp( npp1 , npp2 )
+    nltype     **npp1;
+    nltype     **npp2;
+{
+    return (*npp1) -> toporder - (*npp2) -> toporder;
+}
+
+nltype **
+doarcs()
+{
+    nltype     *parentp, **timesortnlp;
+    arctype    *arcp;
+    long       index;
+
+       /*
+        *      initialize various things:
+        *          zero out child times.
+        *          count self-recursive calls.
+        *          indicate that nothing is on cycles.
+        */
+    for ( parentp = nl ; parentp < npe ; parentp++ ) {
+       parentp -> childtime = 0.0;
+       arcp = arclookup( parentp , parentp );
+       if ( arcp != 0 ) {
+           parentp -> ncall -= arcp -> arc_count;
+           parentp -> selfcalls = arcp -> arc_count;
+       } else {
+           parentp -> selfcalls = 0;
+       }
+       parentp -> propfraction = 0.0;
+       parentp -> propself = 0.0;
+       parentp -> propchild = 0.0;
+       parentp -> printflag = FALSE;
+       parentp -> toporder = DFN_NAN;
+       parentp -> cycleno = 0;
+       parentp -> cyclehead = parentp;
+       parentp -> cnext = 0;
+       if ( cflag ) {
+           findcall( parentp , parentp -> value , (parentp+1) -> value );
+       }
+    }
+       /*
+        *      topologically order things
+        *      if any node is unnumbered,
+        *          number it and any of its descendents.
+        */
+    for ( parentp = nl ; parentp < npe ; parentp++ ) {
+       if ( parentp -> toporder == DFN_NAN ) {
+           dfn( parentp );
+       }
+    }
+       /*
+        *      link together nodes on the same cycle
+        */
+    cyclelink();
+       /*
+        *      Sort the symbol table in reverse topological order
+        */
+    topsortnlp = (nltype **) calloc( nname , sizeof(nltype *) );
+    if ( topsortnlp == (nltype **) 0 ) {
+       fprintf( stderr , "[doarcs] ran out of memory for topo sorting\n" );
+    }
+    for ( index = 0 ; index < nname ; index += 1 ) {
+       topsortnlp[ index ] = &nl[ index ];
+    }
+    qsort( topsortnlp , nname , sizeof(nltype *) , topcmp );
+#   ifdef DEBUG
+       if ( debug & DFNDEBUG ) {
+           printf( "[doarcs] topological sort listing\n" );
+           for ( index = 0 ; index < nname ; index += 1 ) {
+               printf( "[doarcs] " );
+               printf( "%d:" , topsortnlp[ index ] -> toporder );
+               printname( topsortnlp[ index ] );
+               printf( "\n" );
+           }
+       }
+#   endif DEBUG
+       /*
+        *      starting from the topological top,
+        *      propagate print flags to children.
+        *      also, calculate propagation fractions.
+        *      this happens before time propagation
+        *      since time propagation uses the fractions.
+        */
+    doflags();
+       /*
+        *      starting from the topological bottom, 
+        *      propogate children times up to parents.
+        */
+    dotime();
+       /*
+        *      Now, sort by propself + propchild.
+        *      sorting both the regular function names
+        *      and cycle headers.
+        */
+    timesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
+    if ( timesortnlp == (nltype **) 0 ) {
+       fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami );
+    }
+    for ( index = 0 ; index < nname ; index++ ) {
+       timesortnlp[index] = &nl[index];
+    }
+    for ( index = 1 ; index <= ncycle ; index++ ) {
+       timesortnlp[nname+index-1] = &cyclenl[index];
+    }
+    qsort( timesortnlp , nname + ncycle , sizeof(nltype *) , totalcmp );
+    for ( index = 0 ; index < nname + ncycle ; index++ ) {
+       timesortnlp[ index ] -> index = index + 1;
+    }
+    return( timesortnlp );
+}
+
+dotime()
+{
+    int        index;
+
+    cycletime();
+    for ( index = 0 ; index < nname ; index += 1 ) {
+       timepropagate( topsortnlp[ index ] );
+    }
+}
+
+timepropagate( parentp )
+    nltype     *parentp;
+{
+    arctype    *arcp;
+    nltype     *childp;
+    double     share;
+    double     propshare;
+
+    if ( parentp -> propfraction == 0.0 ) {
+       return;
+    }
+       /*
+        *      gather time from children of this parent.
+        */
+    for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
+       childp = arcp -> arc_childp;
+       if ( arcp -> arc_count == 0 ) {
+           continue;
+       }
+       if ( childp == parentp ) {
+           continue;
+       }
+       if ( childp -> propfraction == 0.0 ) {
+           continue;
+       }
+       if ( childp -> cyclehead != childp ) {
+           if ( parentp -> cycleno == childp -> cycleno ) {
+               continue;
+           }
+           if ( parentp -> toporder <= childp -> toporder ) {
+               fprintf( stderr , "[propagate] toporder botches\n" );
+           }
+           childp = childp -> cyclehead;
+       } else {
+           if ( parentp -> toporder <= childp -> toporder ) {
+               fprintf( stderr , "[propagate] toporder botches\n" );
+               continue;
+           }
+       }
+       if ( childp -> ncall == 0 ) {
+           continue;
+       }
+           /*
+            *  distribute time for this arc
+            */
+       arcp -> arc_time = childp -> time
+                               * ( ( (double) arcp -> arc_count ) /
+                                   ( (double) childp -> ncall ) );
+       arcp -> arc_childtime = childp -> childtime
+                               * ( ( (double) arcp -> arc_count ) /
+                                   ( (double) childp -> ncall ) );
+       share = arcp -> arc_time + arcp -> arc_childtime;
+       parentp -> childtime += share;
+           /*
+            *  ( 1 - propfraction ) gets lost along the way
+            */
+       propshare = parentp -> propfraction * share;
+           /*
+            *  fix things for printing
+            */
+       parentp -> propchild += propshare;
+       arcp -> arc_time *= parentp -> propfraction;
+       arcp -> arc_childtime *= parentp -> propfraction;
+           /*
+            *  add this share to the parent's cycle header, if any.
+            */
+       if ( parentp -> cyclehead != parentp ) {
+           parentp -> cyclehead -> childtime += share;
+           parentp -> cyclehead -> propchild += propshare;
+       }
+#      ifdef DEBUG
+           if ( debug & PROPDEBUG ) {
+               printf( "[dotime] child \t" );
+               printname( childp );
+               printf( " with %f %f %d/%d\n" ,
+                       childp -> time , childp -> childtime ,
+                       arcp -> arc_count , childp -> ncall );
+               printf( "[dotime] parent\t" );
+               printname( parentp );
+               printf( "\n[dotime] share %f\n" , share );
+           }
+#      endif DEBUG
+    }
+}
+
+cyclelink()
+{
+    register nltype    *nlp;
+    register nltype    *cyclenlp;
+    int                        cycle;
+    nltype             *memberp;
+    arctype            *arcp;
+
+       /*
+        *      Count the number of cycles, and initialze the cycle lists
+        */
+    ncycle = 0;
+    for ( nlp = nl ; nlp < npe ; nlp++ ) {
+           /*
+            *  this is how you find unattached cycles
+            */
+       if ( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) {
+           ncycle += 1;
+       }
+    }
+       /*
+        *      cyclenl is indexed by cycle number:
+        *      i.e. it is origin 1, not origin 0.
+        */
+    cyclenl = (nltype *) calloc( ncycle + 1 , sizeof( nltype ) );
+    if ( cyclenl == 0 ) {
+       fprintf( stderr , "%s: No room for %d bytes of cycle headers\n" ,
+               whoami , ( ncycle + 1 ) * sizeof( nltype ) );
+       done();
+    }
+       /*
+        *      now link cycles to true cycleheads,
+        *      number them, accumulate the data for the cycle
+        */
+    cycle = 0;
+    for ( nlp = nl ; nlp < npe ; nlp++ ) {
+       if ( !( nlp -> cyclehead == nlp && nlp -> cnext != 0 ) ) {
+           continue;
+       }
+       cycle += 1;
+       cyclenlp = &cyclenl[cycle];
+        cyclenlp -> name = 0;          /* the name */
+        cyclenlp -> value = 0;         /* the pc entry point */
+        cyclenlp -> time = 0.0;                /* ticks in this routine */
+        cyclenlp -> childtime = 0.0;   /* cumulative ticks in children */
+       cyclenlp -> ncall = 0;          /* how many times called */
+       cyclenlp -> selfcalls = 0;      /* how many calls to self */
+       cyclenlp -> propfraction = 0.0; /* what % of time propagates */
+       cyclenlp -> propself = 0.0;     /* how much self time propagates */
+       cyclenlp -> propchild = 0.0;    /* how much child time propagates */
+       cyclenlp -> printflag = TRUE;   /* should this be printed? */
+       cyclenlp -> index = 0;          /* index in the graph list */
+       cyclenlp -> toporder = DFN_NAN; /* graph call chain top-sort order */
+       cyclenlp -> cycleno = cycle;    /* internal number of cycle on */
+       cyclenlp -> cyclehead = cyclenlp;       /* pointer to head of cycle */
+       cyclenlp -> cnext = nlp;        /* pointer to next member of cycle */
+       cyclenlp -> parents = 0;        /* list of caller arcs */
+       cyclenlp -> children = 0;       /* list of callee arcs */
+#      ifdef DEBUG
+           if ( debug & CYCLEDEBUG ) {
+               printf( "[cyclelink] " );
+               printname( nlp );
+               printf( " is the head of cycle %d\n" , cycle );
+           }
+#      endif DEBUG
+           /*
+            *  link members to cycle header
+            */
+       for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) { 
+           memberp -> cycleno = cycle;
+           memberp -> cyclehead = cyclenlp;
+       }
+           /*
+            *  count calls from outside the cycle
+            *  and those among cycle members
+            */
+       for ( memberp = nlp ; memberp ; memberp = memberp -> cnext ) {
+           for ( arcp=memberp->parents ; arcp ; arcp=arcp->arc_parentlist ) {
+               if ( arcp -> arc_parentp == memberp ) {
+                   continue;
+               }
+               if ( arcp -> arc_parentp -> cycleno == cycle ) {
+                   cyclenlp -> selfcalls += arcp -> arc_count;
+               } else {
+                   cyclenlp -> ncall += arcp -> arc_count;
+               }
+           }
+       }
+    }
+}
+
+cycletime()
+{
+    int                        cycle;
+    nltype             *cyclenlp;
+    nltype             *childp;
+
+    for ( cycle = 1 ; cycle <= ncycle ; cycle += 1 ) {
+       cyclenlp = &cyclenl[ cycle ];
+       for ( childp = cyclenlp -> cnext ; childp ; childp = childp -> cnext ) {
+           if ( childp -> propfraction == 0.0 ) {
+                   /*
+                    * all members have the same propfraction except those
+                    *  that were excluded with -E
+                    */
+               continue;
+           }
+           cyclenlp -> time += childp -> time;
+       }
+       cyclenlp -> propself = cyclenlp -> propfraction * cyclenlp -> time;
+    }
+}
+
+    /*
+     * in one top to bottom pass over the topologically sorted namelist
+     * propagate:
+     *         printflag as the union of parents' printflags
+     *         propfraction as the sum of fractional parents' propfractions
+     * and while we're here, sum time for functions.
+     */
+doflags()
+{
+    int                index;
+    nltype     *childp;
+    nltype     *oldhead;
+
+    oldhead = 0;
+    for ( index = nname-1 ; index >= 0 ; index -= 1 ) {
+       childp = topsortnlp[ index ];
+           /*
+            *  if we haven't done this function or cycle,
+            *  inherit things from parent.
+            *  this way, we are linear in the number of arcs
+            *  since we do all members of a cycle (and the cycle itself)
+            *  as we hit the first member of the cycle.
+            */
+       if ( childp -> cyclehead != oldhead ) {
+           oldhead = childp -> cyclehead;
+           inheritflags( childp );
+       }
+#      ifdef DEBUG
+           if ( debug & PROPDEBUG ) {
+               printf( "[doflags] " );
+               printname( childp );
+               printf( " inherits printflag %d and propfraction %f\n" ,
+                       childp -> printflag , childp -> propfraction );
+           }
+#      endif DEBUG
+       if ( ! childp -> printflag ) {
+               /*
+                *      printflag is off
+                *      it gets turned on by
+                *      being on -f list,
+                *      or there not being any -f list and not being on -e list.
+                */
+           if (   onlist( flist , childp -> name )
+               || ( !fflag && !onlist( elist , childp -> name ) ) ) {
+               childp -> printflag = TRUE;
+           }
+       } else {
+               /*
+                *      this function has printing parents:
+                *      maybe someone wants to shut it up
+                *      by putting it on -e list.  (but favor -f over -e)
+                */
+           if (  ( !onlist( flist , childp -> name ) )
+               && onlist( elist , childp -> name ) ) {
+               childp -> printflag = FALSE;
+           }
+       }
+       if ( childp -> propfraction == 0.0 ) {
+               /*
+                *      no parents to pass time to.
+                *      collect time from children if
+                *      its on -F list,
+                *      or there isn't any -F list and its not on -E list.
+                */
+           if ( onlist( Flist , childp -> name )
+               || ( !Fflag && !onlist( Elist , childp -> name ) ) ) {
+                   childp -> propfraction = 1.0;
+           }
+       } else {
+               /*
+                *      it has parents to pass time to, 
+                *      but maybe someone wants to shut it up
+                *      by puttting it on -E list.  (but favor -F over -E)
+                */
+           if (  !onlist( Flist , childp -> name )
+               && onlist( Elist , childp -> name ) ) {
+               childp -> propfraction = 0.0;
+           }
+       }
+       childp -> propself = childp -> time * childp -> propfraction;
+       printtime += childp -> propself;
+#      ifdef DEBUG
+           if ( debug & PROPDEBUG ) {
+               printf( "[doflags] " );
+               printname( childp );
+               printf( " ends up with printflag %d and propfraction %f\n" ,
+                       childp -> printflag , childp -> propfraction );
+               printf( "time %f propself %f printtime %f\n" ,
+                       childp -> time , childp -> propself , printtime );
+           }
+#      endif DEBUG
+    }
+}
+
+    /*
+     * check if any parent of this child
+     * (or outside parents of this cycle)
+     * have their print flags on and set the 
+     * print flag of the child (cycle) appropriately.
+     * similarly, deal with propagation fractions from parents.
+     */
+inheritflags( childp )
+    nltype     *childp;
+{
+    nltype     *headp;
+    arctype    *arcp;
+    nltype     *parentp;
+    nltype     *memp;
+
+    headp = childp -> cyclehead;
+    if ( childp == headp ) {
+           /*
+            *  just a regular child, check its parents
+            */
+       childp -> printflag = FALSE;
+       childp -> propfraction = 0.0;
+       for (arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist) {
+           parentp = arcp -> arc_parentp;
+           if ( childp == parentp ) {
+               continue;
+           }
+           childp -> printflag |= parentp -> printflag;
+               /*
+                *      if the child was never actually called
+                *      (e.g. this arc is static (and all others are, too))
+                *      no time propagates along this arc.
+                */
+           if ( childp -> ncall ) {
+               childp -> propfraction += parentp -> propfraction
+                                           * ( ( (double) arcp -> arc_count )
+                                             / ( (double) childp -> ncall ) );
+           }
+       }
+    } else {
+           /*
+            *  its a member of a cycle, look at all parents from 
+            *  outside the cycle
+            */
+       headp -> printflag = FALSE;
+       headp -> propfraction = 0.0;
+       for ( memp = headp -> cnext ; memp ; memp = memp -> cnext ) {
+           for (arcp = memp->parents ; arcp ; arcp = arcp->arc_parentlist) {
+               if ( arcp -> arc_parentp -> cyclehead == headp ) {
+                   continue;
+               }
+               parentp = arcp -> arc_parentp;
+               headp -> printflag |= parentp -> printflag;
+                   /*
+                    *  if the cycle was never actually called
+                    *  (e.g. this arc is static (and all others are, too))
+                    *  no time propagates along this arc.
+                    */
+               if ( headp -> ncall ) {
+                   headp -> propfraction += parentp -> propfraction
+                                           * ( ( (double) arcp -> arc_count )
+                                             / ( (double) headp -> ncall ) );
+               }
+           }
+       }
+       for ( memp = headp ; memp ; memp = memp -> cnext ) {
+           memp -> printflag = headp -> printflag;
+           memp -> propfraction = headp -> propfraction;
+       }
+    }
+}
diff --git a/gprof/dfn.c b/gprof/dfn.c
new file mode 100644 (file)
index 0000000..1d464be
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)dfn.c      5.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <stdio.h>
+#include "gprof.h"
+
+#define        DFN_DEPTH       100
+struct dfnstruct {
+    nltype     *nlentryp;
+    int                cycletop;
+};
+typedef struct dfnstruct       dfntype;
+
+dfntype        dfn_stack[ DFN_DEPTH ];
+int    dfn_depth = 0;
+
+int    dfn_counter = DFN_NAN;
+
+    /*
+     * given this parent, depth first number its children.
+     */
+dfn( parentp )
+    nltype     *parentp;
+{
+    arctype    *arcp;
+
+#   ifdef DEBUG
+       if ( debug & DFNDEBUG ) {
+           printf( "[dfn] dfn(" );
+           printname( parentp );
+           printf( ")\n" );
+       }
+#   endif DEBUG
+       /*
+        *      if we're already numbered, no need to look any furthur.
+        */
+    if ( dfn_numbered( parentp ) ) {
+       return;
+    }
+       /*
+        *      if we're already busy, must be a cycle
+        */
+    if ( dfn_busy( parentp ) ) {
+       dfn_findcycle( parentp );
+       return;
+    }
+       /*
+        *      visit yourself before your children
+        */
+    dfn_pre_visit( parentp );
+       /*
+        *      visit children
+        */
+    for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
+           dfn( arcp -> arc_childp );
+    }
+       /*
+        *      visit yourself after your children
+        */
+    dfn_post_visit( parentp );
+}
+
+    /*
+     * push a parent onto the stack and mark it busy
+     */
+dfn_pre_visit( parentp )
+    nltype     *parentp;
+{
+
+    dfn_depth += 1;
+    if ( dfn_depth >= DFN_DEPTH ) {
+       fprintf( stderr , "[dfn] out of my depth (dfn_stack overflow)\n" );
+       exit( 1 );
+    }
+    dfn_stack[ dfn_depth ].nlentryp = parentp;
+    dfn_stack[ dfn_depth ].cycletop = dfn_depth;
+    parentp -> toporder = DFN_BUSY;
+#   ifdef DEBUG
+       if ( debug & DFNDEBUG ) {
+           printf( "[dfn_pre_visit]\t\t%d:" , dfn_depth );
+           printname( parentp );
+           printf( "\n" );
+       }
+#   endif DEBUG
+}
+
+    /*
+     * are we already numbered?
+     */
+bool
+dfn_numbered( childp )
+    nltype     *childp;
+{
+    
+    return ( childp -> toporder != DFN_NAN && childp -> toporder != DFN_BUSY );
+}
+
+    /*
+     * are we already busy?
+     */
+bool
+dfn_busy( childp )
+    nltype     *childp;
+{
+
+    if ( childp -> toporder == DFN_NAN ) {
+       return FALSE;
+    }
+    return TRUE;
+}
+
+    /*
+     * MISSING: an explanation
+     */
+dfn_findcycle( childp )
+    nltype     *childp;
+{
+    int                cycletop;
+    nltype     *cycleheadp;
+    nltype     *tailp;
+    int                index;
+
+    for ( cycletop = dfn_depth ; cycletop > 0 ; cycletop -= 1 ) {
+       cycleheadp = dfn_stack[ cycletop ].nlentryp;
+       if ( childp == cycleheadp ) {
+           break;
+       }
+       if ( childp -> cyclehead != childp &&
+           childp -> cyclehead == cycleheadp ) {
+           break;
+       }
+    }
+    if ( cycletop <= 0 ) {
+       fprintf( stderr , "[dfn_findcycle] couldn't find head of cycle\n" );
+       exit( 1 );
+    }
+#   ifdef DEBUG
+       if ( debug & DFNDEBUG ) {
+           printf( "[dfn_findcycle] dfn_depth %d cycletop %d " ,
+                   dfn_depth , cycletop  );
+           printname( cycleheadp );
+           printf( "\n" );
+       }
+#   endif DEBUG
+    if ( cycletop == dfn_depth ) {
+           /*
+            *  this is previous function, e.g. this calls itself
+            *  sort of boring
+            */
+       dfn_self_cycle( childp );
+    } else {
+           /*
+            *  glom intervening functions that aren't already
+            *  glommed into this cycle.
+            *  things have been glommed when their cyclehead field
+            *  points to the head of the cycle they are glommed into.
+            */
+       for ( tailp = cycleheadp ; tailp -> cnext ; tailp = tailp -> cnext ) {
+           /* void: chase down to tail of things already glommed */
+#          ifdef DEBUG
+               if ( debug & DFNDEBUG ) {
+                   printf( "[dfn_findcycle] tail " );
+                   printname( tailp );
+                   printf( "\n" );
+               }
+#          endif DEBUG
+       }
+           /*
+            *  if what we think is the top of the cycle
+            *  has a cyclehead field, then it's not really the
+            *  head of the cycle, which is really what we want
+            */ 
+       if ( cycleheadp -> cyclehead != cycleheadp ) {
+           cycleheadp = cycleheadp -> cyclehead;
+#          ifdef DEBUG
+               if ( debug & DFNDEBUG ) {
+                   printf( "[dfn_findcycle] new cyclehead " );
+                   printname( cycleheadp );
+                   printf( "\n" );
+               }
+#          endif DEBUG
+       }
+       for ( index = cycletop + 1 ; index <= dfn_depth ; index += 1 ) {
+           childp = dfn_stack[ index ].nlentryp;
+           if ( childp -> cyclehead == childp ) {
+                   /*
+                    *  not yet glommed anywhere, glom it
+                    *  and fix any children it has glommed
+                    */
+               tailp -> cnext = childp;
+               childp -> cyclehead = cycleheadp;
+#              ifdef DEBUG
+                   if ( debug & DFNDEBUG ) {
+                       printf( "[dfn_findcycle] glomming " );
+                       printname( childp );
+                       printf( " onto " );
+                       printname( cycleheadp );
+                       printf( "\n" );
+                   }
+#              endif DEBUG
+               for ( tailp = childp ; tailp->cnext ; tailp = tailp->cnext ) {
+                   tailp -> cnext -> cyclehead = cycleheadp;
+#                  ifdef DEBUG
+                       if ( debug & DFNDEBUG ) {
+                           printf( "[dfn_findcycle] and its tail " );
+                           printname( tailp -> cnext );
+                           printf( " onto " );
+                           printname( cycleheadp );
+                           printf( "\n" );
+                       }
+#                  endif DEBUG
+               }
+           } else if ( childp -> cyclehead != cycleheadp /* firewall */ ) {
+               fprintf( stderr ,
+                       "[dfn_busy] glommed, but not to cyclehead\n" );
+           }
+       }
+    }
+}
+
+    /*
+     * deal with self-cycles
+     * for lint: ARGSUSED
+     */
+dfn_self_cycle( parentp )
+    nltype     *parentp;
+{
+       /*
+        *      since we are taking out self-cycles elsewhere
+        *      no need for the special case, here.
+        */
+#   ifdef DEBUG
+       if ( debug & DFNDEBUG ) {
+           printf( "[dfn_self_cycle] " );
+           printname( parentp );
+           printf( "\n" );
+       }
+#   endif DEBUG
+}
+
+    /*
+     * visit a node after all its children
+     * [MISSING: an explanation]
+     * and pop it off the stack
+     */
+dfn_post_visit( parentp )
+    nltype     *parentp;
+{
+    nltype     *memberp;
+
+#   ifdef DEBUG
+       if ( debug & DFNDEBUG ) {
+           printf( "[dfn_post_visit]\t%d: " , dfn_depth );
+           printname( parentp );
+           printf( "\n" );
+       }
+#   endif DEBUG
+       /*
+        *      number functions and things in their cycles
+        *      unless the function is itself part of a cycle
+        */
+    if ( parentp -> cyclehead == parentp ) {
+       dfn_counter += 1;
+       for ( memberp = parentp ; memberp ; memberp = memberp -> cnext ) {
+           memberp -> toporder = dfn_counter;
+#          ifdef DEBUG
+               if ( debug & DFNDEBUG ) {
+                   printf( "[dfn_post_visit]\t\tmember " );
+                   printname( memberp );
+                   printf( " -> toporder = %d\n" , dfn_counter );
+               }
+#          endif DEBUG
+       }
+    } else {
+#      ifdef DEBUG
+           if ( debug & DFNDEBUG ) {
+               printf( "[dfn_post_visit]\t\tis part of a cycle\n" );
+           }
+#      endif DEBUG
+    }
+    dfn_depth -= 1;
+}
diff --git a/gprof/gmon.h b/gprof/gmon.h
new file mode 100644 (file)
index 0000000..c89a721
--- /dev/null
@@ -0,0 +1,105 @@
+/*-
+ * 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.
+ *
+ *     @(#)gmon.h      5.2 (Berkeley) 5/6/91
+ */
+
+struct phdr {
+    char       *lpc;
+    char       *hpc;
+    int                ncnt;
+};
+
+    /*
+     * histogram counters are unsigned shorts (according to the kernel).
+     */
+#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;
+    long               count;
+    unsigned short     link;
+};
+
+    /*
+     * a raw arc,
+     *     with pointers to the calling site and the called site
+     *     and a count.
+     */
+struct rawarc {
+    unsigned long      raw_frompc;
+    unsigned long      raw_selfpc;
+    long               raw_count;
+};
+
+    /*
+     * general rounding functions.
+     */
+#define ROUNDDOWN(x,y) (((x)/(y))*(y))
+#define ROUNDUP(x,y)   ((((x)+(y)-1)/(y))*(y))
diff --git a/gprof/gprof.1 b/gprof/gprof.1
new file mode 100644 (file)
index 0000000..286a312
--- /dev/null
@@ -0,0 +1,264 @@
+.\" Copyright (c) 1983, 1990 The Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms are permitted provided
+.\" that: (1) source distributions retain this entire copyright notice and
+.\" comment, and (2) distributions including binaries display the following
+.\" acknowledgement:  ``This product includes software developed by the
+.\" University of California, Berkeley and its contributors'' in the
+.\" documentation or other materials provided with the distribution and in
+.\" all advertising materials mentioning features or use of this software.
+.\" 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+.\" WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+.\"
+.\"     @(#)gprof.1    6.6 (Berkeley) 7/24/90
+.\"
+.Dd July 24, 1990
+.Dt GPROF 1
+.Os BSD 4.2
+.Sh NAME
+.Nm gprof
+.Nd display call graph profile data
+.Sh SYNOPSIS
+.Nm gprof
+.Op options
+.Op Ar a.out Op Ar gmon.out ...
+.Sh DESCRIPTION
+.Nm gprof
+produces an execution profile of C, Pascal, or Fortran77 programs.
+The effect of called routines is incorporated in the profile of each caller.
+The profile data is taken from the call graph profile file
+.Pf \&( Pa gmon.out
+default) which is created by programs
+that are compiled with the
+.Fl pg
+option of
+.Xr cc 1 ,
+.Xr pc 1 ,
+and
+.Xr f77 1 .
+The
+.Fl pg
+option also links in versions of the library routines
+that are compiled for profiling.
+.Nm Gprof
+reads the given object file (the default is
+.Pa a.out)
+and establishes the relation between it's symbol table
+and the call graph profile from
+.Pa gmon.out .
+If more than one profile file is specified,
+the
+.Nm gprof
+output shows the sum of the profile information in the given profile files.
+.Pp
+.Nm Gprof
+calculates the amount of time spent in each routine.
+Next, these times are propagated along the edges of the call graph.
+Cycles are discovered, and calls into a cycle are made to share the time
+of the cycle.
+The first listing shows the functions
+sorted according to the time they represent
+including the time of their call graph descendents.
+Below each function entry is shown its (direct) call graph children,
+and how their times are propagated to this function.
+A similar display above the function shows how this function's time and the
+time of its descendents is propagated to its (direct) call graph parents.
+.Pp
+Cycles are also shown, with an entry for the cycle as a whole and
+a listing of the members of the cycle and their contributions to the
+time and call counts of the cycle.
+.Pp
+Second, a flat profile is given,
+similar to that provided by
+.Xr prof  1  .
+This listing gives the total execution times, the call counts,
+the time in milleseconds the call spent in the routine itself, and
+the time in milleseconds the call spent in the routine itself including
+its descendents.
+.Pp
+Finally, an index of the function names is provided.
+.Pp
+The following options are available:
+.Tw Fl
+.Tp Fl a
+suppresses the printing of statically declared functions.
+If this option is given, all relevant information about the static function
+(e.g., time samples, calls to other functions, calls from other functions)
+belongs to the function loaded just before the static function in the
+.Pa a.out
+file.
+.Tp Fl b
+suppresses the printing of a description of each field in the profile.
+.Tp Fl c
+the static call graph of the program is discovered by a heuristic
+that examines the text space of the object file.
+Static-only parents or children are shown
+with call counts of 0.
+.Tc Fl e
+.Ws
+.Ar name
+.Cx
+suppresses the printing of the graph profile entry for routine
+.Ar name
+and all its descendants
+(unless they have other ancestors that aren't suppressed).
+More than one
+.Fl e
+option may be given.
+Only one
+.Ar name
+may be given with each
+.Fl e
+option.
+.Tc Fl E
+.Ws
+.Ar name
+.Cx
+suppresses the printing of the graph profile entry for routine
+.Ar name
+(and its descendants) as
+.Fl e  ,
+above, and also excludes the time spent in
+.Ar name
+(and its descendants) from the total and percentage time computations.
+(For example,
+.Fl E
+.Ar mcount
+.Fl E
+.Ar mcleanup
+is the default.)
+.Tc Fl f
+.Ws
+.Ar name
+.Cx
+prints the graph profile entry of only the specified routine
+.Ar name
+and its descendants.
+More than one
+.Fl f
+option may be given.
+Only one
+.Ar name
+may be given with each
+.Fl f
+option.
+.Tc Fl F
+.Ws
+.Ar name
+.Cx
+prints the graph profile entry of only the routine
+.Ar name
+and its descendants (as
+.Fl f ,
+above) and also uses only the times of the printed routines
+in total time and percentage computations.
+More than one
+.Fl F
+option may be given.
+Only one
+.Ar name
+may be given with each
+.Fl F
+option.
+The
+.Fl F
+option
+overrides
+the
+.Fl E
+option.
+.Tc Fl k
+.Ws
+.Ar fromname
+.Ws
+.Ar toname
+.Cx
+will delete any arcs from routine
+.Ar fromname
+to routine
+.Ar toname  .
+This can be used to break undesired cycles.
+More than one
+.Fl k
+option may be given.
+Only one pair of routine names may be given with each
+.Fl k
+option.
+.Tp Fl s
+a profile file
+.Pa gmon.sum
+is produced that represents
+the sum of the profile information in all the specified profile files.
+This summary profile file may be given to later
+executions of gprof (probably also with a
+.Fl s  )
+to accumulate profile data across several runs of an
+.Pa a.out
+file.
+.Tp Fl z
+displays routines that have zero usage (as shown by call counts
+and accumulated time).
+This is useful with the
+.Fl c
+option for discovering which routines were never called.
+.Tp
+.Sh FILES
+.Dw gmon.sum
+.Di L
+.Dp Pa a.out
+the namelist and text space.
+.Dp Pa gmon.out
+dynamic call graph and profile.
+.Dp Pa gmon.sum
+summarized dynamic call graph and profile.
+.Dp
+.Sh SEE ALSO
+.Xr monitor 3 ,
+.Xr profil 2 ,
+.Xr cc 1 ,
+.Xr prof 1
+.br
+.Em An Execution Profiler for Modular Programs ,
+by
+S. Graham, P. Kessler, M. McKusick;
+Software  - Practice and Experience,
+Vol. 13, pp. 671-685, 1983.
+.br
+.Em gprof: A Call Graph Execution Profiler ,
+by S. Graham, P. Kessler, M. McKusick;
+Proceedings of the SIGPLAN '82 Symposium on Compiler Construction,
+SIGPLAN Notices, Vol. 17, No  6, pp. 120-126, June 1982.
+.Sh HISTORY
+.Nm Gprof
+appeared in 4.2 BSD.
+.Sh BUGS
+The granularity of the sampling is shown, but remains
+statistical at best.
+We assume that the time for each execution of a function
+can be expressed by the total time for the function divided
+by the number of times the function is called.
+Thus the time propagated along the call graph arcs to the function's
+parents is directly proportional to the number of times that
+arc is traversed.
+.Pp
+Parents that are not themselves profiled will have the time of
+their profiled children propagated to them, but they will appear
+to be spontaneously invoked in the call graph listing, and will
+not have their time propagated further.
+Similarly, signal catchers, even though profiled, will appear
+to be spontaneous (although for more obscure reasons).
+Any profiled children of signal catchers should have their times
+propagated properly, unless the signal catcher was invoked during
+the execution of the profiling routine, in which case all is lost.
+.Pp
+The profiled program must call
+.Xr exit  2
+or return normally for the profiling information to be saved
+in the
+.Pa gmon.out
+file.
diff --git a/gprof/gprof.c b/gprof/gprof.c
new file mode 100644 (file)
index 0000000..c1f0d08
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)gprof.c    5.6 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include "gprof.h"
+
+char   *whoami = "gprof";
+
+    /*
+     * things which get -E excluded by default.
+     */
+char   *defaultEs[] = { "mcount" , "__mcleanup" , 0 };
+
+main(argc, argv)
+    int argc;
+    char **argv;
+{
+    char       **sp;
+    nltype     **timesortnlp;
+
+    --argc;
+    argv++;
+    debug = 0;
+    bflag = TRUE;
+    while ( *argv != 0 && **argv == '-' ) {
+       (*argv)++;
+       switch ( **argv ) {
+       case 'a':
+           aflag = TRUE;
+           break;
+       case 'b':
+           bflag = FALSE;
+           break;
+       case 'c':
+           cflag = TRUE;
+           break;
+       case 'd':
+           dflag = TRUE;
+           (*argv)++;
+           debug |= atoi( *argv );
+           debug |= ANYDEBUG;
+#          ifdef DEBUG
+               printf("[main] debug = %d\n", debug);
+#          else not DEBUG
+               printf("%s: -d ignored\n", whoami);
+#          endif DEBUG
+           break;
+       case 'E':
+           ++argv;
+           addlist( Elist , *argv );
+           Eflag = TRUE;
+           addlist( elist , *argv );
+           eflag = TRUE;
+           break;
+       case 'e':
+           addlist( elist , *++argv );
+           eflag = TRUE;
+           break;
+       case 'F':
+           ++argv;
+           addlist( Flist , *argv );
+           Fflag = TRUE;
+           addlist( flist , *argv );
+           fflag = TRUE;
+           break;
+       case 'f':
+           addlist( flist , *++argv );
+           fflag = TRUE;
+           break;
+       case 'k':
+           addlist( kfromlist , *++argv );
+           addlist( ktolist , *++argv );
+           kflag = TRUE;
+           break;
+       case 's':
+           sflag = TRUE;
+           break;
+       case 'z':
+           zflag = TRUE;
+           break;
+       }
+       argv++;
+    }
+    if ( *argv != 0 ) {
+       a_outname  = *argv;
+       argv++;
+    } else {
+       a_outname  = A_OUTNAME;
+    }
+    if ( *argv != 0 ) {
+       gmonname = *argv;
+       argv++;
+    } else {
+       gmonname = GMONNAME;
+    }
+       /*
+        *      turn off default functions
+        */
+    for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
+       Eflag = TRUE;
+       addlist( Elist , *sp );
+       eflag = TRUE;
+       addlist( elist , *sp );
+    }
+       /*
+        *      how many ticks per second?
+        *      if we can't tell, report time in ticks.
+        */
+    hz = hertz();
+    if (hz == 0) {
+       hz = 1;
+       fprintf(stderr, "time is in ticks, not seconds\n");
+    }
+       /*
+        *      get information about a.out file.
+        */
+    getnfile();
+       /*
+        *      get information about mon.out file(s).
+        */
+    do {
+       getpfile( gmonname );
+       if ( *argv != 0 ) {
+           gmonname = *argv;
+       }
+    } while ( *argv++ != 0 );
+       /*
+        *      dump out a gmon.sum file if requested
+        */
+    if ( sflag ) {
+       dumpsum( GMONSUM );
+    }
+       /*
+        *      assign samples to procedures
+        */
+    asgnsamples();
+       /*
+        *      assemble the dynamic profile
+        */
+    timesortnlp = doarcs();
+       /*
+        *      print the dynamic profile
+        */
+    printgprof( timesortnlp ); 
+       /*
+        *      print the flat profile
+        */
+    printprof();       
+       /*
+        *      print the index
+        */
+    printindex();      
+    done();
+}
+
+    /*
+     * Set up string and symbol tables from a.out.
+     * and optionally the text space.
+     * On return symbol table is sorted by value.
+     */
+getnfile()
+{
+    FILE       *nfile;
+    int                valcmp();
+
+    nfile = fopen( a_outname ,"r");
+    if (nfile == NULL) {
+       perror( a_outname );
+       done();
+    }
+    fread(&xbuf, 1, sizeof(xbuf), nfile);
+    if (N_BADMAG(xbuf)) {
+       fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname );
+       done();
+    }
+    getstrtab(nfile);
+    getsymtab(nfile);
+    gettextspace( nfile );
+    qsort(nl, nname, sizeof(nltype), valcmp);
+    fclose(nfile);
+#   ifdef DEBUG
+       if ( debug & AOUTDEBUG ) {
+           register int j;
+
+           for (j = 0; j < nname; j++){
+               printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
+           }
+       }
+#   endif DEBUG
+}
+
+getstrtab(nfile)
+    FILE       *nfile;
+{
+
+    fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
+    if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
+       fprintf(stderr, "%s: %s: no string table (old format?)\n" ,
+               whoami , a_outname );
+       done();
+    }
+    strtab = (char *)calloc(ssiz, 1);
+    if (strtab == NULL) {
+       fprintf(stderr, "%s: %s: no room for %d bytes of string table",
+               whoami , a_outname , ssiz);
+       done();
+    }
+    if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
+       fprintf(stderr, "%s: %s: error reading string table\n",
+               whoami , a_outname );
+       done();
+    }
+}
+
+    /*
+     * Read in symbol table
+     */
+getsymtab(nfile)
+    FILE       *nfile;
+{
+    register long      i;
+    int                        askfor;
+    struct nlist       nbuf;
+
+    /* pass1 - count symbols */
+    fseek(nfile, (long)N_SYMOFF(xbuf), 0);
+    nname = 0;
+    for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
+       fread(&nbuf, sizeof(nbuf), 1, nfile);
+       if ( ! funcsymbol( &nbuf ) ) {
+           continue;
+       }
+       nname++;
+    }
+    if (nname == 0) {
+       fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname );
+       done();
+    }
+    askfor = nname + 1;
+    nl = (nltype *) calloc( askfor , sizeof(nltype) );
+    if (nl == 0) {
+       fprintf(stderr, "%s: No room for %d bytes of symbol table\n",
+               whoami, askfor * sizeof(nltype) );
+       done();
+    }
+
+    /* pass2 - read symbols */
+    fseek(nfile, (long)N_SYMOFF(xbuf), 0);
+    npe = nl;
+    nname = 0;
+    for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
+       fread(&nbuf, sizeof(nbuf), 1, nfile);
+       if ( ! funcsymbol( &nbuf ) ) {
+#          ifdef DEBUG
+               if ( debug & AOUTDEBUG ) {
+                   printf( "[getsymtab] rejecting: 0x%x %s\n" ,
+                           nbuf.n_type , strtab + nbuf.n_un.n_strx );
+               }
+#          endif DEBUG
+           continue;
+       }
+       npe->value = nbuf.n_value;
+       npe->name = strtab+nbuf.n_un.n_strx;
+#      ifdef DEBUG
+           if ( debug & AOUTDEBUG ) {
+               printf( "[getsymtab] %d %s 0x%08x\n" ,
+                       nname , npe -> name , npe -> value );
+           }
+#      endif DEBUG
+       npe++;
+       nname++;
+    }
+    npe->value = -1;
+}
+
+    /*
+     * read in the text space of an a.out file
+     */
+gettextspace( nfile )
+    FILE       *nfile;
+{
+    char       *malloc();
+    
+    if ( cflag == 0 ) {
+       return;
+    }
+    textspace = (u_char *) malloc( xbuf.a_text );
+    if ( textspace == 0 ) {
+       fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
+                       whoami , xbuf.a_text );
+       fprintf( stderr , "can't do -c\n" );
+       return;
+    }
+    (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
+    if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
+       fprintf( stderr , "%s: couldn't read text space:  " , whoami );
+       fprintf( stderr , "can't do -c\n" );
+       free( textspace );
+       textspace = 0;
+       return;
+    }
+}
+    /*
+     * information from a gmon.out file is in two parts:
+     * an array of sampling hits within pc ranges,
+     * and the arcs.
+     */
+getpfile(filename)
+    char *filename;
+{
+    FILE               *pfile;
+    FILE               *openpfile();
+    struct rawarc      arc;
+
+    pfile = openpfile(filename);
+    readsamples(pfile);
+       /*
+        *      the rest of the file consists of
+        *      a bunch of <from,self,count> tuples.
+        */
+    while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
+#      ifdef DEBUG
+           if ( debug & SAMPLEDEBUG ) {
+               printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
+                       arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
+           }
+#      endif DEBUG
+           /*
+            *  add this arc
+            */
+       tally( &arc );
+    }
+    fclose(pfile);
+}
+
+FILE *
+openpfile(filename)
+    char *filename;
+{
+    struct hdr tmp;
+    FILE       *pfile;
+
+    if((pfile = fopen(filename, "r")) == NULL) {
+       perror(filename);
+       done();
+    }
+    fread(&tmp, sizeof(struct hdr), 1, pfile);
+    if ( s_highpc != 0 && ( tmp.lowpc != h.lowpc ||
+        tmp.highpc != h.highpc || tmp.ncnt != h.ncnt ) ) {
+       fprintf(stderr, "%s: incompatible with first gmon file\n", filename);
+       done();
+    }
+    h = tmp;
+    s_lowpc = (unsigned long) h.lowpc;
+    s_highpc = (unsigned long) h.highpc;
+    lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
+    highpc = (unsigned long)h.highpc / sizeof(UNIT);
+    sampbytes = h.ncnt - sizeof(struct hdr);
+    nsamples = sampbytes / sizeof (UNIT);
+#   ifdef DEBUG
+       if ( debug & SAMPLEDEBUG ) {
+           printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
+               h.lowpc , h.highpc , h.ncnt );
+           printf( "[openpfile]   s_lowpc 0x%x   s_highpc 0x%x\n" ,
+               s_lowpc , s_highpc );
+           printf( "[openpfile]     lowpc 0x%x     highpc 0x%x\n" ,
+               lowpc , highpc );
+           printf( "[openpfile] sampbytes %d nsamples %d\n" ,
+               sampbytes , nsamples );
+       }
+#   endif DEBUG
+    return(pfile);
+}
+
+tally( rawp )
+    struct rawarc      *rawp;
+{
+    nltype             *parentp;
+    nltype             *childp;
+
+    parentp = nllookup( rawp -> raw_frompc );
+    childp = nllookup( rawp -> raw_selfpc );
+    if ( kflag
+        && onlist( kfromlist , parentp -> name )
+        && onlist( ktolist , childp -> name ) ) {
+       return;
+    }
+    childp -> ncall += rawp -> raw_count;
+#   ifdef DEBUG
+       if ( debug & TALLYDEBUG ) {
+           printf( "[tally] arc from %s to %s traversed %d times\n" ,
+                   parentp -> name , childp -> name , rawp -> raw_count );
+       }
+#   endif DEBUG
+    addarc( parentp , childp , rawp -> raw_count );
+}
+
+/*
+ * dump out the gmon.sum file
+ */
+dumpsum( sumfile )
+    char *sumfile;
+{
+    register nltype *nlp;
+    register arctype *arcp;
+    struct rawarc arc;
+    FILE *sfile;
+
+    if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) {
+       perror( sumfile );
+       done();
+    }
+    /*
+     * dump the header; use the last header read in
+     */
+    if ( fwrite( &h , sizeof h , 1 , sfile ) != 1 ) {
+       perror( sumfile );
+       done();
+    }
+    /*
+     * dump the samples
+     */
+    if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) {
+       perror( sumfile );
+       done();
+    }
+    /*
+     * dump the normalized raw arc information
+     */
+    for ( nlp = nl ; nlp < npe ; nlp++ ) {
+       for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
+           arc.raw_frompc = arcp -> arc_parentp -> value;
+           arc.raw_selfpc = arcp -> arc_childp -> value;
+           arc.raw_count = arcp -> arc_count;
+           if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) {
+               perror( sumfile );
+               done();
+           }
+#          ifdef DEBUG
+               if ( debug & SAMPLEDEBUG ) {
+                   printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" ,
+                           arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
+               }
+#          endif DEBUG
+       }
+    }
+    fclose( sfile );
+}
+
+valcmp(p1, p2)
+    nltype *p1, *p2;
+{
+    if ( p1 -> value < p2 -> value ) {
+       return LESSTHAN;
+    }
+    if ( p1 -> value > p2 -> value ) {
+       return GREATERTHAN;
+    }
+    return EQUALTO;
+}
+
+readsamples(pfile)
+    FILE       *pfile;
+{
+    register i;
+    UNIT       sample;
+    
+    if (samples == 0) {
+       samples = (UNIT *) calloc(sampbytes, sizeof (UNIT));
+       if (samples == 0) {
+           fprintf( stderr , "%s: No room for %d sample pc's\n", 
+               whoami , sampbytes / sizeof (UNIT));
+           done();
+       }
+    }
+    for (i = 0; i < nsamples; i++) {
+       fread(&sample, sizeof (UNIT), 1, pfile);
+       if (feof(pfile))
+               break;
+       samples[i] += sample;
+    }
+    if (i != nsamples) {
+       fprintf(stderr,
+           "%s: unexpected EOF after reading %d/%d samples\n",
+               whoami , --i , nsamples );
+       done();
+    }
+}
+
+/*
+ *     Assign samples to the procedures to which they belong.
+ *
+ *     There are three cases as to where pcl and pch can be
+ *     with respect to the routine entry addresses svalue0 and svalue1
+ *     as shown in the following diagram.  overlap computes the
+ *     distance between the arrows, the fraction of the sample
+ *     that is to be credited to the routine which starts at svalue0.
+ *
+ *         svalue0                                         svalue1
+ *            |                                               |
+ *            v                                               v
+ *
+ *            +-----------------------------------------------+
+ *            |                                               |
+ *       |  ->|    |<-         ->|         |<-         ->|    |<-  |
+ *       |         |             |         |             |         |
+ *       +---------+             +---------+             +---------+
+ *
+ *       ^         ^             ^         ^             ^         ^
+ *       |         |             |         |             |         |
+ *      pcl       pch           pcl       pch           pcl       pch
+ *
+ *     For the vax we assert that samples will never fall in the first
+ *     two bytes of any routine, since that is the entry mask,
+ *     thus we give call alignentries() to adjust the entry points if
+ *     the entry mask falls in one bucket but the code for the routine
+ *     doesn't start until the next bucket.  In conjunction with the
+ *     alignment of routine addresses, this should allow us to have
+ *     only one sample for every four bytes of text space and never
+ *     have any overlap (the two end cases, above).
+ */
+asgnsamples()
+{
+    register int       j;
+    UNIT               ccnt;
+    double             time;
+    unsigned long      pcl, pch;
+    register int       i;
+    unsigned long      overlap;
+    unsigned long      svalue0, svalue1;
+
+    /* read samples and assign to namelist symbols */
+    scale = highpc - lowpc;
+    scale /= nsamples;
+    alignentries();
+    for (i = 0, j = 1; i < nsamples; i++) {
+       ccnt = samples[i];
+       if (ccnt == 0)
+               continue;
+       pcl = lowpc + scale * i;
+       pch = lowpc + scale * (i + 1);
+       time = ccnt;
+#      ifdef DEBUG
+           if ( debug & SAMPLEDEBUG ) {
+               printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" ,
+                       pcl , pch , ccnt );
+           }
+#      endif DEBUG
+       totime += time;
+       for (j = j - 1; j < nname; j++) {
+           svalue0 = nl[j].svalue;
+           svalue1 = nl[j+1].svalue;
+               /*
+                *      if high end of tick is below entry address, 
+                *      go for next tick.
+                */
+           if (pch < svalue0)
+                   break;
+               /*
+                *      if low end of tick into next routine,
+                *      go for next routine.
+                */
+           if (pcl >= svalue1)
+                   continue;
+           overlap = min(pch, svalue1) - max(pcl, svalue0);
+           if (overlap > 0) {
+#              ifdef DEBUG
+                   if (debug & SAMPLEDEBUG) {
+                       printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n",
+                               nl[j].value/sizeof(UNIT), svalue0, svalue1,
+                               nl[j].name, 
+                               overlap * time / scale, overlap);
+                   }
+#              endif DEBUG
+               nl[j].time += overlap * time / scale;
+           }
+       }
+    }
+#   ifdef DEBUG
+       if (debug & SAMPLEDEBUG) {
+           printf("[asgnsamples] totime %f\n", totime);
+       }
+#   endif DEBUG
+}
+
+
+unsigned long
+min(a, b)
+    unsigned long a,b;
+{
+    if (a<b)
+       return(a);
+    return(b);
+}
+
+unsigned long
+max(a, b)
+    unsigned long a,b;
+{
+    if (a>b)
+       return(a);
+    return(b);
+}
+
+    /*
+     * calculate scaled entry point addresses (to save time in asgnsamples),
+     * and possibly push the scaled entry points over the entry mask,
+     * if it turns out that the entry point is in one bucket and the code
+     * for a routine is in the next bucket.
+     */
+alignentries()
+{
+    register struct nl *nlp;
+    unsigned long      bucket_of_entry;
+    unsigned long      bucket_of_code;
+
+    for (nlp = nl; nlp < npe; nlp++) {
+       nlp -> svalue = nlp -> value / sizeof(UNIT);
+       bucket_of_entry = (nlp->svalue - lowpc) / scale;
+       bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
+       if (bucket_of_entry < bucket_of_code) {
+#          ifdef DEBUG
+               if (debug & SAMPLEDEBUG) {
+                   printf("[alignentries] pushing svalue 0x%x to 0x%x\n",
+                           nlp->svalue, nlp->svalue + UNITS_TO_CODE);
+               }
+#          endif DEBUG
+           nlp->svalue += UNITS_TO_CODE;
+       }
+    }
+}
+
+bool
+funcsymbol( nlistp )
+    struct nlist       *nlistp;
+{
+    extern char        *strtab;        /* string table from a.out */
+    extern int aflag;          /* if static functions aren't desired */
+    char       *name;
+
+       /*
+        *      must be a text symbol,
+        *      and static text symbols don't qualify if aflag set.
+        */
+    if ( ! (  ( nlistp -> n_type == ( N_TEXT | N_EXT ) )
+          || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) {
+       return FALSE;
+    }
+       /*
+        *      can't have any `funny' characters in name,
+        *      where `funny' includes  `.', .o file names
+        *                      and     `$', pascal labels.
+        */
+    for ( name = strtab + nlistp -> n_un.n_strx ; *name ; name += 1 ) {
+       if ( *name == '.' || *name == '$' ) {
+           return FALSE;
+       }
+    }
+    return TRUE;
+}
+
+done()
+{
+
+    exit(0);
+}
diff --git a/gprof/gprof.callg b/gprof/gprof.callg
new file mode 100644 (file)
index 0000000..533c96c
--- /dev/null
@@ -0,0 +1,108 @@
+
+
+
+call graph profile:
+          The sum of self and descendents is the major sort
+          for this listing.
+
+          function entries:
+
+index     the index of the function in the call graph
+          listing, as an aid to locating it (see below).
+
+%time     the percentage of the total time of the program
+          accounted for by this function and its
+          descendents.
+
+self      the number of seconds spent in this function
+          itself.
+
+descendents
+          the number of seconds spent in the descendents of
+          this function on behalf of this function.
+
+called    the number of times this function is called (other
+          than recursive calls).
+
+self      the number of times this function calls itself
+          recursively.
+
+name      the name of the function, with an indication of
+          its membership in a cycle, if any.
+
+index     the index of the function in the call graph
+          listing, as an aid to locating it.
+
+
+
+          parent listings:
+
+self*     the number of seconds of this function's self time
+          which is due to calls from this parent.
+
+descendents*
+          the number of seconds of this function's
+          descendent time which is due to calls from this
+          parent.
+
+called**  the number of times this function is called by
+          this parent.  This is the numerator of the
+          fraction which divides up the function's time to
+          its parents.
+
+total*    the number of times this function was called by
+          all of its parents.  This is the denominator of
+          the propagation fraction.
+
+parents   the name of this parent, with an indication of the
+          parent's membership in a cycle, if any.
+
+index     the index of this parent in the call graph
+          listing, as an aid in locating it.
+
+
+
+          children listings:
+
+self*     the number of seconds of this child's self time
+          which is due to being called by this function.
+
+descendent*
+          the number of seconds of this child's descendent's
+          time which is due to being called by this
+          function.
+
+called**  the number of times this child is called by this
+          function.  This is the numerator of the
+          propagation fraction for this child.
+
+total*    the number of times this child is called by all
+          functions.  This is the denominator of the
+          propagation fraction.
+
+children  the name of this child, and an indication of its
+          membership in a cycle, if any.
+
+index     the index of this child in the call graph listing,
+          as an aid to locating it.
+
+
+
+          * these fields are omitted for parents (or
+          children) in the same cycle as the function.  If
+          the function (or child) is a member of a cycle,
+          the propagated times and propagation denominator
+          represent the self time and descendent time of the
+          cycle as a whole.
+
+          ** static-only parents and children are indicated
+          by a call count of 0.
+
+
+
+          cycle listings:
+          the cycle as a whole is listed with the same
+          fields as a function entry.  Below it are listed
+          the members of the cycle, and their contributions
+          to the time and call counts of the cycle.
+\f
diff --git a/gprof/gprof.flat b/gprof/gprof.flat
new file mode 100644 (file)
index 0000000..60999a3
--- /dev/null
@@ -0,0 +1,32 @@
+
+
+
+flat profile:
+
+ %         the percentage of the total running time of the
+time       program used by this function.
+
+cumulative a running sum of the number of seconds accounted
+ seconds   for by this function and those listed above it.
+
+ self      the number of seconds accounted for by this
+seconds    function alone.  This is the major sort for this
+           listing.
+
+calls      the number of times this function was invoked, if
+           this function is profiled, else blank.
+ self      the average number of milliseconds spent in this
+ms/call    function per call, if this function is profiled,
+          else blank.
+
+ total     the average number of milliseconds spent in this
+ms/call    function and its descendents per call, if this 
+          function is profiled, else blank.
+
+name       the name of the function.  This is the minor sort
+           for this listing. The index shows the location of
+          the function in the gprof listing. If the index is
+          in parenthesis it shows where it would appear in
+          the gprof listing if it were to be printed.
+\f
diff --git a/gprof/gprof.h b/gprof/gprof.h
new file mode 100644 (file)
index 0000000..6edec28
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)gprof.h     5.9 (Berkeley) 6/1/90
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <a.out.h>
+#include <stdio.h>
+#include "gmon.h"
+
+#ifdef MACHINE_H
+#      include MACHINE_H
+#else
+#      if vax
+#         include "vax.h"
+#      endif
+#      if sun
+#              include "sun.h"
+#      endif
+#      if tahoe
+#              include "tahoe.h"
+#      endif
+#endif
+
+
+    /*
+     * who am i, for error messages.
+     */
+char   *whoami;
+
+    /*
+     * booleans
+     */
+typedef int    bool;
+#define        FALSE   0
+#define        TRUE    1
+
+    /*
+     * ticks per second
+     */
+long   hz;
+
+typedef        u_short UNIT;           /* unit of profiling */
+char   *a_outname;
+#define        A_OUTNAME               "a.out"
+
+char   *gmonname;
+#define        GMONNAME                "gmon.out"
+#define        GMONSUM                 "gmon.sum"
+
+    /*
+     * a constructed arc,
+     *     with pointers to the namelist entry of the parent and the child,
+     *     a count of how many times this arc was traversed,
+     *     and pointers to the next parent of this child and
+     *         the next child of this parent.
+     */
+struct arcstruct {
+    struct nl          *arc_parentp;   /* pointer to parent's nl entry */
+    struct nl          *arc_childp;    /* pointer to child's nl entry */
+    long               arc_count;      /* how calls from parent to child */
+    double             arc_time;       /* time inherited along arc */
+    double             arc_childtime;  /* childtime inherited along arc */
+    struct arcstruct   *arc_parentlist; /* parents-of-this-child list */
+    struct arcstruct   *arc_childlist; /* children-of-this-parent list */
+};
+typedef struct arcstruct       arctype;
+
+    /*
+     * The symbol table;
+     * for each external in the specified file we gather
+     * its address, the number of calls and compute its share of cpu time.
+     */
+struct nl {
+    char               *name;          /* the name */
+    unsigned long      value;          /* the pc entry point */
+    unsigned long      svalue;         /* entry point aligned to histograms */
+    double             time;           /* ticks in this routine */
+    double             childtime;      /* cumulative ticks in children */
+    long               ncall;          /* how many times called */
+    long               selfcalls;      /* how many calls to self */
+    double             propfraction;   /* what % of time propagates */
+    double             propself;       /* how much self time propagates */
+    double             propchild;      /* how much child time propagates */
+    bool               printflag;      /* should this be printed? */
+    int                        index;          /* index in the graph list */
+    int                        toporder;       /* graph call chain top-sort order */
+    int                        cycleno;        /* internal number of cycle on */
+    struct nl          *cyclehead;     /* pointer to head of cycle */
+    struct nl          *cnext;         /* pointer to next member of cycle */
+    arctype            *parents;       /* list of caller arcs */
+    arctype            *children;      /* list of callee arcs */
+};
+typedef struct nl      nltype;
+
+nltype *nl;                    /* the whole namelist */
+nltype *npe;                   /* the virtual end of the namelist */
+int    nname;                  /* the number of function names */
+
+    /*
+     * flag which marks a nl entry as topologically ``busy''
+     * flag which marks a nl entry as topologically ``not_numbered''
+     */
+#define        DFN_BUSY        -1
+#define        DFN_NAN         0
+
+    /* 
+     * namelist entries for cycle headers.
+     * the number of discovered cycles.
+     */
+nltype *cyclenl;               /* cycle header namelist */
+int    ncycle;                 /* number of cycles discovered */
+
+    /*
+     * The header on the gmon.out file.
+     * gmon.out consists of one of these headers,
+     * and then an array of ncnt samples
+     * representing the discretized program counter values.
+     * this should be a struct phdr, but since everything is done
+     * as UNITs, this is in UNITs too.
+     */
+struct hdr {
+    UNIT       *lowpc;
+    UNIT       *highpc;
+    int        ncnt;
+};
+
+struct hdr     h;
+
+int    debug;
+
+    /*
+     * Each discretized pc sample has
+     * a count of the number of samples in its range
+     */
+UNIT   *samples;
+
+unsigned long  s_lowpc;        /* lowpc from the profile file */
+unsigned long  s_highpc;       /* highpc from the profile file */
+unsigned lowpc, highpc;                /* range profiled, in UNIT's */
+unsigned sampbytes;            /* number of bytes of samples */
+int    nsamples;               /* number of samples */
+double actime;                 /* accumulated time thus far for putprofline */
+double totime;                 /* total time for all routines */
+double printtime;              /* total of time being printed */
+double scale;                  /* scale factor converting samples to pc
+                                  values: each sample covers scale bytes */
+char   *strtab;                /* string table in core */
+off_t  ssiz;                   /* size of the string table */
+struct exec xbuf;              /* exec header of a.out */
+unsigned char  *textspace;             /* text space of a.out in core */
+
+    /*
+     * option flags, from a to z.
+     */
+bool   aflag;                          /* suppress static functions */
+bool   bflag;                          /* blurbs, too */
+bool   cflag;                          /* discovered call graph, too */
+bool   dflag;                          /* debugging options */
+bool   eflag;                          /* specific functions excluded */
+bool   Eflag;                          /* functions excluded with time */
+bool   fflag;                          /* specific functions requested */
+bool   Fflag;                          /* functions requested with time */
+bool   kflag;                          /* arcs to be deleted */
+bool   sflag;                          /* sum multiple gmon.out files */
+bool   zflag;                          /* zero time/called functions, too */
+
+    /*
+     * structure for various string lists
+     */
+struct stringlist {
+    struct stringlist  *next;
+    char               *string;
+};
+struct stringlist      *elist;
+struct stringlist      *Elist;
+struct stringlist      *flist;
+struct stringlist      *Flist;
+struct stringlist      *kfromlist;
+struct stringlist      *ktolist;
+
+    /*
+     * function declarations
+     */
+/*
+               addarc();
+*/
+int            arccmp();
+arctype                *arclookup();
+/*
+               asgnsamples();
+               printblurb();
+               cyclelink();
+               dfn();
+*/
+bool           dfn_busy();
+/*
+               dfn_findcycle();
+*/
+bool           dfn_numbered();
+/*
+               dfn_post_visit();
+               dfn_pre_visit();
+               dfn_self_cycle();
+*/
+nltype         **doarcs();
+/*
+               done();
+               findcalls();
+               flatprofheader();
+               flatprofline();
+*/
+bool           funcsymbol();
+/*
+               getnfile();
+               getpfile();
+               getstrtab();
+               getsymtab();
+               gettextspace();
+               gprofheader();
+               gprofline();
+               main();
+*/
+unsigned long  max();
+int            membercmp();
+unsigned long  min();
+nltype         *nllookup();
+FILE           *openpfile();
+/*
+               printchildren();
+               printcycle();
+               printgprof();
+               printmembers();
+               printname();
+               printparents();
+               printprof();
+               readsamples();
+*/
+unsigned long  reladdr();
+/*
+               sortchildren();
+               sortmembers();
+               sortparents();
+               tally();
+               timecmp();
+               topcmp();
+*/
+int            totalcmp();
+/*
+               valcmp();
+*/
+
+#define        LESSTHAN        -1
+#define        EQUALTO         0
+#define        GREATERTHAN     1
+
+#define        DFNDEBUG        1
+#define        CYCLEDEBUG      2
+#define        ARCDEBUG        4
+#define        TALLYDEBUG      8
+#define        TIMEDEBUG       16
+#define        SAMPLEDEBUG     32
+#define        AOUTDEBUG       64
+#define        CALLDEBUG       128
+#define        LOOKUPDEBUG     256
+#define        PROPDEBUG       512
+#define        ANYDEBUG        1024
diff --git a/gprof/hertz.c b/gprof/hertz.c
new file mode 100644 (file)
index 0000000..1c2927f
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)hertz.c    5.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include <sys/time.h>
+
+    /*
+     * discover the tick frequency of the machine
+     * if something goes wrong, we return 0, an impossible hertz.
+     */
+#define        HZ_WRONG        0
+
+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(HZ_WRONG);
+       return (1000000 / tim.it_interval.tv_usec);
+}
diff --git a/gprof/lookup.c b/gprof/lookup.c
new file mode 100644 (file)
index 0000000..405f320
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)lookup.c   5.4 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include "gprof.h"
+
+    /*
+     * look up an address in a sorted-by-address namelist
+     *     this deals with misses by mapping them to the next lower 
+     *     entry point.
+     */
+nltype *
+nllookup( address )
+    unsigned long      address;
+{
+    register long      low;
+    register long      middle;
+    register long      high;
+#   ifdef DEBUG
+       register int    probes;
+
+       probes = 0;
+#   endif DEBUG
+    for ( low = 0 , high = nname - 1 ; low != high ; ) {
+#      ifdef DEBUG
+           probes += 1;
+#      endif DEBUG
+       middle = ( high + low ) >> 1;
+       if ( nl[ middle ].value <= address && nl[ middle+1 ].value > address ) {
+#          ifdef DEBUG
+               if ( debug & LOOKUPDEBUG ) {
+                   printf( "[nllookup] %d (%d) probes\n" , probes , nname-1 );
+               }
+#          endif DEBUG
+           return &nl[ middle ];
+       }
+       if ( nl[ middle ].value > address ) {
+           high = middle;
+       } else {
+           low = middle + 1;
+       }
+    }
+    fprintf( stderr , "[nllookup] binary search fails???\n" );
+    return 0;
+}
+
+arctype *
+arclookup( parentp , childp )
+    nltype     *parentp;
+    nltype     *childp;
+{
+    arctype    *arcp;
+
+    if ( parentp == 0 || childp == 0 ) {
+       fprintf( "[arclookup] parentp == 0 || childp == 0\n" );
+       return 0;
+    }
+#   ifdef DEBUG
+       if ( debug & LOOKUPDEBUG ) {
+           printf( "[arclookup] parent %s child %s\n" ,
+                   parentp -> name , childp -> name );
+       }
+#   endif DEBUG
+    for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
+#      ifdef DEBUG
+           if ( debug & LOOKUPDEBUG ) {
+               printf( "[arclookup]\t arc_parent %s arc_child %s\n" ,
+                       arcp -> arc_parentp -> name ,
+                       arcp -> arc_childp -> name );
+           }
+#      endif DEBUG
+       if ( arcp -> arc_childp == childp ) {
+           return arcp;
+       }
+    }
+    return 0;
+}
diff --git a/gprof/pathnames.h b/gprof/pathnames.h
new file mode 100755 (executable)
index 0000000..729325c
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)pathnames.h 5.2 (Berkeley) 6/1/90
+ */
+
+#define        _PATH_FLAT_BLURB        "/usr/share/misc/gprof.flat"
+#define        _PATH_CALLG_BLURB       "/usr/share/misc/gprof.callg"
+
diff --git a/gprof/printgprof.c b/gprof/printgprof.c
new file mode 100644 (file)
index 0000000..ce78852
--- /dev/null
@@ -0,0 +1,704 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)printgprof.c       5.7 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include "gprof.h"
+#include "pathnames.h"
+
+printprof()
+{
+    register nltype    *np;
+    nltype             **sortednlp;
+    int                        index, timecmp();
+
+    actime = 0.0;
+    printf( "\f\n" );
+    flatprofheader();
+       /*
+        *      Sort the symbol table in by time
+        */
+    sortednlp = (nltype **) calloc( nname , sizeof(nltype *) );
+    if ( sortednlp == (nltype **) 0 ) {
+       fprintf( stderr , "[printprof] ran out of memory for time sorting\n" );
+    }
+    for ( index = 0 ; index < nname ; index += 1 ) {
+       sortednlp[ index ] = &nl[ index ];
+    }
+    qsort( sortednlp , nname , sizeof(nltype *) , timecmp );
+    for ( index = 0 ; index < nname ; index += 1 ) {
+       np = sortednlp[ index ];
+       flatprofline( np );
+    }
+    actime = 0.0;
+    cfree( sortednlp );
+}
+
+timecmp( npp1 , npp2 )
+    nltype **npp1, **npp2;
+{
+    double     timediff;
+    long       calldiff;
+
+    timediff = (*npp2) -> time - (*npp1) -> time;
+    if ( timediff > 0.0 )
+       return 1 ;
+    if ( timediff < 0.0 )
+       return -1;
+    calldiff = (*npp2) -> ncall - (*npp1) -> ncall;
+    if ( calldiff > 0 )
+       return 1;
+    if ( calldiff < 0 )
+       return -1;
+    return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
+}
+
+    /*
+     * header for flatprofline
+     */
+flatprofheader()
+{
+    
+    if ( bflag ) {
+       printblurb( _PATH_FLAT_BLURB );
+    }
+    printf( "\ngranularity: each sample hit covers %d byte(s)" ,
+           (long) scale * sizeof(UNIT) );
+    if ( totime > 0.0 ) {
+       printf( " for %.2f%% of %.2f seconds\n\n" ,
+               100.0/totime , totime / hz );
+    } else {
+       printf( " no time accumulated\n\n" );
+           /*
+            *  this doesn't hurt sinc eall the numerators will be zero.
+            */
+       totime = 1.0;
+    }
+    printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n" ,
+           "%  " , "cumulative" , "self  " , "" , "self  " , "total " , "" );
+    printf( "%5.5s %10.10s %8.8s %8.8s %8.8s %8.8s  %-8.8s\n" ,
+           "time" , "seconds " , "seconds" , "calls" ,
+           "ms/call" , "ms/call" , "name" );
+}
+
+flatprofline( np )
+    register nltype    *np;
+{
+
+    if ( zflag == 0 && np -> ncall == 0 && np -> time == 0 ) {
+       return;
+    }
+    actime += np -> time;
+    printf( "%5.1f %10.2f %8.2f" ,
+       100 * np -> time / totime , actime / hz , np -> time / hz );
+    if ( np -> ncall != 0 ) {
+       printf( " %8d %8.2f %8.2f  " , np -> ncall ,
+           1000 * np -> time / hz / np -> ncall ,
+           1000 * ( np -> time + np -> childtime ) / hz / np -> ncall );
+    } else {
+       printf( " %8.8s %8.8s %8.8s  " , "" , "" , "" );
+    }
+    printname( np );
+    printf( "\n" );
+}
+
+gprofheader()
+{
+
+    if ( bflag ) {
+       printblurb( _PATH_CALLG_BLURB );
+    }
+    printf( "\ngranularity: each sample hit covers %d byte(s)" ,
+           (long) scale * sizeof(UNIT) );
+    if ( printtime > 0.0 ) {
+       printf( " for %.2f%% of %.2f seconds\n\n" ,
+               100.0/printtime , printtime / hz );
+    } else {
+       printf( " no time propagated\n\n" );
+           /*
+            *  this doesn't hurt, since all the numerators will be 0.0
+            */
+       printtime = 1.0;
+    }
+    printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
+       "" , "" , "" , "" , "called" , "total" , "parents");
+    printf( "%-6.6s %5.5s %7.7s %11.11s %7.7s+%-7.7s %-8.8s\t%5.5s\n" ,
+       "index" , "%time" , "self" , "descendents" ,
+       "called" , "self" , "name" , "index" );
+    printf( "%6.6s %5.5s %7.7s %11.11s %7.7s/%-7.7s     %-8.8s\n" ,
+       "" , "" , "" , "" , "called" , "total" , "children");
+    printf( "\n" );
+}
+
+gprofline( np )
+    register nltype    *np;
+{
+    char       kirkbuffer[ BUFSIZ ];
+
+    sprintf( kirkbuffer , "[%d]" , np -> index );
+    printf( "%-6.6s %5.1f %7.2f %11.2f" ,
+           kirkbuffer ,
+           100 * ( np -> propself + np -> propchild ) / printtime ,
+           np -> propself / hz ,
+           np -> propchild / hz );
+    if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
+       printf( " %7d" , np -> ncall );
+       if ( np -> selfcalls != 0 ) {
+           printf( "+%-7d " , np -> selfcalls );
+       } else {
+           printf( " %7.7s " , "" );
+       }
+    } else {
+       printf( " %7.7s %7.7s " , "" , "" );
+    }
+    printname( np );
+    printf( "\n" );
+}
+
+printgprof(timesortnlp)
+    nltype     **timesortnlp;
+{
+    int                index;
+    nltype     *parentp;
+
+       /*
+        *      Print out the structured profiling list
+        */
+    gprofheader();
+    for ( index = 0 ; index < nname + ncycle ; index ++ ) {
+       parentp = timesortnlp[ index ];
+       if ( zflag == 0 &&
+            parentp -> ncall == 0 &&
+            parentp -> selfcalls == 0 &&
+            parentp -> propself == 0 &&
+            parentp -> propchild == 0 ) {
+           continue;
+       }
+       if ( ! parentp -> printflag ) {
+           continue;
+       }
+       if ( parentp -> name == 0 && parentp -> cycleno != 0 ) {
+               /*
+                *      cycle header
+                */
+           printcycle( parentp );
+           printmembers( parentp );
+       } else {
+           printparents( parentp );
+           gprofline( parentp );
+           printchildren( parentp );
+       }
+       printf( "\n" );
+       printf( "-----------------------------------------------\n" );
+       printf( "\n" );
+    }
+    cfree( timesortnlp );
+}
+
+    /*
+     * sort by decreasing propagated time
+     * if times are equal, but one is a cycle header,
+     *         say that's first (e.g. less, i.e. -1).
+     * if one's name doesn't have an underscore and the other does,
+     *         say the one is first.
+     * all else being equal, sort by names.
+     */
+int
+totalcmp( npp1 , npp2 )
+    nltype     **npp1;
+    nltype     **npp2;
+{
+    register nltype    *np1 = *npp1;
+    register nltype    *np2 = *npp2;
+    double             diff;
+
+    diff =    ( np1 -> propself + np1 -> propchild )
+           - ( np2 -> propself + np2 -> propchild );
+    if ( diff < 0.0 )
+           return 1;
+    if ( diff > 0.0 )
+           return -1;
+    if ( np1 -> name == 0 && np1 -> cycleno != 0 ) 
+       return -1;
+    if ( np2 -> name == 0 && np2 -> cycleno != 0 )
+       return 1;
+    if ( np1 -> name == 0 )
+       return -1;
+    if ( np2 -> name == 0 )
+       return 1;
+    if ( *(np1 -> name) != '_' && *(np2 -> name) == '_' )
+       return -1;
+    if ( *(np1 -> name) == '_' && *(np2 -> name) != '_' )
+       return 1;
+    if ( np1 -> ncall > np2 -> ncall )
+       return -1;
+    if ( np1 -> ncall < np2 -> ncall ) 
+       return 1;
+    return strcmp( np1 -> name , np2 -> name );
+}
+
+printparents( childp )
+    nltype     *childp;
+{
+    nltype     *parentp;
+    arctype    *arcp;
+    nltype     *cycleheadp;
+
+    if ( childp -> cyclehead != 0 ) {
+       cycleheadp = childp -> cyclehead;
+    } else {
+       cycleheadp = childp;
+    }
+    if ( childp -> parents == 0 ) {
+       printf( "%6.6s %5.5s %7.7s %11.11s %7.7s %7.7s     <spontaneous>\n" ,
+               "" , "" , "" , "" , "" , "" );
+       return;
+    }
+    sortparents( childp );
+    for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
+       parentp = arcp -> arc_parentp;
+       if ( childp == parentp ||
+            ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
+               /*
+                *      selfcall or call among siblings
+                */
+           printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s     " ,
+                   "" , "" , "" , "" ,
+                   arcp -> arc_count , "" );
+           printname( parentp );
+           printf( "\n" );
+       } else {
+               /*
+                *      regular parent of child
+                */
+           printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
+                   "" , "" ,
+                   arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
+                   arcp -> arc_count , cycleheadp -> ncall );
+           printname( parentp );
+           printf( "\n" );
+       }
+    }
+}
+
+printchildren( parentp )
+    nltype     *parentp;
+{
+    nltype     *childp;
+    arctype    *arcp;
+
+    sortchildren( parentp );
+    arcp = parentp -> children;
+    for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
+       childp = arcp -> arc_childp;
+       if ( childp == parentp ||
+           ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
+               /*
+                *      self call or call to sibling
+                */
+           printf( "%6.6s %5.5s %7.7s %11.11s %7d %7.7s     " ,
+                   "" , "" , "" , "" , arcp -> arc_count , "" );
+           printname( childp );
+           printf( "\n" );
+       } else {
+               /*
+                *      regular child of parent
+                */
+           printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
+                   "" , "" ,
+                   arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
+                   arcp -> arc_count , childp -> cyclehead -> ncall );
+           printname( childp );
+           printf( "\n" );
+       }
+    }
+}
+
+printname( selfp )
+    nltype     *selfp;
+{
+
+    if ( selfp -> name != 0 ) {
+       printf( "%s" , selfp -> name );
+#      ifdef DEBUG
+           if ( debug & DFNDEBUG ) {
+               printf( "{%d} " , selfp -> toporder );
+           }
+           if ( debug & PROPDEBUG ) {
+               printf( "%5.2f%% " , selfp -> propfraction );
+           }
+#      endif DEBUG
+    }
+    if ( selfp -> cycleno != 0 ) {
+       printf( " <cycle %d>" , selfp -> cycleno );
+    }
+    if ( selfp -> index != 0 ) {
+       if ( selfp -> printflag ) {
+           printf( " [%d]" , selfp -> index );
+       } else {
+           printf( " (%d)" , selfp -> index );
+       }
+    }
+}
+
+sortchildren( parentp )
+    nltype     *parentp;
+{
+    arctype    *arcp;
+    arctype    *detachedp;
+    arctype    sorted;
+    arctype    *prevp;
+
+       /*
+        *      unlink children from parent,
+        *      then insertion sort back on to sorted's children.
+        *          *arcp       the arc you have detached and are inserting.
+        *          *detachedp  the rest of the arcs to be sorted.
+        *          sorted      arc list onto which you insertion sort.
+        *          *prevp      arc before the arc you are comparing.
+        */
+    sorted.arc_childlist = 0;
+    for (  (arcp = parentp -> children)&&(detachedp = arcp -> arc_childlist);
+           arcp ;
+          (arcp = detachedp)&&(detachedp = detachedp -> arc_childlist)) {
+           /*
+            *  consider *arcp as disconnected
+            *  insert it into sorted
+            */
+       for (   prevp = &sorted ;
+               prevp -> arc_childlist ;
+               prevp = prevp -> arc_childlist ) {
+           if ( arccmp( arcp , prevp -> arc_childlist ) != LESSTHAN ) {
+               break;
+           }
+       }
+       arcp -> arc_childlist = prevp -> arc_childlist;
+       prevp -> arc_childlist = arcp;
+    }
+       /*
+        *      reattach sorted children to parent
+        */
+    parentp -> children = sorted.arc_childlist;
+}
+
+sortparents( childp )
+    nltype     *childp;
+{
+    arctype    *arcp;
+    arctype    *detachedp;
+    arctype    sorted;
+    arctype    *prevp;
+
+       /*
+        *      unlink parents from child,
+        *      then insertion sort back on to sorted's parents.
+        *          *arcp       the arc you have detached and are inserting.
+        *          *detachedp  the rest of the arcs to be sorted.
+        *          sorted      arc list onto which you insertion sort.
+        *          *prevp      arc before the arc you are comparing.
+        */
+    sorted.arc_parentlist = 0;
+    for (  (arcp = childp -> parents)&&(detachedp = arcp -> arc_parentlist);
+           arcp ;
+          (arcp = detachedp)&&(detachedp = detachedp -> arc_parentlist)) {
+           /*
+            *  consider *arcp as disconnected
+            *  insert it into sorted
+            */
+       for (   prevp = &sorted ;
+               prevp -> arc_parentlist ;
+               prevp = prevp -> arc_parentlist ) {
+           if ( arccmp( arcp , prevp -> arc_parentlist ) != GREATERTHAN ) {
+               break;
+           }
+       }
+       arcp -> arc_parentlist = prevp -> arc_parentlist;
+       prevp -> arc_parentlist = arcp;
+    }
+       /*
+        *      reattach sorted arcs to child
+        */
+    childp -> parents = sorted.arc_parentlist;
+}
+
+    /*
+     * print a cycle header
+     */
+printcycle( cyclep )
+    nltype     *cyclep;
+{
+    char       kirkbuffer[ BUFSIZ ];
+
+    sprintf( kirkbuffer , "[%d]" , cyclep -> index );
+    printf( "%-6.6s %5.1f %7.2f %11.2f %7d" ,
+           kirkbuffer ,
+           100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
+           cyclep -> propself / hz ,
+           cyclep -> propchild / hz ,
+           cyclep -> ncall );
+    if ( cyclep -> selfcalls != 0 ) {
+       printf( "+%-7d" , cyclep -> selfcalls );
+    } else {
+       printf( " %7.7s" , "" );
+    }
+    printf( " <cycle %d as a whole>\t[%d]\n" ,
+           cyclep -> cycleno , cyclep -> index );
+}
+
+    /*
+     * print the members of a cycle
+     */
+printmembers( cyclep )
+    nltype     *cyclep;
+{
+    nltype     *memberp;
+
+    sortmembers( cyclep );
+    for ( memberp = cyclep -> cnext ; memberp ; memberp = memberp -> cnext ) {
+       printf( "%6.6s %5.5s %7.2f %11.2f %7d" , 
+               "" , "" , memberp -> propself / hz , memberp -> propchild / hz ,
+               memberp -> ncall );
+       if ( memberp -> selfcalls != 0 ) {
+           printf( "+%-7d" , memberp -> selfcalls );
+       } else {
+           printf( " %7.7s" , "" );
+       }
+       printf( "     " );
+       printname( memberp );
+       printf( "\n" );
+    }
+}
+
+    /*
+     * sort members of a cycle
+     */
+sortmembers( cyclep )
+    nltype     *cyclep;
+{
+    nltype     *todo;
+    nltype     *doing;
+    nltype     *prev;
+
+       /*
+        *      detach cycle members from cyclehead,
+        *      and insertion sort them back on.
+        */
+    todo = cyclep -> cnext;
+    cyclep -> cnext = 0;
+    for (  (doing = todo)&&(todo = doing -> cnext);
+           doing ;
+          (doing = todo )&&(todo = doing -> cnext )){
+       for ( prev = cyclep ; prev -> cnext ; prev = prev -> cnext ) {
+           if ( membercmp( doing , prev -> cnext ) == GREATERTHAN ) {
+               break;
+           }
+       }
+       doing -> cnext = prev -> cnext;
+       prev -> cnext = doing;
+    }
+}
+
+    /*
+     * major sort is on propself + propchild,
+     * next is sort on ncalls + selfcalls.
+     */
+int
+membercmp( this , that )
+    nltype     *this;
+    nltype     *that;
+{
+    double     thistime = this -> propself + this -> propchild;
+    double     thattime = that -> propself + that -> propchild;
+    long       thiscalls = this -> ncall + this -> selfcalls;
+    long       thatcalls = that -> ncall + that -> selfcalls;
+
+    if ( thistime > thattime ) {
+       return GREATERTHAN;
+    }
+    if ( thistime < thattime ) {
+       return LESSTHAN;
+    }
+    if ( thiscalls > thatcalls ) {
+       return GREATERTHAN;
+    }
+    if ( thiscalls < thatcalls ) {
+       return LESSTHAN;
+    }
+    return EQUALTO;
+}
+    /*
+     * compare two arcs to/from the same child/parent.
+     * - if one arc is a self arc, it's least.
+     * - if one arc is within a cycle, it's less than.
+     * - if both arcs are within a cycle, compare arc counts.
+     * - if neither arc is within a cycle, compare with
+     *         arc_time + arc_childtime as major key
+     *         arc count as minor key
+     */
+int
+arccmp( thisp , thatp )
+    arctype    *thisp;
+    arctype    *thatp;
+{
+    nltype     *thisparentp = thisp -> arc_parentp;
+    nltype     *thischildp = thisp -> arc_childp;
+    nltype     *thatparentp = thatp -> arc_parentp;
+    nltype     *thatchildp = thatp -> arc_childp;
+    double     thistime;
+    double     thattime;
+
+#   ifdef DEBUG
+       if ( debug & TIMEDEBUG ) {
+           printf( "[arccmp] " );
+           printname( thisparentp );
+           printf( " calls " );
+           printname ( thischildp );
+           printf( " %f + %f %d/%d\n" ,
+                   thisp -> arc_time , thisp -> arc_childtime ,
+                   thisp -> arc_count , thischildp -> ncall );
+           printf( "[arccmp] " );
+           printname( thatparentp );
+           printf( " calls " );
+           printname( thatchildp );
+           printf( " %f + %f %d/%d\n" ,
+                   thatp -> arc_time , thatp -> arc_childtime ,
+                   thatp -> arc_count , thatchildp -> ncall );
+           printf( "\n" );
+       }
+#   endif DEBUG
+    if ( thisparentp == thischildp ) {
+           /* this is a self call */
+       return LESSTHAN;
+    }
+    if ( thatparentp == thatchildp ) {
+           /* that is a self call */
+       return GREATERTHAN;
+    }
+    if ( thisparentp -> cycleno != 0 && thischildp -> cycleno != 0 &&
+       thisparentp -> cycleno == thischildp -> cycleno ) {
+           /* this is a call within a cycle */
+       if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
+           thatparentp -> cycleno == thatchildp -> cycleno ) {
+               /* that is a call within the cycle, too */
+           if ( thisp -> arc_count < thatp -> arc_count ) {
+               return LESSTHAN;
+           }
+           if ( thisp -> arc_count > thatp -> arc_count ) {
+               return GREATERTHAN;
+           }
+           return EQUALTO;
+       } else {
+               /* that isn't a call within the cycle */
+           return LESSTHAN;
+       }
+    } else {
+           /* this isn't a call within a cycle */
+       if ( thatparentp -> cycleno != 0 && thatchildp -> cycleno != 0 &&
+           thatparentp -> cycleno == thatchildp -> cycleno ) {
+               /* that is a call within a cycle */
+           return GREATERTHAN;
+       } else {
+               /* neither is a call within a cycle */
+           thistime = thisp -> arc_time + thisp -> arc_childtime;
+           thattime = thatp -> arc_time + thatp -> arc_childtime;
+           if ( thistime < thattime )
+               return LESSTHAN;
+           if ( thistime > thattime )
+               return GREATERTHAN;
+           if ( thisp -> arc_count < thatp -> arc_count )
+               return LESSTHAN;
+           if ( thisp -> arc_count > thatp -> arc_count )
+               return GREATERTHAN;
+           return EQUALTO;
+       }
+    }
+}
+
+printblurb( blurbname )
+    char       *blurbname;
+{
+    FILE       *blurbfile;
+    int                input;
+
+    blurbfile = fopen( blurbname , "r" );
+    if ( blurbfile == NULL ) {
+       perror( blurbname );
+       return;
+    }
+    while ( ( input = getc( blurbfile ) ) != EOF ) {
+       putchar( input );
+    }
+    fclose( blurbfile );
+}
+
+int
+namecmp( npp1 , npp2 )
+    nltype **npp1, **npp2;
+{
+    return( strcmp( (*npp1) -> name , (*npp2) -> name ) );
+}
+
+printindex()
+{
+    nltype             **namesortnlp;
+    register nltype    *nlp;
+    int                        index, nnames, todo, i, j;
+    char               peterbuffer[ BUFSIZ ];
+
+       /*
+        *      Now, sort regular function name alphbetically
+        *      to create an index.
+        */
+    namesortnlp = (nltype **) calloc( nname + ncycle , sizeof(nltype *) );
+    if ( namesortnlp == (nltype **) 0 ) {
+       fprintf( stderr , "%s: ran out of memory for sorting\n" , whoami );
+    }
+    for ( index = 0 , nnames = 0 ; index < nname ; index++ ) {
+       if ( zflag == 0 && nl[index].ncall == 0 && nl[index].time == 0 )
+               continue;
+       namesortnlp[nnames++] = &nl[index];
+    }
+    qsort( namesortnlp , nnames , sizeof(nltype *) , namecmp );
+    for ( index = 1 , todo = nnames ; index <= ncycle ; index++ ) {
+       namesortnlp[todo++] = &cyclenl[index];
+    }
+    printf( "\f\nIndex by function name\n\n" );
+    index = ( todo + 2 ) / 3;
+    for ( i = 0; i < index ; i++ ) {
+       for ( j = i; j < todo ; j += index ) {
+           nlp = namesortnlp[ j ];
+           if ( nlp -> printflag ) {
+               sprintf( peterbuffer , "[%d]" , nlp -> index );
+           } else {
+               sprintf( peterbuffer , "(%d)" , nlp -> index );
+           }
+           if ( j < nnames ) {
+               printf( "%6.6s %-19.19s" , peterbuffer , nlp -> name );
+           } else {
+               printf( "%6.6s " , peterbuffer );
+               sprintf( peterbuffer , "<cycle %d>" , nlp -> cycleno );
+               printf( "%-19.19s" , peterbuffer );
+           }
+       }
+       printf( "\n" );
+    }
+    cfree( namesortnlp );
+}
diff --git a/gprof/printlist.c b/gprof/printlist.c
new file mode 100644 (file)
index 0000000..8e952f0
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)printlist.c        5.5 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include "gprof.h"
+
+    /*
+     * these are the lists of names:
+     * there is the list head and then the listname
+     * is a pointer to the list head
+     * (for ease of passing to stringlist functions).
+     */
+struct stringlist      kfromhead = { 0 , 0 };
+struct stringlist      *kfromlist = &kfromhead;
+struct stringlist      ktohead = { 0 , 0 };
+struct stringlist      *ktolist = &ktohead;
+struct stringlist      fhead = { 0 , 0 };
+struct stringlist      *flist = &fhead;
+struct stringlist      Fhead = { 0 , 0 };
+struct stringlist      *Flist = &Fhead;
+struct stringlist      ehead = { 0 , 0 };
+struct stringlist      *elist = &ehead;
+struct stringlist      Ehead = { 0 , 0 };
+struct stringlist      *Elist = &Ehead;
+
+addlist( listp , funcname )
+    struct stringlist  *listp;
+    char               *funcname;
+{
+    struct stringlist  *slp;
+
+    slp = (struct stringlist *) malloc( sizeof(struct stringlist));
+    if ( slp == (struct stringlist *) 0 ) {
+       fprintf( stderr, "gprof: ran out room for printlist\n" );
+       done();
+    }
+    slp -> next = listp -> next;
+    slp -> string = funcname;
+    listp -> next = slp;
+}
+
+bool
+onlist( listp , funcname )
+    struct stringlist  *listp;
+    char               *funcname;
+{
+    struct stringlist  *slp;
+
+    for ( slp = listp -> next ; slp ; slp = slp -> next ) {
+       if ( ! strcmp( slp -> string , funcname ) ) {
+           return TRUE;
+       }
+       if ( funcname[0] == '_' && ! strcmp( slp -> string , &funcname[1] ) ) {
+           return TRUE;
+       }
+    }
+    return FALSE;
+}
diff --git a/gprof/sparc.c b/gprof/sparc.c
new file mode 100644 (file)
index 0000000..0bd6451
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tahoe.c    1.5 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include       "gprof.h"
+
+    /*
+     * a namelist entry to be the child of indirect callf
+     */
+nltype indirectchild = {
+       "(*)" ,                         /* the name */
+       (unsigned long) 0 ,             /* the pc entry point */
+       (unsigned long) 0 ,             /* entry point aligned to histogram */
+       (double) 0.0 ,                  /* ticks in this routine */
+       (double) 0.0 ,                  /* cumulative ticks in children */
+       (long) 0 ,                      /* how many times called */
+       (long) 0 ,                      /* how many calls to self */
+       (double) 1.0 ,                  /* propagation fraction */
+       (double) 0.0 ,                  /* self propagation time */
+       (double) 0.0 ,                  /* child propagation time */
+       (bool) 0 ,                      /* print flag */
+       (int) 0 ,                       /* index in the graph list */
+       (int) 0 ,                       /* graph call chain top-sort order */
+       (int) 0 ,                       /* internal number of cycle on */
+       (struct nl *) &indirectchild ,  /* pointer to head of cycle */
+       (struct nl *) 0 ,               /* pointer to next member of cycle */
+       (arctype *) 0 ,                 /* list of caller arcs */
+       (arctype *) 0                   /* list of callee arcs */
+    };
+
+findcall( parentp , p_lowpc , p_highpc )
+    nltype             *parentp;
+    unsigned long      p_lowpc;
+    unsigned long      p_highpc;
+{
+    unsigned char      *instructp;
+    long               length;
+    nltype             *childp;
+    unsigned long      destpc;
+
+    if ( textspace == 0 ) {
+       return;
+    }
+    if ( p_lowpc < s_lowpc ) {
+       p_lowpc = s_lowpc;
+    }
+    if ( p_highpc > s_highpc ) {
+       p_highpc = s_highpc;
+    }
+#   ifdef DEBUG
+       if ( debug & CALLDEBUG ) {
+           printf( "[findcall] %s: 0x%x to 0x%x\n" ,
+                   parentp -> name , p_lowpc , p_highpc );
+       }
+#   endif DEBUG
+    for (   instructp = textspace + p_lowpc ;
+           instructp < textspace + p_highpc ;
+           instructp += length ) {
+       length = 1;
+       if ( (*instructp & CALL) ) {
+#          ifdef DEBUG
+         if ( debug & CALLDEBUG ) {
+           printf( "[findcall]\t0x%x:callf" , instructp - textspace );
+         }
+#          endif DEBUG
+         length += 4;  /* constant length in a SPARC */
+         /*
+          *    regular pc relative addressing
+          *    check that this is the address of 
+          *    a function.
+          */
+         destpc = ( (unsigned long)instructp + (*(long *)instructp & ~CALL) )
+           - (unsigned long) textspace;
+         if ( destpc >= s_lowpc && destpc <= s_highpc ) {
+           childp = nllookup( destpc );
+#                      ifdef DEBUG
+           if ( debug & CALLDEBUG ) {
+             printf( "[findcall]\tdestpc 0x%x" , destpc );
+             printf( " childp->name %s" , childp -> name );
+             printf( " childp->value 0x%x\n" ,
+                    childp -> value );
+           }
+#                      endif DEBUG
+           if ( childp -> value == destpc ) {
+             /*
+              *        a hit
+              */
+             addarc( parentp , childp , (long) 0 );
+             length += 4;      /* constant lengths */
+             continue;
+           }
+           goto botched;
+         }
+         /*
+          *    else:
+          *    it looked like a callf,
+          *    but it wasn't to anywhere.
+          */
+       botched:
+         /*
+          *    something funny going on.
+          */
+#                  ifdef DEBUG
+         if ( debug & CALLDEBUG ) {
+           printf( "[findcall]\tbut it's a botch\n" );
+         }
+#                  endif DEBUG
+         length = 1;
+         continue;
+       }
+      }
+  }
diff --git a/gprof/sparc.h b/gprof/sparc.h
new file mode 100644 (file)
index 0000000..0287b88
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)tahoe.h     1.4 (Berkeley) 6/1/90
+ */
+
+    /*
+     * opcode of the `callf' instruction
+     */
+#define        CALL    (0xc0000000)
+    /*
+     * offset (in bytes) of the code from the entry address of a routine.
+     * (see asgnsamples for use and explanation.)
+     */
+#define OFFSET_OF_CODE 0
+#define        UNITS_TO_CODE   (OFFSET_OF_CODE / sizeof(UNIT))
+
diff --git a/gprof/t.c b/gprof/t.c
new file mode 100755 (executable)
index 0000000..62272b4
--- /dev/null
+++ b/gprof/t.c
@@ -0,0 +1,12 @@
+void
+foo(int x) {
+       if (x&3)
+               foo (x-1);
+}
+
+main() {
+       int i;
+
+       for (i=0; i< 1024; i++)
+               foo(i);
+}
diff --git a/gprof/tahoe.c b/gprof/tahoe.c
new file mode 100644 (file)
index 0000000..924d95d
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tahoe.c    1.5 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include       "gprof.h"
+
+    /*
+     * a namelist entry to be the child of indirect callf
+     */
+nltype indirectchild = {
+       "(*)" ,                         /* the name */
+       (unsigned long) 0 ,             /* the pc entry point */
+       (unsigned long) 0 ,             /* entry point aligned to histogram */
+       (double) 0.0 ,                  /* ticks in this routine */
+       (double) 0.0 ,                  /* cumulative ticks in children */
+       (long) 0 ,                      /* how many times called */
+       (long) 0 ,                      /* how many calls to self */
+       (double) 1.0 ,                  /* propagation fraction */
+       (double) 0.0 ,                  /* self propagation time */
+       (double) 0.0 ,                  /* child propagation time */
+       (bool) 0 ,                      /* print flag */
+       (int) 0 ,                       /* index in the graph list */
+       (int) 0 ,                       /* graph call chain top-sort order */
+       (int) 0 ,                       /* internal number of cycle on */
+       (struct nl *) &indirectchild ,  /* pointer to head of cycle */
+       (struct nl *) 0 ,               /* pointer to next member of cycle */
+       (arctype *) 0 ,                 /* list of caller arcs */
+       (arctype *) 0                   /* list of callee arcs */
+    };
+
+operandenum
+operandmode( modep )
+    unsigned char      *modep;
+{
+    long       usesreg = ((long)*modep) & 0xf;
+    
+    switch ( ((long)*modep) >> 4 ) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+           return literal;
+       case 4:
+           return indexed;
+       case 5:
+           return reg;
+       case 6:
+           return regdef;
+       case 7:
+           return autodec;
+       case 8:
+           return ( usesreg != 0xe ? autoinc : immediate );
+       case 9:
+           return ( usesreg != PC ? autoincdef : absolute );
+       case 10:
+           return ( usesreg != PC ? bytedisp : byterel );
+       case 11:
+           return ( usesreg != PC ? bytedispdef : bytereldef );
+       case 12:
+           return ( usesreg != PC ? worddisp : wordrel );
+       case 13:
+           return ( usesreg != PC ? worddispdef : wordreldef );
+       case 14:
+           return ( usesreg != PC ? longdisp : longrel );
+       case 15:
+           return ( usesreg != PC ? longdispdef : longreldef );
+    }
+    /* NOTREACHED */
+}
+
+char *
+operandname( mode )
+    operandenum        mode;
+{
+    
+    switch ( mode ) {
+       case literal:
+           return "literal";
+       case indexed:
+           return "indexed";
+       case reg:
+           return "register";
+       case regdef:
+           return "register deferred";
+       case autodec:
+           return "autodecrement";
+       case autoinc:
+           return "autoincrement";
+       case autoincdef:
+           return "autoincrement deferred";
+       case bytedisp:
+           return "byte displacement";
+       case bytedispdef:
+           return "byte displacement deferred";
+       case byterel:
+           return "byte relative";
+       case bytereldef:
+           return "byte relative deferred";
+       case worddisp:
+           return "word displacement";
+       case worddispdef:
+           return "word displacement deferred";
+       case wordrel:
+           return "word relative";
+       case wordreldef:
+           return "word relative deferred";
+       case immediate:
+           return "immediate";
+       case absolute:
+           return "absolute";
+       case longdisp:
+           return "long displacement";
+       case longdispdef:
+           return "long displacement deferred";
+       case longrel:
+           return "long relative";
+       case longreldef:
+           return "long relative deferred";
+    }
+    /* NOTREACHED */
+}
+
+long
+operandlength( modep )
+    unsigned char      *modep;
+{
+    
+    switch ( operandmode( modep ) ) {
+       case literal:
+       case reg:
+       case regdef:
+       case autodec:
+       case autoinc:
+       case autoincdef:
+           return 1;
+       case bytedisp:
+       case bytedispdef:
+       case byterel:
+       case bytereldef:
+           return 2;
+       case worddisp:
+       case worddispdef:
+       case wordrel:
+       case wordreldef:
+           return 3;
+       case immediate:
+       case absolute:
+       case longdisp:
+       case longdispdef:
+       case longrel:
+       case longreldef:
+           return 5;
+       case indexed:
+           return 1+operandlength( modep + 1 );
+    }
+    /* NOTREACHED */
+}
+
+unsigned long
+reladdr( modep )
+    char       *modep;
+{
+    operandenum        mode = operandmode( modep );
+    char       *cp;
+    short      *sp;
+    long       *lp;
+    int                i;
+    long       value = 0;
+
+    cp = modep;
+    cp += 1;                   /* skip over the mode */
+    switch ( mode ) {
+       default:
+           fprintf( stderr , "[reladdr] not relative address\n" );
+           return (unsigned long) modep;
+       case byterel:
+           return (unsigned long) ( cp + sizeof *cp + *cp );
+       case wordrel:
+           for (i = 0; i < sizeof *sp; i++)
+               value = (value << 8) + (cp[i] & 0xff);
+           return (unsigned long) ( cp + sizeof *sp + value );
+       case longrel:
+           for (i = 0; i < sizeof *lp; i++)
+               value = (value << 8) + (cp[i] & 0xff);
+           return (unsigned long) ( cp + sizeof *lp + value );
+    }
+}
+
+findcall( parentp , p_lowpc , p_highpc )
+    nltype             *parentp;
+    unsigned long      p_lowpc;
+    unsigned long      p_highpc;
+{
+    unsigned char      *instructp;
+    long               length;
+    nltype             *childp;
+    operandenum                mode;
+    operandenum                firstmode;
+    unsigned long      destpc;
+
+    if ( textspace == 0 ) {
+       return;
+    }
+    if ( p_lowpc < s_lowpc ) {
+       p_lowpc = s_lowpc;
+    }
+    if ( p_highpc > s_highpc ) {
+       p_highpc = s_highpc;
+    }
+#   ifdef DEBUG
+       if ( debug & CALLDEBUG ) {
+           printf( "[findcall] %s: 0x%x to 0x%x\n" ,
+                   parentp -> name , p_lowpc , p_highpc );
+       }
+#   endif DEBUG
+    for (   instructp = textspace + p_lowpc ;
+           instructp < textspace + p_highpc ;
+           instructp += length ) {
+       length = 1;
+       if ( *instructp == CALLF ) {
+               /*
+                *      maybe a callf, better check it out.
+                *      skip the count of the number of arguments.
+                */
+#          ifdef DEBUG
+               if ( debug & CALLDEBUG ) {
+                   printf( "[findcall]\t0x%x:callf" , instructp - textspace );
+               }
+#          endif DEBUG
+           firstmode = operandmode( instructp+length );
+           switch ( firstmode ) {
+               case literal:
+               case immediate:
+                   break;
+               default:
+                   goto botched;
+           }
+           length += operandlength( instructp+length );
+           mode = operandmode( instructp + length );
+#          ifdef DEBUG
+               if ( debug & CALLDEBUG ) {
+                   printf( "\tfirst operand is %s", operandname( firstmode ) );
+                   printf( "\tsecond operand is %s\n" , operandname( mode ) );
+               }
+#          endif DEBUG
+           switch ( mode ) {
+               case regdef:
+               case bytedispdef:
+               case worddispdef:
+               case longdispdef:
+               case bytereldef:
+               case wordreldef:
+               case longreldef:
+                       /*
+                        *      indirect call: call through pointer
+                        *      either  *d(r)   as a parameter or local
+                        *              (r)     as a return value
+                        *              *f      as a global pointer
+                        *      [are there others that we miss?,
+                        *       e.g. arrays of pointers to functions???]
+                        */
+                   addarc( parentp , &indirectchild , (long) 0 );
+                   length += operandlength( instructp + length );
+                   continue;
+               case byterel:
+               case wordrel:
+               case longrel:
+                       /*
+                        *      regular pc relative addressing
+                        *      check that this is the address of 
+                        *      a function.
+                        */
+                   destpc = reladdr( instructp+length )
+                               - (unsigned long) textspace;
+                   if ( destpc >= s_lowpc && destpc <= s_highpc ) {
+                       childp = nllookup( destpc );
+#                      ifdef DEBUG
+                           if ( debug & CALLDEBUG ) {
+                               printf( "[findcall]\tdestpc 0x%x" , destpc );
+                               printf( " childp->name %s" , childp -> name );
+                               printf( " childp->value 0x%x\n" ,
+                                       childp -> value );
+                           }
+#                      endif DEBUG
+                       if ( childp -> value == destpc ) {
+                               /*
+                                *      a hit
+                                */
+                           addarc( parentp , childp , (long) 0 );
+                           length += operandlength( instructp + length );
+                           continue;
+                       }
+                       goto botched;
+                   }
+                       /*
+                        *      else:
+                        *      it looked like a callf,
+                        *      but it wasn't to anywhere.
+                        */
+                   goto botched;
+               default:
+               botched:
+                       /*
+                        *      something funny going on.
+                        */
+#                  ifdef DEBUG
+                       if ( debug & CALLDEBUG ) {
+                           printf( "[findcall]\tbut it's a botch\n" );
+                       }
+#                  endif DEBUG
+                   length = 1;
+                   continue;
+           }
+       }
+    }
+}
diff --git a/gprof/tahoe.h b/gprof/tahoe.h
new file mode 100644 (file)
index 0000000..55c1d32
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)tahoe.h     1.4 (Berkeley) 6/1/90
+ */
+
+    /*
+     * opcode of the `callf' instruction
+     */
+#define        CALLF   0xfe
+
+    /*
+     * offset (in bytes) of the code from the entry address of a routine.
+     * (see asgnsamples for use and explanation.)
+     */
+#define OFFSET_OF_CODE 2
+#define        UNITS_TO_CODE   (OFFSET_OF_CODE / sizeof(UNIT))
+
+    /*
+     * register for pc relative addressing
+     */
+#define        PC      0xf
+
+enum opermodes {
+    literal, indexed, reg, regdef, autodec, autoinc, autoincdef, 
+    bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
+    immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
+    longrel, longreldef
+};
+typedef enum opermodes operandenum;
diff --git a/gprof/vax.c b/gprof/vax.c
new file mode 100644 (file)
index 0000000..220b758
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)vax.c      5.6 (Berkeley) 6/1/90";
+#endif /* not lint */
+
+#include       "gprof.h"
+
+    /*
+     * a namelist entry to be the child of indirect calls
+     */
+nltype indirectchild = {
+       "(*)" ,                         /* the name */
+       (unsigned long) 0 ,             /* the pc entry point */
+       (unsigned long) 0 ,             /* entry point aligned to histogram */
+       (double) 0.0 ,                  /* ticks in this routine */
+       (double) 0.0 ,                  /* cumulative ticks in children */
+       (long) 0 ,                      /* how many times called */
+       (long) 0 ,                      /* how many calls to self */
+       (double) 1.0 ,                  /* propagation fraction */
+       (double) 0.0 ,                  /* self propagation time */
+       (double) 0.0 ,                  /* child propagation time */
+       (bool) 0 ,                      /* print flag */
+       (int) 0 ,                       /* index in the graph list */
+       (int) 0 ,                       /* graph call chain top-sort order */
+       (int) 0 ,                       /* internal number of cycle on */
+       (struct nl *) &indirectchild ,  /* pointer to head of cycle */
+       (struct nl *) 0 ,               /* pointer to next member of cycle */
+       (arctype *) 0 ,                 /* list of caller arcs */
+       (arctype *) 0                   /* list of callee arcs */
+    };
+
+operandenum
+operandmode( modep )
+    struct modebyte    *modep;
+{
+    long       usesreg = modep -> regfield;
+    
+    switch ( modep -> modefield ) {
+       case 0:
+       case 1:
+       case 2:
+       case 3:
+           return literal;
+       case 4:
+           return indexed;
+       case 5:
+           return reg;
+       case 6:
+           return regdef;
+       case 7:
+           return autodec;
+       case 8:
+           return ( usesreg != PC ? autoinc : immediate );
+       case 9:
+           return ( usesreg != PC ? autoincdef : absolute );
+       case 10:
+           return ( usesreg != PC ? bytedisp : byterel );
+       case 11:
+           return ( usesreg != PC ? bytedispdef : bytereldef );
+       case 12:
+           return ( usesreg != PC ? worddisp : wordrel );
+       case 13:
+           return ( usesreg != PC ? worddispdef : wordreldef );
+       case 14:
+           return ( usesreg != PC ? longdisp : longrel );
+       case 15:
+           return ( usesreg != PC ? longdispdef : longreldef );
+    }
+    /* NOTREACHED */
+}
+
+char *
+operandname( mode )
+    operandenum        mode;
+{
+    
+    switch ( mode ) {
+       case literal:
+           return "literal";
+       case indexed:
+           return "indexed";
+       case reg:
+           return "register";
+       case regdef:
+           return "register deferred";
+       case autodec:
+           return "autodecrement";
+       case autoinc:
+           return "autoincrement";
+       case autoincdef:
+           return "autoincrement deferred";
+       case bytedisp:
+           return "byte displacement";
+       case bytedispdef:
+           return "byte displacement deferred";
+       case byterel:
+           return "byte relative";
+       case bytereldef:
+           return "byte relative deferred";
+       case worddisp:
+           return "word displacement";
+       case worddispdef:
+           return "word displacement deferred";
+       case wordrel:
+           return "word relative";
+       case wordreldef:
+           return "word relative deferred";
+       case immediate:
+           return "immediate";
+       case absolute:
+           return "absolute";
+       case longdisp:
+           return "long displacement";
+       case longdispdef:
+           return "long displacement deferred";
+       case longrel:
+           return "long relative";
+       case longreldef:
+           return "long relative deferred";
+    }
+    /* NOTREACHED */
+}
+
+long
+operandlength( modep )
+    struct modebyte    *modep;
+{
+    
+    switch ( operandmode( modep ) ) {
+       case literal:
+       case reg:
+       case regdef:
+       case autodec:
+       case autoinc:
+       case autoincdef:
+           return 1;
+       case bytedisp:
+       case bytedispdef:
+       case byterel:
+       case bytereldef:
+           return 2;
+       case worddisp:
+       case worddispdef:
+       case wordrel:
+       case wordreldef:
+           return 3;
+       case immediate:
+       case absolute:
+       case longdisp:
+       case longdispdef:
+       case longrel:
+       case longreldef:
+           return 5;
+       case indexed:
+           return 1+operandlength( (struct modebyte *) ((char *) modep) + 1 );
+    }
+    /* NOTREACHED */
+}
+
+unsigned long
+reladdr( modep )
+    struct modebyte    *modep;
+{
+    operandenum        mode = operandmode( modep );
+    char       *cp;
+    short      *sp;
+    long       *lp;
+
+    cp = (char *) modep;
+    cp += 1;                   /* skip over the mode */
+    switch ( mode ) {
+       default:
+           fprintf( stderr , "[reladdr] not relative address\n" );
+           return (unsigned long) modep;
+       case byterel:
+           return (unsigned long) ( cp + sizeof *cp + *cp );
+       case wordrel:
+           sp = (short *) cp;
+           return (unsigned long) ( cp + sizeof *sp + *sp );
+       case longrel:
+           lp = (long *) cp;
+           return (unsigned long) ( cp + sizeof *lp + *lp );
+    }
+}
+
+findcall( parentp , p_lowpc , p_highpc )
+    nltype             *parentp;
+    unsigned long      p_lowpc;
+    unsigned long      p_highpc;
+{
+    unsigned char      *instructp;
+    long               length;
+    nltype             *childp;
+    operandenum                mode;
+    operandenum                firstmode;
+    unsigned long      destpc;
+
+    if ( textspace == 0 ) {
+       return;
+    }
+    if ( p_lowpc < s_lowpc ) {
+       p_lowpc = s_lowpc;
+    }
+    if ( p_highpc > s_highpc ) {
+       p_highpc = s_highpc;
+    }
+#   ifdef DEBUG
+       if ( debug & CALLDEBUG ) {
+           printf( "[findcall] %s: 0x%x to 0x%x\n" ,
+                   parentp -> name , p_lowpc , p_highpc );
+       }
+#   endif DEBUG
+    for (   instructp = textspace + p_lowpc ;
+           instructp < textspace + p_highpc ;
+           instructp += length ) {
+       length = 1;
+       if ( *instructp == CALLS ) {
+               /*
+                *      maybe a calls, better check it out.
+                *      skip the count of the number of arguments.
+                */
+#          ifdef DEBUG
+               if ( debug & CALLDEBUG ) {
+                   printf( "[findcall]\t0x%x:calls" , instructp - textspace );
+               }
+#          endif DEBUG
+           firstmode = operandmode( (struct modebyte *) (instructp+length) );
+           switch ( firstmode ) {
+               case literal:
+               case immediate:
+                   break;
+               default:
+                   goto botched;
+           }
+           length += operandlength( (struct modebyte *) (instructp+length) );
+           mode = operandmode( (struct modebyte *) ( instructp + length ) );
+#          ifdef DEBUG
+               if ( debug & CALLDEBUG ) {
+                   printf( "\tfirst operand is %s", operandname( firstmode ) );
+                   printf( "\tsecond operand is %s\n" , operandname( mode ) );
+               }
+#          endif DEBUG
+           switch ( mode ) {
+               case regdef:
+               case bytedispdef:
+               case worddispdef:
+               case longdispdef:
+               case bytereldef:
+               case wordreldef:
+               case longreldef:
+                       /*
+                        *      indirect call: call through pointer
+                        *      either  *d(r)   as a parameter or local
+                        *              (r)     as a return value
+                        *              *f      as a global pointer
+                        *      [are there others that we miss?,
+                        *       e.g. arrays of pointers to functions???]
+                        */
+                   addarc( parentp , &indirectchild , (long) 0 );
+                   length += operandlength(
+                               (struct modebyte *) ( instructp + length ) );
+                   continue;
+               case byterel:
+               case wordrel:
+               case longrel:
+                       /*
+                        *      regular pc relative addressing
+                        *      check that this is the address of 
+                        *      a function.
+                        */
+                   destpc = reladdr( (struct modebyte *) (instructp+length) )
+                               - (unsigned long) textspace;
+                   if ( destpc >= s_lowpc && destpc <= s_highpc ) {
+                       childp = nllookup( destpc );
+#                      ifdef DEBUG
+                           if ( debug & CALLDEBUG ) {
+                               printf( "[findcall]\tdestpc 0x%x" , destpc );
+                               printf( " childp->name %s" , childp -> name );
+                               printf( " childp->value 0x%x\n" ,
+                                       childp -> value );
+                           }
+#                      endif DEBUG
+                       if ( childp -> value == destpc ) {
+                               /*
+                                *      a hit
+                                */
+                           addarc( parentp , childp , (long) 0 );
+                           length += operandlength( (struct modebyte *)
+                                           ( instructp + length ) );
+                           continue;
+                       }
+                       goto botched;
+                   }
+                       /*
+                        *      else:
+                        *      it looked like a calls,
+                        *      but it wasn't to anywhere.
+                        */
+                   goto botched;
+               default:
+               botched:
+                       /*
+                        *      something funny going on.
+                        */
+#                  ifdef DEBUG
+                       if ( debug & CALLDEBUG ) {
+                           printf( "[findcall]\tbut it's a botch\n" );
+                       }
+#                  endif DEBUG
+                   length = 1;
+                   continue;
+           }
+       }
+    }
+}
diff --git a/gprof/vax.h b/gprof/vax.h
new file mode 100644 (file)
index 0000000..3e45167
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement:  ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)vax.h       5.4 (Berkeley) 6/1/90
+ */
+
+    /*
+     * opcode of the `calls' instruction
+     */
+#define        CALLS   0xfb
+
+    /*
+     * offset (in bytes) of the code from the entry address of a routine.
+     * (see asgnsamples for use and explanation.)
+     */
+#define OFFSET_OF_CODE 2
+#define        UNITS_TO_CODE   (OFFSET_OF_CODE / sizeof(UNIT))
+
+    /*
+     * register for pc relative addressing
+     */
+#define        PC      0xf
+
+enum opermodes {
+    literal, indexed, reg, regdef, autodec, autoinc, autoincdef, 
+    bytedisp, bytedispdef, worddisp, worddispdef, longdisp, longdispdef,
+    immediate, absolute, byterel, bytereldef, wordrel, wordreldef,
+    longrel, longreldef
+};
+typedef enum opermodes operandenum;
+
+struct modebyte {
+    unsigned int       regfield:4;
+    unsigned int       modefield:4;
+};
+