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

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