add -C flag to do cycle elimination
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Tue, 25 Feb 1992 14:27:34 +0000 (06:27 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Tue, 25 Feb 1992 14:27:34 +0000 (06:27 -0800)
SCCS-vsn: usr.bin/gprof/gprof.h 5.11
SCCS-vsn: usr.bin/gprof/printgprof.c 5.8
SCCS-vsn: usr.bin/gprof/gprof.c 5.9
SCCS-vsn: usr.bin/gprof/dfn.c 5.5
SCCS-vsn: usr.bin/gprof/arcs.c 5.7

usr/src/usr.bin/gprof/arcs.c
usr/src/usr.bin/gprof/dfn.c
usr/src/usr.bin/gprof/gprof.c
usr/src/usr.bin/gprof/gprof.h
usr/src/usr.bin/gprof/printgprof.c

index 73e4272..c15ab4d 100644 (file)
@@ -6,11 +6,18 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)arcs.c     5.6 (Berkeley) %G%";
+static char sccsid[] = "@(#)arcs.c     5.7 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "gprof.h"
 
 #endif /* not lint */
 
 #include "gprof.h"
 
+#ifdef DEBUG
+int visited;
+int viable;
+int newcycle;
+int oldcycle;
+#endif DEBUG
+
     /*
      * add (or just increment) an arc
      */
     /*
      * add (or just increment) an arc
      */
@@ -81,6 +88,7 @@ doarcs()
     nltype     *parentp, **timesortnlp;
     arctype    *arcp;
     long       index;
     nltype     *parentp, **timesortnlp;
     arctype    *arcp;
     long       index;
+    long       pass;
 
        /*
         *      initialize various things:
 
        /*
         *      initialize various things:
@@ -97,6 +105,7 @@ doarcs()
        } else {
            parentp -> selfcalls = 0;
        }
        } else {
            parentp -> selfcalls = 0;
        }
+       parentp -> npropcall = parentp -> ncall;
        parentp -> propfraction = 0.0;
        parentp -> propself = 0.0;
        parentp -> propchild = 0.0;
        parentp -> propfraction = 0.0;
        parentp -> propself = 0.0;
        parentp -> propchild = 0.0;
@@ -109,20 +118,56 @@ doarcs()
            findcall( parentp , parentp -> value , (parentp+1) -> value );
        }
     }
            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 );
+    for ( pass = 1 ; ; pass++ ) {
+           /*
+            *  topologically order things
+            *  if any node is unnumbered,
+            *      number it and any of its descendents.
+            */
+       for ( dfn_init() , parentp = nl ; parentp < npe ; parentp++ ) {
+           if ( parentp -> toporder == DFN_NAN ) {
+               dfn( parentp );
+           }
+       }
+           /*
+            *  link together nodes on the same cycle
+            */
+       cyclelink();
+           /*
+            *  if no cycles to break up, proceed
+            */
+       if ( ! Cflag )
+           break;
+           /*
+            *  analyze cycles to determine breakup
+            */
+#      ifdef DEBUG
+           if ( debug & BREAKCYCLE ) {
+               printf("[doarcs] pass %d, cycle(s) %d\n" , pass , ncycle );
+           }
+#      endif DEBUG
+       if ( pass == 1 ) {
+           printf( "\n\n%s %s\n%s %d:\n" ,
+               "The following arcs were deleted" ,
+               "from the propagation calculation" ,
+               "to reduce the maximum cycle size to", cyclethreshold );
+       }
+       if ( cycleanalyze() )
+           break;
+       free ( cyclenl );
+       ncycle = 0;
+       for ( parentp = nl ; parentp < npe ; parentp++ ) {
+           parentp -> toporder = DFN_NAN;
+           parentp -> cycleno = 0;
+           parentp -> cyclehead = parentp;
+           parentp -> cnext = 0;
        }
     }
        }
     }
-       /*
-        *      link together nodes on the same cycle
-        */
-    cyclelink();
+    if ( pass > 1 ) {
+       printf( "\f\n" );
+    } else {
+       printf( "\tNone\n\n" );
+    }
        /*
         *      Sort the symbol table in reverse topological order
         */
        /*
         *      Sort the symbol table in reverse topological order
         */
