[BACK]Return to gprof.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / gprof

Annotation of src/usr.bin/gprof/gprof.c, Revision 1.14

1.14    ! art         1: /*     $OpenBSD: gprof.c,v 1.13 2003/06/10 22:20:47 deraadt Exp $      */
1.1       deraadt     2: /*     $NetBSD: gprof.c,v 1.8 1995/04/19 07:15:59 cgd Exp $    */
                      3:
                      4: /*
                      5:  * Copyright (c) 1983, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
1.12      millert    16:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: #ifndef lint
                     34: static char copyright[] =
                     35: "@(#) Copyright (c) 1983, 1993\n\
                     36:        The Regents of the University of California.  All rights reserved.\n";
                     37: #endif /* not lint */
                     38:
                     39: #ifndef lint
                     40: #if 0
                     41: static char sccsid[] = "@(#)gprof.c    8.1 (Berkeley) 6/6/93";
                     42: #else
1.14    ! art        43: static char rcsid[] = "$OpenBSD: gprof.c,v 1.13 2003/06/10 22:20:47 deraadt Exp $";
1.1       deraadt    44: #endif
                     45: #endif /* not lint */
                     46:
                     47: #include "gprof.h"
                     48:
1.11      art        49: int valcmp(const void *, const void *);
1.1       deraadt    50:
                     51: static struct gmonhdr  gmonhdr;
1.8       mickey     52: extern char *__progname;
1.1       deraadt    53:
1.7       mickey     54: int
1.13      deraadt    55: main(int argc, char *argv[])
1.1       deraadt    56: {
                     57:     char       **sp;
                     58:     nltype     **timesortnlp;
1.11      art        59:     char       **defaultEs;
1.1       deraadt    60:
                     61:     --argc;
                     62:     argv++;
                     63:     debug = 0;
                     64:     bflag = TRUE;
                     65:     while ( *argv != 0 && **argv == '-' ) {
                     66:        (*argv)++;
                     67:        switch ( **argv ) {
                     68:        case 'a':
                     69:            aflag = TRUE;
                     70:            break;
                     71:        case 'b':
                     72:            bflag = FALSE;
                     73:            break;
                     74:        case 'C':
                     75:            Cflag = TRUE;
                     76:            cyclethreshold = atoi( *++argv );
                     77:            break;
                     78:        case 'c':
1.5       deraadt    79: #if defined(__i386__) || defined(__vax__) || defined(__tahoe__) || defined(__sparc__)
1.1       deraadt    80:            cflag = TRUE;
                     81: #else
1.7       mickey     82:            fprintf(stderr, "%s: -c isn't supported on this architecture yet\n", __progname);
1.1       deraadt    83:            exit(1);
                     84: #endif
                     85:            break;
                     86:        case 'd':
                     87:            dflag = TRUE;
                     88:            setlinebuf(stdout);
                     89:            debug |= atoi( *++argv );
                     90:            debug |= ANYDEBUG;
                     91: #          ifdef DEBUG
                     92:                printf("[main] debug = %d\n", debug);
1.10      danh       93: #          else /* not DEBUG */
1.7       mickey     94:                warnx("-d ignored");
1.10      danh       95: #          endif /* DEBUG */
1.1       deraadt    96:            break;
                     97:        case 'E':
                     98:            ++argv;
                     99:            addlist( Elist , *argv );
                    100:            Eflag = TRUE;
                    101:            addlist( elist , *argv );
                    102:            eflag = TRUE;
                    103:            break;
                    104:        case 'e':
                    105:            addlist( elist , *++argv );
                    106:            eflag = TRUE;
                    107:            break;
                    108:        case 'F':
                    109:            ++argv;
                    110:            addlist( Flist , *argv );
                    111:            Fflag = TRUE;
                    112:            addlist( flist , *argv );
                    113:            fflag = TRUE;
                    114:            break;
                    115:        case 'f':
                    116:            addlist( flist , *++argv );
                    117:            fflag = TRUE;
                    118:            break;
                    119:        case 'k':
                    120:            addlist( kfromlist , *++argv );
                    121:            addlist( ktolist , *++argv );
                    122:            kflag = TRUE;
                    123:            break;
                    124:        case 's':
                    125:            sflag = TRUE;
                    126:            break;
                    127:        case 'z':
                    128:            zflag = TRUE;
                    129:            break;
                    130:        }
                    131:        argv++;
                    132:     }
                    133:     if ( *argv != 0 ) {
                    134:        a_outname  = *argv;
                    135:        argv++;
                    136:     } else {
                    137:        a_outname  = A_OUTNAME;
                    138:     }
                    139:     if ( *argv != 0 ) {
                    140:        gmonname = *argv;
                    141:        argv++;
                    142:     } else {
                    143:        gmonname = GMONNAME;
                    144:     }
                    145:        /*
1.11      art       146:         *      get information about a.out file.
                    147:         */
                    148:     if (getnfile(a_outname, &defaultEs) == -1)
                    149:        errx(1, "%s: bad format", a_outname);
                    150:        /*
                    151:         *      sort symbol table.
                    152:         */
                    153:     qsort(nl, nname, sizeof(nltype), valcmp);
                    154:        /*
1.1       deraadt   155:         *      turn off default functions
                    156:         */
                    157:     for ( sp = &defaultEs[0] ; *sp ; sp++ ) {
                    158:        Eflag = TRUE;
                    159:        addlist( Elist , *sp );
                    160:        eflag = TRUE;
                    161:        addlist( elist , *sp );
                    162:     }
                    163:        /*
                    164:         *      get information about mon.out file(s).
                    165:         */
                    166:     do {
                    167:        getpfile( gmonname );
                    168:        if ( *argv != 0 ) {
                    169:            gmonname = *argv;
                    170:        }
                    171:     } while ( *argv++ != 0 );
                    172:        /*
                    173:         *      how many ticks per second?
                    174:         *      if we can't tell, report time in ticks.
                    175:         */
                    176:     if (hz == 0) {
                    177:        hz = 1;
1.7       mickey    178:        warnx("time is in ticks, not seconds");
1.1       deraadt   179:     }
                    180:        /*
                    181:         *      dump out a gmon.sum file if requested
                    182:         */
                    183:     if ( sflag ) {
                    184:        dumpsum( GMONSUM );
                    185:     }
                    186:        /*
                    187:         *      assign samples to procedures
                    188:         */
                    189:     asgnsamples();
                    190:        /*
                    191:         *      assemble the dynamic profile
                    192:         */
                    193:     timesortnlp = doarcs();
                    194:        /*
                    195:         *      print the dynamic profile
                    196:         */
                    197:     printgprof( timesortnlp );
                    198:        /*
                    199:         *      print the flat profile
                    200:         */
                    201:     printprof();
                    202:        /*
                    203:         *      print the index
                    204:         */
                    205:     printindex();
1.7       mickey    206:
                    207:     return (0);
1.1       deraadt   208: }
                    209:
                    210:     /*
                    211:      * information from a gmon.out file is in two parts:
                    212:      * an array of sampling hits within pc ranges,
                    213:      * and the arcs.
                    214:      */
