date and time created 88/12/22 13:04:38 by sam
[unix-history] / usr / src / usr.bin / gprof / gprof.c
index 50c9fbb..a683863 100644 (file)
@@ -1,6 +1,29 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not 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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
 #ifndef lint
 #ifndef lint
-    static     char *sccsid = "@(#)gprof.c     1.15 (Berkeley) %G%";
-#endif 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.5 (Berkeley) %G%";
+#endif /* not lint */
 
 #include "gprof.h"
 
 
 #include "gprof.h"
 
@@ -16,10 +39,12 @@ main(argc, argv)
     char **argv;
 {
     char       **sp;
     char **argv;
 {
     char       **sp;
+    nltype     **timesortnlp;
 
     --argc;
     argv++;
     debug = 0;
 
     --argc;
     argv++;
     debug = 0;
+    bflag = TRUE;
     while ( *argv != 0 && **argv == '-' ) {
        (*argv)++;
        switch ( **argv ) {
     while ( *argv != 0 && **argv == '-' ) {
        (*argv)++;
        switch ( **argv ) {
@@ -27,7 +52,7 @@ main(argc, argv)
            aflag = TRUE;
            break;
        case 'b':
            aflag = TRUE;
            break;
        case 'b':
-           bflag = TRUE;
+           bflag = FALSE;
            break;
        case 'c':
            cflag = TRUE;
            break;
        case 'c':
            cflag = TRUE;
@@ -38,7 +63,9 @@ main(argc, argv)
            debug |= atoi( *argv );
            debug |= ANYDEBUG;
 #          ifdef DEBUG
            debug |= atoi( *argv );
            debug |= ANYDEBUG;
 #          ifdef DEBUG
-               printf( "[main] debug = %d\n" , debug );
+               printf("[main] debug = %d\n", debug);
+#          else not DEBUG
+               printf("%s: -d ignored\n", whoami);
 #          endif DEBUG
            break;
        case 'E':
 #          endif DEBUG
            break;
        case 'E':
@@ -63,6 +90,11 @@ main(argc, argv)
            addlist( flist , *++argv );
            fflag = TRUE;
            break;
            addlist( flist , *++argv );
            fflag = TRUE;
            break;
+       case 'k':
+           addlist( kfromlist , *++argv );
+           addlist( ktolist , *++argv );
+           kflag = TRUE;
+           break;
        case 's':
            sflag = TRUE;
            break;
        case 's':
            sflag = TRUE;
            break;
@@ -92,6 +124,15 @@ main(argc, argv)
        addlist( Elist , *sp );
        eflag = TRUE;
        addlist( elist , *sp );
        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.
     }
        /*
         *      get information about a.out file.
@@ -117,13 +158,21 @@ main(argc, argv)
         */
     asgnsamples();
        /*
         */
     asgnsamples();
        /*
-        *      print the usual profile
+        *      assemble the dynamic profile
+        */
+    timesortnlp = doarcs();
+       /*
+        *      print the dynamic profile
+        */
+    printgprof( timesortnlp ); 
+       /*
+        *      print the flat profile
         */
     printprof();       
        /*
         */
     printprof();       
        /*
-        *      assemble and print the dynamic profile
+        *      print the index
         */
         */
-    doarcs();
+    printindex();      
     done();
 }
 
     done();
 }
 
@@ -135,6 +184,7 @@ main(argc, argv)
 getnfile()
 {
     FILE       *nfile;
 getnfile()
 {
     FILE       *nfile;
+    int                valcmp();
 
     nfile = fopen( a_outname ,"r");
     if (nfile == NULL) {
 
     nfile = fopen( a_outname ,"r");
     if (nfile == NULL) {
@@ -244,7 +294,6 @@ getsymtab(nfile)
        nname++;
     }
     npe->value = -1;
        nname++;
     }
     npe->value = -1;
-    npe++;
 }
 
     /*
 }
 
     /*
@@ -253,12 +302,12 @@ getsymtab(nfile)
 gettextspace( nfile )
     FILE       *nfile;
 {
 gettextspace( nfile )
     FILE       *nfile;
 {
-    unsigned char      *malloc();
+    char       *malloc();
     
     if ( cflag == 0 ) {
        return;
     }
     
     if ( cflag == 0 ) {
        return;
     }
-    textspace = malloc( xbuf.a_text );
+    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 );
     if ( textspace == 0 ) {
        fprintf( stderr , "%s: ran out room for %d bytes of text space:  " ,
                        whoami , xbuf.a_text );
@@ -327,10 +376,10 @@ openpfile(filename)
     h = tmp;
     s_lowpc = (unsigned long) h.lowpc;
     s_highpc = (unsigned long) h.highpc;
     h = tmp;
     s_lowpc = (unsigned long) h.lowpc;
     s_highpc = (unsigned long) h.highpc;
-    lowpc = h.lowpc - (UNIT *)0;
-    highpc = h.highpc - (UNIT *)0;
+    lowpc = (unsigned long)h.lowpc / sizeof(UNIT);
+    highpc = (unsigned long)h.highpc / sizeof(UNIT);
     sampbytes = h.ncnt - sizeof(struct hdr);
     sampbytes = h.ncnt - sizeof(struct hdr);
-    nsamples = sampbytes / sizeof (unsigned UNIT);
+    nsamples = sampbytes / sizeof (UNIT);
 #   ifdef DEBUG
        if ( debug & SAMPLEDEBUG ) {
            printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
 #   ifdef DEBUG
        if ( debug & SAMPLEDEBUG ) {
            printf( "[openpfile] hdr.lowpc 0x%x hdr.highpc 0x%x hdr.ncnt %d\n",
@@ -354,6 +403,11 @@ tally( rawp )
 
     parentp = nllookup( rawp -> raw_frompc );
     childp = nllookup( rawp -> raw_selfpc );
 
     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 ) {
     childp -> ncall += rawp -> raw_count;
 #   ifdef DEBUG
        if ( debug & TALLYDEBUG ) {
@@ -389,14 +443,14 @@ dumpsum( sumfile )
     /*
      * dump the samples
      */
     /*
      * dump the samples
      */
-    if (fwrite(samples, sizeof(unsigned UNIT), nsamples, sfile) != nsamples) {
+    if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) {
        perror( sumfile );
        done();
     }
     /*
      * dump the normalized raw arc information
      */
        perror( sumfile );
        done();
     }
     /*
      * dump the normalized raw arc information
      */
-    for ( nlp = nl ; nlp < npe - 1 ; nlp++ ) {
+    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;
        for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
            arc.raw_frompc = arcp -> arc_parentp -> value;
            arc.raw_selfpc = arcp -> arc_childp -> value;
@@ -432,18 +486,18 @@ readsamples(pfile)
     FILE       *pfile;
 {
     register i;
     FILE       *pfile;
 {
     register i;
-    unsigned UNIT      sample;
+    UNIT       sample;
     
     if (samples == 0) {
     
     if (samples == 0) {
-       samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
+       samples = (UNIT *) calloc(sampbytes, sizeof (UNIT));
        if (samples == 0) {
            fprintf( stderr , "%s: No room for %d sample pc's\n", 
        if (samples == 0) {
            fprintf( stderr , "%s: No room for %d sample pc's\n", 
-               whoami , sampbytes / sizeof (unsigned UNIT));
+               whoami , sampbytes / sizeof (UNIT));
            done();
        }
     }
     for (i = 0; i < nsamples; i++) {
            done();
        }
     }
     for (i = 0; i < nsamples; i++) {
-       fread(&sample, sizeof (unsigned UNIT), 1, pfile);
+       fread(&sample, sizeof (UNIT), 1, pfile);
        if (feof(pfile))
                break;
        samples[i] += sample;
        if (feof(pfile))
                break;
        samples[i] += sample;
@@ -457,12 +511,41 @@ readsamples(pfile)
 }
 
 /*
 }
 
 /*
- * Assign samples to the procedures to which they belong.
+ *     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;
  */
 asgnsamples()
 {
     register int       j;
-    unsigned UNIT      ccnt;
+    UNIT               ccnt;
     double             time;
     unsigned long      pcl, pch;
     register int       i;
     double             time;
     unsigned long      pcl, pch;
     register int       i;
@@ -472,12 +555,13 @@ asgnsamples()
     /* read samples and assign to namelist symbols */
     scale = highpc - lowpc;
     scale /= nsamples;
     /* read samples and assign to namelist symbols */
     scale = highpc - lowpc;
     scale /= nsamples;
-    for (i=0; i < nsamples; i++) {
+    alignentries();
+    for (i = 0, j = 1; i < nsamples; i++) {
        ccnt = samples[i];
        if (ccnt == 0)
                continue;
        ccnt = samples[i];
        if (ccnt == 0)
                continue;
-       pcl = lowpc + scale*i;
-       pch = lowpc + scale*(i+1);
+       pcl = lowpc + scale * i;
+       pch = lowpc + scale * (i + 1);
        time = ccnt;
 #      ifdef DEBUG
            if ( debug & SAMPLEDEBUG ) {
        time = ccnt;
 #      ifdef DEBUG
            if ( debug & SAMPLEDEBUG ) {
@@ -486,29 +570,38 @@ asgnsamples()
            }
 #      endif DEBUG
        totime += time;
            }
 #      endif DEBUG
        totime += time;
-       for (j=0; j<nname; j++) {
-           svalue0 = nl[j].value / sizeof(UNIT);
-           svalue1 = nl[j+1].value / sizeof(UNIT);
+       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 (pch < svalue0)
                    break;
+               /*
+                *      if low end of tick into next routine,
+                *      go for next routine.
+                */
            if (pcl >= svalue1)
                    continue;
            if (pcl >= svalue1)
                    continue;
-           overlap=min(pch,svalue1) - max(pcl,svalue0);
-           if (overlap>0) {
+           overlap = min(pch, svalue1) - max(pcl, svalue0);
+           if (overlap > 0) {
 #              ifdef DEBUG
 #              ifdef DEBUG
-                   if ( debug & SAMPLEDEBUG ) {
-                       printf( "[asgnsamples] (0x%x-0x%x) %s gets %f ticks\n" ,
-                               svalue0 , svalue1 , nl[j].name , 
-                               overlap*time/scale );
+                   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
                    }
 #              endif DEBUG
-               nl[j].time += overlap*time/scale;
+               nl[j].time += overlap * time / scale;
            }
        }
     }
 #   ifdef DEBUG
            }
        }
     }
 #   ifdef DEBUG
-       if ( debug & SAMPLEDEBUG ) {
-           printf( "[asgnsamples] totime %f\n" , totime );
+       if (debug & SAMPLEDEBUG) {
+           printf("[asgnsamples] totime %f\n", totime);
        }
 #   endif DEBUG
 }
        }
 #   endif DEBUG
 }
@@ -532,6 +625,34 @@ max(a, b)
     return(b);
 }
 
     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;
 bool
 funcsymbol( nlistp )
     struct nlist       *nlistp;