@@ -206,6 +251,9 @@ timepropagate( parentp )
         */
     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
        childp = arcp -> arc_childp;
         */
     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
        childp = arcp -> arc_childp;
+       if ( arcp -> arc_flags & DEADARC ) {
+           continue;
+       }
        if ( arcp -> arc_count == 0 ) {
            continue;
        }
        if ( arcp -> arc_count == 0 ) {
            continue;
        }
@@ -229,7 +277,7 @@ timepropagate( parentp )
                continue;
            }
        }
                continue;
            }
        }
-       if ( childp -> ncall == 0 ) {
+       if ( childp -> npropcall == 0 ) {
            continue;
        }
            /*
            continue;
        }
            /*
@@ -237,10 +285,10 @@ timepropagate( parentp )
             */
        arcp -> arc_time = childp -> time
                                * ( ( (double) arcp -> arc_count ) /
             */
        arcp -> arc_time = childp -> time
                                * ( ( (double) arcp -> arc_count ) /
-                                   ( (double) childp -> ncall ) );
+                                   ( (double) childp -> npropcall ) );
        arcp -> arc_childtime = childp -> childtime
                                * ( ( (double) arcp -> arc_count ) /
        arcp -> arc_childtime = childp -> childtime
                                * ( ( (double) arcp -> arc_count ) /
-                                   ( (double) childp -> ncall ) );
+                                   ( (double) childp -> npropcall ) );
        share = arcp -> arc_time + arcp -> arc_childtime;
        parentp -> childtime += share;
            /*
        share = arcp -> arc_time + arcp -> arc_childtime;
        parentp -> childtime += share;
            /*
@@ -266,7 +314,7 @@ timepropagate( parentp )
                printname( childp );
                printf( " with %f %f %d/%d\n" ,
                        childp -> time , childp -> childtime ,
                printname( childp );
                printf( " with %f %f %d/%d\n" ,
                        childp -> time , childp -> childtime ,
-                       arcp -> arc_count , childp -> ncall );
+                       arcp -> arc_count , childp -> npropcall );
                printf( "[dotime] parent\t" );
                printname( parentp );
                printf( "\n[dotime] share %f\n" , share );
                printf( "[dotime] parent\t" );
                printname( parentp );
                printf( "\n[dotime] share %f\n" , share );
@@ -359,13 +407,329 @@ cyclelink()
                if ( arcp -> arc_parentp -> cycleno == cycle ) {
                    cyclenlp -> selfcalls += arcp -> arc_count;
                } else {
                if ( arcp -> arc_parentp -> cycleno == cycle ) {
                    cyclenlp -> selfcalls += arcp -> arc_count;
                } else {
-                   cyclenlp -> ncall += arcp -> arc_count;
+                   cyclenlp -> npropcall += arcp -> arc_count;
                }
            }
        }
     }
 }
 
                }
            }
        }
     }
 }
 
+    /*
+     * analyze cycles to determine breakup
+     */
+cycleanalyze()
+{
+    arctype    **cyclestack;
+    arctype    **stkp;
+    arctype    **arcpp;
+    arctype    **endlist;
+    arctype    *arcp;
+    nltype     *nlp;
+    cltype     *clp;
+    bool       ret;
+    bool       done;
+    int                size;
+    int                cycleno;
+
+       /*
+        *      calculate the size of the cycle, and find nodes that
+        *      exit the cycle as they are desirable targets to cut
+        *      some of their parents
+        */
+    for ( done = TRUE , cycleno = 1 ; cycleno <= ncycle ; cycleno++ ) {
+       size = 0;
+       for (nlp = cyclenl[ cycleno ] . cnext; nlp; nlp = nlp -> cnext) {
+           size += 1;
+           nlp -> parentcnt = 0;
+           nlp -> flags &= ~HASCYCLEXIT;
+           for ( arcp = nlp -> parents; arcp; arcp = arcp -> arc_parentlist ) {
+               nlp -> parentcnt += 1;
+               if ( arcp -> arc_parentp -> cycleno != cycleno )
+                   nlp -> flags |= HASCYCLEXIT;
+           }
+       }
+       if ( size <= cyclethreshold )
+           continue;
+       done = FALSE;
+        cyclestack = (arctype **) calloc( size + 1 , sizeof( arctype *) );
+       if ( cyclestack == 0 ) {
+           fprintf( stderr , "%s: No room for %d bytes of cycle stack\n" ,
+               whoami , ( size + 1 ) * sizeof( arctype * ) );
+           return;
+       }
+#      ifdef DEBUG
+           if ( debug & BREAKCYCLE ) {
+               printf( "[cycleanalyze] starting cycle %d of %d, size %d\n" ,
+                   cycleno , ncycle , size );
+           }
+#      endif DEBUG
+       for ( nlp = cyclenl[ cycleno ] . cnext ; nlp ; nlp = nlp -> cnext ) {
+           stkp = &cyclestack[0];
+           nlp -> flags |= CYCLEHEAD;
+           ret = descend ( nlp , cyclestack , stkp );
+           nlp -> flags &= ~CYCLEHEAD;
+           if ( ret == FALSE )
+               break;
+       }
+       free( cyclestack );
+       if ( cyclecnt > 0 ) {
+           compresslist();
+           for ( clp = cyclehead ; clp ; ) {
+               endlist = &clp -> list[ clp -> size ];
+               for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
+                   (*arcpp) -> arc_cyclecnt--;
+               cyclecnt--;
+               clp = clp -> next;
+               free( clp );
+           }
+           cyclehead = 0;
+       }
+    }
+#   ifdef DEBUG
+       if ( debug & BREAKCYCLE ) {
+           printf("%s visited %d, viable %d, newcycle %d, oldcycle %d\n",
+               "[doarcs]" , visited , viable , newcycle , oldcycle);
+       }
+#   endif DEBUG
+    return( done );
+}
+
+descend( node , stkstart , stkp )
+    nltype     *node;
+    arctype    **stkstart;
+    arctype    **stkp;
+{
+    arctype    *arcp;
+    bool       ret;
+
+    for ( arcp = node -> children ; arcp ; arcp = arcp -> arc_childlist ) {
+#      ifdef DEBUG
+           visited++;
+#      endif DEBUG
+       if ( arcp -> arc_childp -> cycleno != node -> cycleno
+           || ( arcp -> arc_childp -> flags & VISITED )
+           || ( arcp -> arc_flags & DEADARC ) )
+           continue;
+#      ifdef DEBUG
+           viable++;
+#      endif DEBUG
+       *stkp = arcp;
+       if ( arcp -> arc_childp -> flags & CYCLEHEAD ) {
+           if ( addcycle( stkstart , stkp ) == FALSE )
+               return( FALSE );
+           continue;
+       }
+       arcp -> arc_childp -> flags |= VISITED;
+       ret = descend( arcp -> arc_childp , stkstart , stkp + 1 );
+       arcp -> arc_childp -> flags &= ~VISITED;
+       if ( ret == FALSE )
+           return( FALSE );
+    }
+}
+
+addcycle( stkstart , stkend )
+    arctype    **stkstart;
+    arctype    **stkend;
+{
+    arctype    **arcpp;
+    arctype    **stkloc;
+    arctype    **stkp;
+    arctype    **endlist;
+    arctype    *minarc;
+    arctype    *arcp;
+    cltype     *clp;
+    int                size;
+
+    size = stkend - stkstart + 1;
+    if ( size <= 1 )
+       return( TRUE );
+    for ( arcpp = stkstart , minarc = *arcpp ; arcpp <= stkend ; arcpp++ ) {
+       if ( *arcpp > minarc )
+           continue;
+       minarc = *arcpp;
+       stkloc = arcpp;
+    }
+    for ( clp = cyclehead ; clp ; clp = clp -> next ) {
+       if ( clp -> size != size )
+           continue;
+       stkp = stkloc;
+       endlist = &clp -> list[ size ];
+       for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
+           if ( *stkp++ != *arcpp )
+               break;
+           if ( stkp > stkend )
+               stkp = stkstart;
+       }
+       if ( arcpp == endlist ) {
+#          ifdef DEBUG
+               oldcycle++;
+#          endif DEBUG
+           return( TRUE );
+       }
+    }
+    clp = (cltype *)
+       calloc( 1 , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
+    if ( clp == 0 ) {
+       fprintf( stderr , "%s: No room for %d bytes of subcycle storage\n" ,
+           whoami , sizeof ( cltype ) + ( size - 1 ) * sizeof( arctype * ) );
+       return( FALSE );
+    }
+    stkp = stkloc;
+    endlist = &clp -> list[ size ];
+    for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ ) {
+       arcp = *arcpp = *stkp++;
+       if ( stkp > stkend )
+           stkp = stkstart;
+       arcp -> arc_cyclecnt++;
+       if ( ( arcp -> arc_flags & ONLIST ) == 0 ) {
+           arcp -> arc_flags |= ONLIST;
+           arcp -> arc_next = archead;
+           archead = arcp;
+       }
+    }
+    clp -> size = size;
+    clp -> next = cyclehead;
+    cyclehead = clp;
+#   ifdef DEBUG
+       newcycle++;
+       if ( debug & SUBCYCLELIST ) {
+           printsubcycle( clp );
+       }
+#   endif DEBUG
+    cyclecnt++;
+    if ( cyclecnt >= CYCLEMAX )
+       return( FALSE );
+    return( TRUE );
+}
+
+compresslist()
+{
+    cltype     *clp;
+    cltype     **prev;
+    arctype    **arcpp;
+    arctype    **endlist;
+    arctype    *arcp;
+    arctype    *maxarcp;
+    arctype    *maxexitarcp;
+    arctype    *maxwithparentarcp;
+    arctype    *maxnoparentarcp;
+    int                maxexitcnt;
+    int                maxwithparentcnt;
+    int                maxnoparentcnt;
+    char       *type;
+
+    maxexitcnt = 0;
+    maxwithparentcnt = 0;
+    maxnoparentcnt = 0;
+    for ( endlist = &archead , arcp = archead ; arcp ; ) {
+       if ( arcp -> arc_cyclecnt == 0 ) {
+           arcp -> arc_flags &= ~ONLIST;
+           *endlist = arcp -> arc_next;
+           arcp -> arc_next = 0;
+           arcp = *endlist;
+           continue;
+       }
+       if ( arcp -> arc_childp -> flags & HASCYCLEXIT ) {
+           if ( arcp -> arc_cyclecnt > maxexitcnt ||
+               ( arcp -> arc_cyclecnt == maxexitcnt &&
+               arcp -> arc_cyclecnt < maxexitarcp -> arc_count ) ) {
+               maxexitcnt = arcp -> arc_cyclecnt;
+               maxexitarcp = arcp;
+           }
+       } else if ( arcp -> arc_childp -> parentcnt > 1 ) {
+           if ( arcp -> arc_cyclecnt > maxwithparentcnt ||
+               ( arcp -> arc_cyclecnt == maxwithparentcnt &&
+               arcp -> arc_cyclecnt < maxwithparentarcp -> arc_count ) ) {
+               maxwithparentcnt = arcp -> arc_cyclecnt;
+               maxwithparentarcp = arcp;
+           }
+       } else {
+           if ( arcp -> arc_cyclecnt > maxnoparentcnt ||
+               ( arcp -> arc_cyclecnt == maxnoparentcnt &&
+               arcp -> arc_cyclecnt < maxnoparentarcp -> arc_count ) ) {
+               maxnoparentcnt = arcp -> arc_cyclecnt;
+               maxnoparentarcp = arcp;
+           }
+       }
+       endlist = &arcp -> arc_next;
+       arcp = arcp -> arc_next;
+    }
+    if ( maxexitcnt > 0 ) {
+       /*
+        *      first choice is edge leading to node with out-of-cycle parent
+        */
+       maxarcp = maxexitarcp;
+#      ifdef DEBUG
+           type = "exit";
+#      endif DEBUG
+    } else if ( maxwithparentcnt > 0 ) {
+       /*
+        *      second choice is edge leading to node with at least one
+        *      other in-cycle parent
+        */
+       maxarcp = maxwithparentarcp;
+#      ifdef DEBUG
+           type = "internal";
+#      endif DEBUG
+    } else {
+       /*
+        *      last choice is edge leading to node with only this arc as
+        *      a parent (as it will now be orphaned)
+        */
+       maxarcp = maxnoparentarcp;
+#      ifdef DEBUG
+           type = "orphan";
+#      endif DEBUG
+    }
+    maxarcp -> arc_flags |= DEADARC;
+    maxarcp -> arc_childp -> parentcnt -= 1;
+    maxarcp -> arc_childp -> npropcall -= maxarcp -> arc_count;
+#   ifdef DEBUG
+       if ( debug & BREAKCYCLE ) {
+           printf( "%s delete %s arc: %s (%d) -> %s from %d cycle(s)\n" ,
+               "[compresslist]" , type , maxarcp -> arc_parentp -> name ,
+               maxarcp -> arc_count , maxarcp -> arc_childp -> name ,
+               maxarcp -> arc_cyclecnt );
+       }
+#   endif DEBUG
+    printf( "\t%s to %s with %d calls\n" , maxarcp -> arc_parentp -> name ,
+       maxarcp -> arc_childp -> name , maxarcp -> arc_count );
+    prev = &cyclehead;
+    for ( clp = cyclehead ; clp ; ) {
+       endlist = &clp -> list[ clp -> size ];
+       for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
+           if ( (*arcpp) -> arc_flags & DEADARC )
+               break;
+       if ( arcpp == endlist ) {
+           prev = &clp -> next;
+           clp = clp -> next;
+           continue;
+       }
+       for ( arcpp = clp -> list ; arcpp < endlist ; arcpp++ )
+           (*arcpp) -> arc_cyclecnt--;
+       cyclecnt--;
+       *prev = clp -> next;
+       clp = clp -> next;
+       free( clp );
+    }
+}
+
+#ifdef DEBUG
+printsubcycle( clp )
+    cltype     *clp;
+{
+    arctype    **arcpp;
+    arctype    **endlist;
+
+    arcpp = clp -> list;
+    printf( "%s <cycle %d>\n" , (*arcpp) -> arc_parentp -> name ,
+       (*arcpp) -> arc_parentp -> cycleno ) ;
+    for ( endlist = &clp -> list[ clp -> size ]; arcpp < endlist ; arcpp++ )
+       printf( "\t(%d) -> %s\n" , (*arcpp) -> arc_count ,
+           (*arcpp) -> arc_childp -> name ) ;
+}
+#endif DEBUG
+
 cycletime()
 {
     int                        cycle;
 cycletime()
 {
     int                        cycle;
@@ -515,10 +879,13 @@ inheritflags( childp )
                 *      (e.g. this arc is static (and all others are, too))
                 *      no time propagates along this arc.
                 */
                 *      (e.g. this arc is static (and all others are, too))
                 *      no time propagates along this arc.
                 */
-           if ( childp -> ncall ) {
+           if ( arcp -> arc_flags & DEADARC ) {
+               continue;
+           }
+           if ( childp -> npropcall ) {
                childp -> propfraction += parentp -> propfraction
                childp -> propfraction += parentp -> propfraction
-                                           * ( ( (double) arcp -> arc_count )
-                                             / ( (double) childp -> ncall ) );
+                                       * ( ( (double) arcp -> arc_count )
+                                         / ( (double) childp -> npropcall ) );
            }
        }
     } else {
            }
        }
     } else {
@@ -540,10 +907,13 @@ inheritflags( childp )
                     *  (e.g. this arc is static (and all others are, too))
                     *  no time propagates along this arc.
                     */
                     *  (e.g. this arc is static (and all others are, too))
                     *  no time propagates along this arc.
                     */
-               if ( headp -> ncall ) {
+               if ( arcp -> arc_flags & DEADARC ) {
+                   continue;
+               }
+               if ( headp -> npropcall ) {
                    headp -> propfraction += parentp -> propfraction
                    headp -> propfraction += parentp -> propfraction
-                                           * ( ( (double) arcp -> arc_count )
-                                             / ( (double) headp -> ncall ) );
+                                       * ( ( (double) arcp -> arc_count )
+                                         / ( (double) headp -> npropcall ) );
                }
            }
        }
                }
            }
        }