1.7       mickey    215: void
1.13      deraadt   216: getpfile(char *filename)
1.1       deraadt   217: {
                    218:     FILE               *pfile;
                    219:     FILE               *openpfile();
                    220:     struct rawarc      arc;
                    221:
                    222:     pfile = openpfile(filename);
                    223:     readsamples(pfile);
                    224:        /*
                    225:         *      the rest of the file consists of
                    226:         *      a bunch of <from,self,count> tuples.
                    227:         */
                    228:     while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
                    229: #      ifdef DEBUG
                    230:            if ( debug & SAMPLEDEBUG ) {
1.14    ! art       231:                printf( "[getpfile] frompc 0x%lx selfpc 0x%lx count %ld\n" ,
1.1       deraadt   232:                        arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
                    233:            }
1.10      danh      234: #      endif /* DEBUG */
1.1       deraadt   235:            /*
                    236:             *  add this arc
                    237:             */
                    238:        tally( &arc );
                    239:     }
                    240:     fclose(pfile);
                    241: }
                    242:
                    243: FILE *
1.13      deraadt   244: openpfile(char *filename)
1.1       deraadt   245: {
                    246:     struct gmonhdr     tmp;
                    247:     FILE               *pfile;
                    248:     int                        size;
                    249:     int                        rate;
                    250:
1.7       mickey    251:     if((pfile = fopen(filename, "r")) == NULL)
                    252:        err(1, "fopen: %s", filename);
1.1       deraadt   253:     fread(&tmp, sizeof(struct gmonhdr), 1, pfile);
                    254:     if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc ||
1.7       mickey    255:         tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt))
                    256:        errx(1, "%s: incompatible with first gmon file", filename);
