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