index f3053d6..8c87512 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)dfn.c      5.4 (Berkeley) %G%";
+static char sccsid[] = "@(#)dfn.c      5.5 (Berkeley) %G%";
 #endif /* not lint */
 
 #include <stdio.h>
 #endif /* not lint */
 
 #include <stdio.h>
@@ -20,9 +20,16 @@ struct dfnstruct {
 typedef struct dfnstruct       dfntype;
 
 dfntype        dfn_stack[ DFN_DEPTH ];
 typedef struct dfnstruct       dfntype;
 
 dfntype        dfn_stack[ DFN_DEPTH ];
-int    dfn_depth = 0;
+int    dfn_depth;
 
 
-int    dfn_counter = DFN_NAN;
+int    dfn_counter;
+
+dfn_init()
+{
+
+    dfn_depth = 0;
+    dfn_counter = DFN_NAN;
+}
 
     /*
      * given this parent, depth first number its children.
 
     /*
      * given this parent, depth first number its children.
@@ -60,6 +67,8 @@ dfn( parentp )
         *      visit children
         */
     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
         *      visit children
         */
     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
+           if ( arcp -> arc_flags & DEADARC )
+               continue;
            dfn( arcp -> arc_childp );
     }
        /*
            dfn( arcp -> arc_childp );
     }
        /*
index 73be598..d89044c 100644 (file)
@@ -12,7 +12,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)gprof.c    5.8 (Berkeley) %G%";
+static char sccsid[] = "@(#)gprof.c    5.9 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "gprof.h"
 #endif /* not lint */
 
 #include "gprof.h"