1.1       deraadt   257:     gmonhdr = tmp;
                    258:     if ( gmonhdr.version == GMONVERSION ) {
                    259:        rate = gmonhdr.profrate;
                    260:        size = sizeof(struct gmonhdr);
                    261:     } else {
                    262:        fseek(pfile, sizeof(struct ophdr), SEEK_SET);
                    263:        size = sizeof(struct ophdr);
                    264:        gmonhdr.profrate = rate = hertz();
                    265:        gmonhdr.version = GMONVERSION;
                    266:     }
                    267:     if (hz == 0) {
                    268:        hz = rate;
1.7       mickey    269:     } else if (hz != rate)
                    270:        errx(1, "%s: profile clock rate (%d) incompatible with clock rate "
                    271:            "(%ld) in first gmon file", filename, rate, hz);
1.1       deraadt   272:     s_lowpc = (unsigned long) gmonhdr.lpc;
                    273:     s_highpc = (unsigned long) gmonhdr.hpc;
                    274:     lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT);
                    275:     highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT);
                    276:     sampbytes = gmonhdr.ncnt - size;
                    277:     nsamples = sampbytes / sizeof (UNIT);
                    278: #   ifdef DEBUG
                    279:        if ( debug & SAMPLEDEBUG ) {
1.14    ! art       280:            printf( "[openpfile] hdr.lpc 0x%lx hdr.hpc 0x%lx hdr.ncnt %d\n",
1.1       deraadt   281:                gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt );
1.14    ! art       282:            printf( "[openpfile]   s_lowpc 0x%lx   s_highpc 0x%lx\n" ,
1.1       deraadt   283:                s_lowpc , s_highpc );
1.14    ! art       284:            printf( "[openpfile]     lowpc 0x%lx     highpc 0x%lx\n" ,
1.1       deraadt   285:                lowpc , highpc );
                    286:            printf( "[openpfile] sampbytes %d nsamples %d\n" ,
                    287:                sampbytes , nsamples );
1.14    ! art       288:            printf( "[openpfile] sample rate %ld\n" , hz );
1.1       deraadt   289:        }
1.10      danh      290: #   endif /* DEBUG */
1.1       deraadt   291:     return(pfile);
                    292: }
                    293:
1.7       mickey    294: void
1.13      deraadt   295: tally(struct rawarc *rawp)
1.1       deraadt   296: {
                    297:     nltype             *parentp;
                    298:     nltype             *childp;
                    299:
                    300:     parentp = nllookup( rawp -> raw_frompc );
                    301:     childp = nllookup( rawp -> raw_selfpc );
                    302:     if ( parentp == 0 || childp == 0 )
                    303:        return;
                    304:     if ( kflag
                    305:         && onlist( kfromlist , parentp -> name )
                    306:         && onlist( ktolist , childp -> name ) ) {
                    307:        return;
                    308:     }
                    309:     childp -> ncall += rawp -> raw_count;
                    310: #   ifdef DEBUG
                    311:        if ( debug & TALLYDEBUG ) {
1.14    ! art       312:            printf( "[tally] arc from %s to %s traversed %ld times\n" ,
1.1       deraadt   313:                    parentp -> name , childp -> name , rawp -> raw_count );
                    314:        }
1.10      danh      315: #   endif /* DEBUG */
1.1       deraadt   316:     addarc( parentp , childp , rawp -> raw_count );
                    317: }
                    318:
                    319: /*
                    320:  * dump out the gmon.sum file
                    321:  */
1.7       mickey    322: void
1.13      deraadt   323: dumpsum(char *sumfile)
1.1       deraadt   324: {
1.9       mpech     325:     nltype *nlp;
                    326:     arctype *arcp;
1.1       deraadt   327:     struct rawarc arc;
                    328:     FILE *sfile;
                    329:
1.7       mickey    330:     if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL )
                    331:        err(1, "fopen: %s", sumfile);
1.1       deraadt   332:     /*
                    333:      * dump the header; use the last header read in
                    334:      */
1.7       mickey    335:     if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 )
                    336:        err(1, "fwrite: %s", sumfile);
1.1       deraadt   337:     /*
                    338:      * dump the samples
                    339:      */
1.7       mickey    340:     if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples)
                    341:        err(1, "fwrite: %s", sumfile);
