--- /dev/null
+# @(#)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)
--- /dev/null
+/*
+ * 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;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*-
+ * 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))
--- /dev/null
+.\" 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.
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+
+
+
+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
--- /dev/null
+
+
+
+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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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"
+
--- /dev/null
+/*
+ * 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 );
+}
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+ }
--- /dev/null
+/*
+ * 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))
+
--- /dev/null
+void
+foo(int x) {
+ if (x&3)
+ foo (x-1);
+}
+
+main() {
+ int i;
+
+ for (i=0; i< 1024; i++)
+ foo(i);
+}
--- /dev/null
+/*
+ * 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;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
--- /dev/null
+/*
+ * 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;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+};
+