@@ -44,6 +44,10 @@ main(argc, argv)
        case 'b':
            bflag = FALSE;
            break;
        case 'b':
            bflag = FALSE;
            break;
+       case 'C':
+           Cflag = TRUE;
+           cyclethreshold = atoi( *++argv );
+           break;
        case 'c':
 #if defined(vax) || defined(tahoe)
            cflag = TRUE;
        case 'c':
 #if defined(vax) || defined(tahoe)
            cflag = TRUE;
@@ -54,8 +58,7 @@ main(argc, argv)
            break;
        case 'd':
            dflag = TRUE;
            break;
        case 'd':
            dflag = TRUE;
-           (*argv)++;
-           debug |= atoi( *argv );
+           debug |= atoi( *++argv );
            debug |= ANYDEBUG;
 #          ifdef DEBUG
                printf("[main] debug = %d\n", debug);
            debug |= ANYDEBUG;
 #          ifdef DEBUG
                printf("[main] debug = %d\n", debug);
index 8f3e341..f88f823 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)gprof.h     5.10 (Berkeley) %G%
+ *     @(#)gprof.h     5.11 (Berkeley) %G%
  */
 
 #include <sys/types.h>
  */
 
 #include <sys/types.h>
@@ -65,14 +65,23 @@ char        *gmonname;
 struct arcstruct {
     struct nl          *arc_parentp;   /* pointer to parent's nl entry */
     struct nl          *arc_childp;    /* pointer to child's nl entry */
 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 */
+    long               arc_count;      /* num 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 */
     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 */
+    struct arcstruct   *arc_next;      /* list of arcs on cycle */
+    unsigned short     arc_cyclecnt;   /* num cycles involved in */
+    unsigned short     arc_flags;      /* see below */
 };
 typedef struct arcstruct       arctype;
 
 };
 typedef struct arcstruct       arctype;
 