1.1       deraadt   342:     /*
                    343:      * dump the normalized raw arc information
                    344:      */
                    345:     for ( nlp = nl ; nlp < npe ; nlp++ ) {
                    346:        for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
                    347:            arc.raw_frompc = arcp -> arc_parentp -> value;
                    348:            arc.raw_selfpc = arcp -> arc_childp -> value;
                    349:            arc.raw_count = arcp -> arc_count;
1.7       mickey    350:            if (fwrite ( &arc , sizeof arc , 1 , sfile ) != 1)
                    351:                err(1, "fwrite: %s", sumfile);
1.1       deraadt   352: #          ifdef DEBUG
                    353:                if ( debug & SAMPLEDEBUG ) {
1.14    ! art       354:                    printf( "[dumpsum] frompc 0x%lx selfpc 0x%lx count %ld\n" ,
1.1       deraadt   355:                            arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
                    356:                }
1.10      danh      357: #          endif /* DEBUG */
1.1       deraadt   358:        }
                    359:     }
                    360:     fclose( sfile );
                    361: }
                    362:
1.7       mickey    363: int
1.11      art       364: valcmp(const void *vp1, const void *vp2)
1.1       deraadt   365: {
1.11      art       366:     const nltype *p1 = vp1;
                    367:     const nltype *p2 = vp2;
                    368:
1.1       deraadt   369:     if ( p1 -> value < p2 -> value ) {
                    370:        return LESSTHAN;
                    371:     }
                    372:     if ( p1 -> value > p2 -> value ) {
                    373:        return GREATERTHAN;
                    374:     }
                    375:     return EQUALTO;
                    376: }
                    377:
1.7       mickey    378: void
1.13      deraadt   379: readsamples(FILE *pfile)
1.1       deraadt   380: {
                    381:     UNIT       sample;
1.9       mpech     382:     int i;
1.1       deraadt   383:
                    384:     if (samples == 0) {
                    385:        samples = (UNIT *) calloc(sampbytes, sizeof (UNIT));
1.7       mickey    386:        if (samples == 0)
1.14    ! art       387:            errx(1, "No room for %ld sample pc's", sampbytes / sizeof (UNIT));
1.1       deraadt   388:     }
                    389:     for (i = 0; i < nsamples; i++) {
                    390:        fread(&sample, sizeof (UNIT), 1, pfile);
                    391:        if (feof(pfile))
                    392:                break;
                    393:        samples[i] += sample;
                    394:     }
1.7       mickey    395:     if (i != nsamples)
                    396:        errx(1, "unexpected EOF after reading %d/%d samples", i, nsamples );
1.1       deraadt   397: }
                    398:
                    399: /*
                    400:  *     Assign samples to the procedures to which they belong.
                    401:  *
                    402:  *     There are three cases as to where pcl and pch can be
                    403:  *     with respect to the routine entry addresses svalue0 and svalue1
                    404:  *     as shown in the following diagram.  overlap computes the
                    405:  *     distance between the arrows, the fraction of the sample
                    406:  *     that is to be credited to the routine which starts at svalue0.
                    407:  *
                    408:  *         svalue0                                         svalue1
                    409:  *            |                                               |
                    410:  *            v                                               v
                    411:  *
                    412:  *            +-----------------------------------------------+
                    413:  *            |                                               |
                    414:  *       |  ->|    |<-         ->|         |<-         ->|    |<-  |
                    415:  *       |         |             |         |             |         |
                    416:  *       +---------+             +---------+             +---------+
                    417:  *
                    418:  *       ^         ^             ^         ^             ^         ^
                    419:  *       |         |             |         |             |         |
                    420:  *      pcl       pch           pcl       pch           pcl       pch
                    421:  *
                    422:  *     For the vax we assert that samples will never fall in the first
                    423:  *     two bytes of any routine, since that is the entry mask,
                    424:  *     thus we give call alignentries() to adjust the entry points if
                    425:  *     the entry mask falls in one bucket but the code for the routine
                    426:  *     doesn't start until the next bucket.  In conjunction with the
                    427:  *     alignment of routine addresses, this should allow us to have
                    428:  *     only one sample for every four bytes of text space and never
                    429:  *     have any overlap (the two end cases, above).
                    430:  */
