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

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