+    /*
+     * arc flags
+     */
+#define        DEADARC 0x01    /* time should not propagate across the arc */
+#define        ONLIST  0x02    /* arc is on list of arcs in cycles */
+
     /*
      * The symbol table;
      * for each external in the specified file we gather
     /*
      * The symbol table;
      * for each external in the specified file we gather
@@ -85,14 +94,17 @@ struct nl {
     double             time;           /* ticks in this routine */
     double             childtime;      /* cumulative ticks in children */
     long               ncall;          /* how many times called */
     double             time;           /* ticks in this routine */
     double             childtime;      /* cumulative ticks in children */
     long               ncall;          /* how many times called */
+    long               npropcall;      /* times called by live arcs */
     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 */
     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? */
+    short              printflag;      /* should this be printed? */
+    short              flags;          /* see below */
     int                        index;          /* index in the graph list */
     int                        toporder;       /* graph call chain top-sort order */
     int                        cycleno;        /* internal number of cycle on */
     int                        index;          /* index in the graph list */
     int                        toporder;       /* graph call chain top-sort order */
     int                        cycleno;        /* internal number of cycle on */
+    int                        parentcnt;      /* number of live parent arcs */
     struct nl          *cyclehead;     /* pointer to head of cycle */
     struct nl          *cnext;         /* pointer to next member of cycle */
     arctype            *parents;       /* list of caller arcs */
     struct nl          *cyclehead;     /* pointer to head of cycle */
     struct nl          *cnext;         /* pointer to next member of cycle */
     arctype            *parents;       /* list of caller arcs */
