[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.23

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