1.7       mickey    431: void
1.13      deraadt   432: asgnsamples(void)
1.1       deraadt   433: {
1.9       mpech     434:     int        j;
1.1       deraadt   435:     UNIT               ccnt;
                    436:     double             time;
                    437:     unsigned long      pcl, pch;
1.9       mpech     438:     int        i;
1.1       deraadt   439:     unsigned long      overlap;
                    440:     unsigned long      svalue0, svalue1;
                    441:
                    442:     /* read samples and assign to namelist symbols */
                    443:     scale = highpc - lowpc;
                    444:     scale /= nsamples;
                    445:     alignentries();
                    446:     for (i = 0, j = 1; i < nsamples; i++) {
                    447:        ccnt = samples[i];
                    448:        if (ccnt == 0)
                    449:                continue;
                    450:        pcl = lowpc + scale * i;
                    451:        pch = lowpc + scale * (i + 1);
                    452:        time = ccnt;
                    453: #      ifdef DEBUG
                    454:            if ( debug & SAMPLEDEBUG ) {
1.14    ! art       455:                printf( "[asgnsamples] pcl 0x%lx pch 0x%lx ccnt %d\n" ,
1.1       deraadt   456:                        pcl , pch , ccnt );
                    457:            }
1.10      danh      458: #      endif /* DEBUG */
1.1       deraadt   459:        totime += time;
                    460:        for (j = j - 1; j < nname; j++) {
                    461:            svalue0 = nl[j].svalue;
                    462:            svalue1 = nl[j+1].svalue;
                    463:                /*
                    464:                 *      if high end of tick is below entry address,
                    465:                 *      go for next tick.
                    466:                 */
                    467:            if (pch < svalue0)
                    468:                    break;
                    469:                /*
                    470:                 *      if low end of tick into next routine,
                    471:                 *      go for next routine.
                    472:                 */
                    473:            if (pcl >= svalue1)
                    474:                    continue;
                    475:            overlap = min(pch, svalue1) - max(pcl, svalue0);
                    476:            if (overlap > 0) {
                    477: #              ifdef DEBUG
                    478:                    if (debug & SAMPLEDEBUG) {
1.14    ! art       479:                        printf("[asgnsamples] (0x%lx->0x%lx-0x%lx) %s gets %f ticks %ld overlap\n",
1.1       deraadt   480:                                nl[j].value/sizeof(UNIT), svalue0, svalue1,
                    481:                                nl[j].name,
                    482:                                overlap * time / scale, overlap);
                    483:                    }
1.10      danh      484: #              endif /* DEBUG */
1.1       deraadt   485:                nl[j].time += overlap * time / scale;
                    486:            }
                    487:        }
                    488:     }
                    489: #   ifdef DEBUG
                    490:        if (debug & SAMPLEDEBUG) {
                    491:            printf("[asgnsamples] totime %f\n", totime);
                    492:        }
1.10      danh      493: #   endif /* DEBUG */
1.1       deraadt   494: }
                    495:
                    496:
                    497: unsigned long
1.13      deraadt   498: min(unsigned long a, unsigned long b)
1.1       deraadt   499: {
                    500:     if (a<b)
                    501:        return(a);
                    502:     return(b);
                    503: }
                    504:
                    505: unsigned long
1.13      deraadt   506: max(unsigned long a, unsigned long b)
1.1       deraadt   507: {
                    508:     if (a>b)
                    509:        return(a);
                    510:     return(b);
                    511: }
                    512:
                    513:     /*
                    514:      * calculate scaled entry point addresses (to save time in asgnsamples),
                    515:      * and possibly push the scaled entry points over the entry mask,
                    516:      * if it turns out that the entry point is in one bucket and the code
                    517:      * for a routine is in the next bucket.
                    518:      */
1.7       mickey    519: void
1.13      deraadt   520: alignentries(void)
1.1       deraadt   521: {
1.9       mpech     522:     struct nl          *nlp;
1.1       deraadt   523:     unsigned long      bucket_of_entry;
                    524:     unsigned long      bucket_of_code;
                    525:
                    526:     for (nlp = nl; nlp < npe; nlp++) {
                    527:        nlp -> svalue = nlp -> value / sizeof(UNIT);
                    528:        bucket_of_entry = (nlp->svalue - lowpc) / scale;
                    529:        bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale;
                    530:        if (bucket_of_entry < bucket_of_code) {
                    531: #          ifdef DEBUG
                    532:                if (debug & SAMPLEDEBUG) {
1.14    ! art       533:                    printf("[alignentries] pushing svalue 0x%lx to 0x%lx\n",
1.1       deraadt   534:                            nlp->svalue, nlp->svalue + UNITS_TO_CODE);
                    535:                }
1.10      danh      536: #          endif /* DEBUG */
1.1       deraadt   537:            nlp->svalue += UNITS_TO_CODE;
                    538:        }
                    539:     }
                    540: }