@@ -104,6 +116,28 @@ nltype     *nl;                    /* the whole namelist */
 nltype *npe;                   /* the virtual end of the namelist */
 int    nname;                  /* the number of function names */
 
 nltype *npe;                   /* the virtual end of the namelist */
 int    nname;                  /* the number of function names */
 
+#define        HASCYCLEXIT     0x08    /* node has arc exiting from cycle */
+#define        CYCLEHEAD       0x10    /* node marked as head of a cycle */
+#define        VISITED         0x20    /* node visited during a cycle */
+
+    /*
+     * The cycle list.
+     * for each subcycle within an identified cycle, we gather
+     * its size and the list of included arcs.
+     */
+struct cl {
+    int                size;           /* length of cycle */
+    struct cl  *next;          /* next member of list */
+    arctype    *list[1];       /* list of arcs in cycle */
+    /* actually longer */
+};
+typedef struct cl cltype;
+
+arctype        *archead;               /* the head of arcs in current cycle list */
+cltype *cyclehead;             /* the head of the list */
+int    cyclecnt;               /* the number of cycles found */
+#define        CYCLEMAX        100     /* maximum cycles before cutting one of them */
+
     /*
      * flag which marks a nl entry as topologically ``busy''
      * flag which marks a nl entry as topologically ``not_numbered''
     /*
      * flag which marks a nl entry as topologically ``busy''
      * flag which marks a nl entry as topologically ``not_numbered''
@@ -155,7 +189,8 @@ double      scale;                  /* scale factor converting samples to pc
 char   *strtab;                /* string table in core */
 off_t  ssiz;                   /* size of the string table */
 struct exec xbuf;              /* exec header of a.out */
 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 */
+unsigned char  *textspace;     /* text space of a.out in core */
+int    cyclethreshold;         /* with -C, minimum cycle size to ignore */
 
     /*
      * option flags, from a to z.
 
     /*
      * option flags, from a to z.
@@ -163,6 +198,7 @@ unsigned char       *textspace;             /* text space of a.out in core */
 bool   aflag;                          /* suppress static functions */
 bool   bflag;                          /* blurbs, too */
 bool   cflag;                          /* discovered call graph, too */
 bool   aflag;                          /* suppress static functions */
 bool   bflag;                          /* blurbs, too */
 bool   cflag;                          /* discovered call graph, too */
+bool   Cflag;                          /* find cut-set to eliminate cycles */
 bool   dflag;                          /* debugging options */
 bool   eflag;                          /* specific functions excluded */
 bool   Eflag;                          /* functions excluded with time */
 bool   dflag;                          /* debugging options */
 bool   eflag;                          /* specific functions excluded */
 bool   Eflag;                          /* functions excluded with time */
@@ -274,4 +310,6 @@ int         totalcmp();
 #define        CALLDEBUG       128
 #define        LOOKUPDEBUG     256
 #define        PROPDEBUG       512
 #define        CALLDEBUG       128
 #define        LOOKUPDEBUG     256
 #define        PROPDEBUG       512
-#define        ANYDEBUG        1024
+#define        BREAKCYCLE      1024
+#define        SUBCYCLELIST    2048
+#define        ANYDEBUG        4096
index a4ccfe7..592a406 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)printgprof.c       5.7 (Berkeley) %G%";
+static char sccsid[] = "@(#)printgprof.c       5.8 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "gprof.h"
 #endif /* not lint */
 
 #include "gprof.h"
@@ -148,7 +148,7 @@ gprofline( np )
            np -> propself / hz ,
            np -> propchild / hz );
     if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
            np -> propself / hz ,
            np -> propchild / hz );
     if ( ( np -> ncall + np -> selfcalls ) != 0 ) {
-       printf( " %7d" , np -> ncall );
+       printf( " %7d" , np -> npropcall );
        if ( np -> selfcalls != 0 ) {
            printf( "+%-7d " , np -> selfcalls );
        } else {
        if ( np -> selfcalls != 0 ) {
            printf( "+%-7d " , np -> selfcalls );
        } else {
@@ -263,7 +263,7 @@ printparents( childp )
     sortparents( childp );
     for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
        parentp = arcp -> arc_parentp;
     sortparents( childp );
     for ( arcp = childp -> parents ; arcp ; arcp = arcp -> arc_parentlist ) {
        parentp = arcp -> arc_parentp;
-       if ( childp == parentp ||
+       if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) ||
             ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
                /*
                 *      selfcall or call among siblings
             ( childp->cycleno != 0 && parentp->cycleno == childp->cycleno ) ) {
                /*
                 *      selfcall or call among siblings
@@ -280,7 +280,7 @@ printparents( childp )
            printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
                    "" , "" ,
                    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
            printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
                    "" , "" ,
                    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
-                   arcp -> arc_count , cycleheadp -> ncall );
+                   arcp -> arc_count , cycleheadp -> npropcall );
            printname( parentp );
            printf( "\n" );
        }
            printname( parentp );
            printf( "\n" );
        }
@@ -297,7 +297,7 @@ printchildren( parentp )
     arcp = parentp -> children;
     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
        childp = arcp -> arc_childp;
     arcp = parentp -> children;
     for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
        childp = arcp -> arc_childp;
-       if ( childp == parentp ||
+       if ( childp == parentp || ( arcp -> arc_flags & DEADARC ) ||
            ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
                /*
                 *      self call or call to sibling
            ( childp->cycleno != 0 && childp->cycleno == parentp->cycleno ) ) {
                /*
                 *      self call or call to sibling
@@ -313,7 +313,7 @@ printchildren( parentp )
            printf( "%6.6s %5.5s %7.2f %11.2f %7d/%-7d     " ,
                    "" , "" ,
                    arcp -> arc_time / hz , arcp -> arc_childtime / hz ,
            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 );
+                   arcp -> arc_count , childp -> cyclehead -> npropcall );
            printname( childp );
            printf( "\n" );
        }
            printname( childp );
            printf( "\n" );
        }
@@ -441,7 +441,7 @@ printcycle( cyclep )
            100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
            cyclep -> propself / hz ,
            cyclep -> propchild / hz ,
            100 * ( cyclep -> propself + cyclep -> propchild ) / printtime ,
            cyclep -> propself / hz ,
            cyclep -> propchild / hz ,
-           cyclep -> ncall );
+           cyclep -> npropcall );
     if ( cyclep -> selfcalls != 0 ) {
        printf( "+%-7d" , cyclep -> selfcalls );
     } else {
     if ( cyclep -> selfcalls != 0 ) {
        printf( "+%-7d" , cyclep -> selfcalls );
     } else {
@@ -463,7 +463,7 @@ printmembers( 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 ,
     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 );
+               memberp -> npropcall );
        if ( memberp -> selfcalls != 0 ) {
            printf( "+%-7d" , memberp -> selfcalls );
        } else {
        if ( memberp -> selfcalls != 0 ) {
            printf( "+%-7d" , memberp -> selfcalls );
        } else {