Annotation of 41BSD/cmd/prof/prof.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * prof
                      3:  */
                      4: #include <stdio.h>
                      5: #include <sys/types.h>
                      6: #include <sys/stat.h>
                      7: #include <a.out.h>
                      8: #include <pagsiz.h>
                      9: 
                     10: typedef        short UNIT;             /* unit of profiling */
                     11: #define        A_OUTNAME       "a.out"
                     12: #define        MON_OUTNAME     "mon.out"
                     13: #define        MON_SUMNAME     "mon.sum"
                     14: 
                     15: /*
                     16:  * The symbol table;
                     17:  * for each external in the specified file we gather
                     18:  * its address, the number of calls and compute its share of cpu time.
                     19:  */
                     20: struct nl {
                     21:        char    *name;
                     22:        unsigned value;
                     23:        float   time;
                     24:        long    ncall;
                     25: } *nl;
                     26: int    nname;
                     27: struct nl *np;
                     28: struct nl *npe;
                     29: 
                     30: /*
                     31:  * The header on the mon.out file.
                     32:  * Mon.out consists of one of these headers, an array of ncount
                     33:  * cnt structures (as below) and then an array of samples
                     34:  * representing the discretized program counter values.
                     35:  */
                     36: struct hdr {
                     37:        UNIT    *lowpc, *highpc;
                     38:        int     ncount;
                     39: } h;
                     40: 
                     41: /*
                     42:  * Each counter has an address and a number of calls.
                     43:  */
                     44: struct cnt {
                     45:        unsigned cvalue;
                     46:        long    cncall;
                     47: } *cbuf;
                     48: 
                     49: /*
                     50:  * Each discretized pc sample has
                     51:  * a count of the number of samples in its range
                     52:  */
                     53: unsigned UNIT  *samples;
                     54: 
                     55: FILE   *pfile, *nfile;
                     56: 
                     57: unsigned lowpc, highpc;                /* range profiled */
                     58: double ransca, ranoff;         /* scaling for blowing up plots */
                     59: unsigned sampbytes;            /* number of bytes of samples */
                     60: int    nsamples;               /* number of samples */
                     61: double totime;                 /* total time for all routines */
                     62: double maxtime;                /* maximum time of any routine (for plot) */
                     63: double scale;                  /* scale factor converting samples to pc
                     64:                                   values: each sample covers scale bytes */
                     65: char   *strtab;                /* string table in core */
                     66: off_t  ssiz;                   /* size of the string table */
                     67: struct exec xbuf;              /* exec header of a.out */
                     68: 
                     69: int    aflg;
                     70: int    nflg;
                     71: int    vflg;
                     72: int    lflg;
                     73: int    zflg;
                     74: int    sflag;
                     75: 
                     76: char   *namfil;
                     77: 
                     78: int    timcmp(), valcmp(), cntcmp();
                     79: 
                     80: main(argc, argv)
                     81:        char **argv;
                     82: {
                     83:        int lowpct, highpct;
                     84: 
                     85:        /*
                     86:         * Use highpct and lowpc as percentages, temporarily
                     87:         * for graphing options involving blow-up
                     88:         */
                     89:        lowpct = -1;
                     90:        highpct = -1;
                     91:        argv++;
                     92:        while ( *argv != 0 && **argv == '-' ) {
                     93:                *argv += 1;
                     94:                if (**argv == 'l')
                     95:                        lflg++;
                     96:                else if (**argv == 'a')
                     97:                        aflg++;
                     98:                else if (**argv == 'n')
                     99:                        nflg++;
                    100:                else if (**argv == 'z')
                    101:                        zflg++;
                    102:                else if (**argv == 'v')
                    103:                        vflg++;
                    104:                else if ( **argv == 's' )
                    105:                        sflag++;
                    106:                else if (**argv >= '0' && **argv <= '9') {
                    107:                        int i = atoi(*argv);
                    108:                        if (lowpct == -1)
                    109:                                lowpct = i;
                    110:                        else
                    111:                                highpct = i;
                    112:                }
                    113:                argv++;
                    114:        }
                    115:        if ( *argv != 0 ) {
                    116:                namfil = *argv;
                    117:                argv++;
                    118:        } else {
                    119:                namfil = A_OUTNAME;
                    120:        }
                    121:        if (lowpct >= 100)
                    122:                lowpct = 0;
                    123:        if (highpct <= lowpct || highpct > 100)
                    124:                highpct = 100;
                    125:        ransca = 100./(highpct-lowpct);
                    126:        ranoff = 2040. + 40.8*lowpc*ransca;
                    127:                /*
                    128:                 *      get information about a.out file.
                    129:                 */
                    130:        getnfile();
                    131:                /*
                    132:                 *      get information about mon.out file(s).
                    133:                 */
                    134:        if ( *argv == 0 ) {
                    135:                getpfile( MON_OUTNAME );
                    136:        } else {
                    137:                do {
                    138:                        getpfile( *argv );
                    139:                        argv++;
                    140:                } while ( *argv != 0 );
                    141:        }
                    142:        asgnsamples();          /* assign samples to procedures */
                    143: #ifdef plot
                    144:        if (vflag)
                    145:                plotprof();     /* a plotted or ... */
                    146:        else
                    147: #else
                    148:                printprof();    /* a printed profile */
                    149: #endif
                    150:        if ( sflag != 0 ) {
                    151:                putprof();
                    152:        }
                    153:        done();
                    154: }
                    155: 
                    156: printprof()
                    157: {
                    158:        double time, actime;
                    159: 
                    160:        actime = 0;
                    161:        printf(" %%time  cumsecs  #call  ms/call  name\n");
                    162:        if (!lflg)
                    163:                qsort(nl, nname, sizeof(struct nl), timcmp);
                    164:        for (np = nl; np<npe-1; np++) {
                    165:                if (zflg == 0 && np->time == 0 && np->ncall == 0)
                    166:                        continue;
                    167:                time = np->time/totime;
                    168:                actime += np->time;
                    169:                printf("%6.1f%9.2f", 100*time, actime/60);
                    170:                if (np->ncall != 0)
                    171:                        printf("%7ld %8.2f",
                    172:                            np->ncall, np->time/(np->ncall*.06));
                    173:                else
                    174:                        printf("%7.7s %8.8s", "", "");
                    175:                printf("  %s\n", np->name);
                    176:        }
                    177: }
                    178: 
                    179: /*
                    180:  * Set up string and symbol tables from a.out.
                    181:  * On return symbol table is sorted by value.
                    182:  */
                    183: getnfile()
                    184: {
                    185: 
                    186:        nfile = fopen(namfil,"r");
                    187:        if (nfile == NULL) {
                    188:                perror(namfil);
                    189:                done();
                    190:        }
                    191:        fread(&xbuf, 1, sizeof(xbuf), nfile);
                    192:        if (N_BADMAG(xbuf)) {
                    193:                fprintf(stderr, "%s: bad format\n", namfil);
                    194:                done();
                    195:        }
                    196:        getstrtab();
                    197:        getsymtab();
                    198:        qsort(nl, nname, sizeof(struct nl), valcmp);
                    199: }
                    200: 
                    201: getstrtab()
                    202: {
                    203: 
                    204:        fseek(nfile, N_SYMOFF(xbuf) + xbuf.a_syms, 0);
                    205:        if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
                    206:                fprintf(stderr, "%s: no string table (old format?)\n", namfil);
                    207:                done();
                    208:        }
                    209:        strtab = (char *)calloc(ssiz, 1);
                    210:        if (strtab == NULL) {
                    211:                fprintf(stderr, "%s: no room for %d bytes of string table",
                    212:                    namfil, ssiz);
                    213:                done();
                    214:        }
                    215:        if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
                    216:                fprintf(stderr, "%s: error reading string table\n", namfil);
                    217:                done();
                    218:        }
                    219: }
                    220: 
                    221: /*
                    222:  * Read in symbol table
                    223:  */
                    224: getsymtab()
                    225: {
                    226:        register int i;
                    227: 
                    228:        /* pass1 - count symbols */
                    229:        fseek(nfile, N_SYMOFF(xbuf), 0);
                    230:        nname = 0;
                    231:        for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
                    232:                struct nlist nbuf;
                    233:                fread(&nbuf, sizeof(nbuf), 1, nfile);
                    234:                if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
                    235:                        continue;
                    236:                if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
                    237:                        continue;
                    238:                nname++;
                    239:        }
                    240:        if (nname == 0) {
                    241:                fprintf(stderr, "%s: no symbols\n", namfil);
                    242:                done();
                    243:        }
                    244:        nl = (struct nl *)calloc((nname+1), sizeof (struct nl));
                    245:        if (nl == 0) {
                    246:                fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
                    247:                    (nname+1) * sizeof (struct nlist));
                    248:                done();
                    249:        }
                    250: 
                    251:        /* pass2 - read symbols */
                    252:        fseek(nfile, N_SYMOFF(xbuf), 0);
                    253:        npe = nl;
                    254:        nname = 0;
                    255:        for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
                    256:                struct nlist nbuf;
                    257:                fread(&nbuf, sizeof(nbuf), 1, nfile);
                    258:                if (nbuf.n_type!=N_TEXT && nbuf.n_type!=N_TEXT+N_EXT)
                    259:                        continue;
                    260:                if (aflg==0 && nbuf.n_type!=N_TEXT+N_EXT)
                    261:                        continue;
                    262:                npe->value = nbuf.n_value/sizeof(UNIT);
                    263:                npe->name = strtab+nbuf.n_un.n_strx;
                    264:                npe++;
                    265:                nname++;
                    266:        }
                    267:        npe->value = -1;
                    268:        npe++;
                    269: }
                    270: 
                    271:        /*
                    272:         *      information from a mon.out file is in two parts:
                    273:         *      the counters of how many times each procedure was called,
                    274:         *      if it was called at all;
                    275:         *      and an array of sampling hits within pc ranges.
                    276:         *      the counters must be dealt with on a file-by-file basis,
                    277:         *      since which procedures are represented may vary.
                    278:         *      the samples ranges are fixed, but must be summed across
                    279:         *      files, and then distributed amoung procedures, because
                    280:         *      of the wierd way the plotting is done.
                    281:         */
                    282: getpfile( filename )
                    283:        char    *filename;
                    284: {
                    285:        openpfile( filename );
                    286:        readcntrs();
                    287:        asgncntrs();            /* assign counts to procedures */
                    288:        readsamples();
                    289:        closepfile();
                    290: }
                    291: 
                    292: openpfile( filename )
                    293:        char    *filename;
                    294: {
                    295:        struct stat stb;
                    296: 
                    297:        if((pfile = fopen( filename ,"r")) == NULL) {
                    298:                perror( filename );
                    299:                done();
                    300:        }
                    301:        fstat(fileno(pfile), &stb);
                    302:        fread(&h, sizeof(struct hdr), 1, pfile);
                    303:        lowpc = h.lowpc - (UNIT *)0;
                    304:        highpc = h.highpc - (UNIT *)0;
                    305:        sampbytes =
                    306:            stb.st_size - sizeof(struct hdr) - h.ncount*sizeof(struct cnt);
                    307:        nsamples = sampbytes / sizeof (unsigned UNIT);
                    308: }
                    309: 
                    310: closepfile()
                    311: {
                    312: 
                    313:        fclose( pfile );
                    314:        free( cbuf );
                    315: }
                    316: 
                    317:        /*
                    318:         * read in procedure call counters
                    319:         */
                    320: readcntrs()
                    321: {
                    322:        struct cnt *kp;
                    323: 
                    324:        cbuf = (struct cnt *)calloc((h.ncount+1), sizeof (struct cnt));
                    325:        if (cbuf == 0) {
                    326:                fprintf(stderr, "prof: No room for %d bytes of count buffer\n",
                    327:                    (h.ncount+1) * sizeof (struct cnt));
                    328:                exit(1);
                    329:        }
                    330:        fread(cbuf, sizeof(struct cnt), h.ncount, pfile);
                    331:        /* eliminate zero counters and scale counter pc values */
                    332:        if (h.ncount) {
                    333:                kp = &cbuf[h.ncount - 1];
                    334:                for (;;) {
                    335:                        if (kp->cvalue==0) {
                    336:                                h.ncount=kp-cbuf;
                    337:                                ++kp;
                    338:                                break;
                    339:                        }
                    340:                        if (kp == cbuf) {
                    341:                                h.ncount = 0;
                    342:                                break;
                    343:                        }
                    344:                        --kp;
                    345:                }
                    346:                for (; --kp>=cbuf; )
                    347:                        kp->cvalue /= sizeof(UNIT);
                    348:        }
                    349:        /* sort counters */
                    350:        qsort(cbuf, h.ncount, sizeof(struct cnt), cntcmp);
                    351: }
                    352: 
                    353: /*
                    354:  * Assign counters to the procedures to which they belong
                    355:  */
                    356: asgncntrs()
                    357: {
                    358:        register int i;
                    359:        struct cnt *kp;
                    360: 
                    361:        kp = &cbuf[h.ncount-1];
                    362:        np = npe;
                    363:        while (--np>=nl) {
                    364:                if (kp<cbuf || np->value > kp->cvalue)
                    365:                        continue;
                    366:                while (kp >= cbuf && kp->cvalue - np->value > 11)
                    367:                        --kp;
                    368:                if (kp->cvalue >= np->value) {
                    369:                        np->ncall += kp->cncall;
                    370:                        --kp;
                    371:                }
                    372:        }
                    373: }
                    374: 
                    375:        /*
                    376:         *      read pc samples
                    377:         */
                    378: readsamples()
                    379: {
                    380:        register        i;
                    381:        unsigned UNIT   sample;
                    382:        
                    383:        if ( samples == 0 ) {
                    384:                samples = (unsigned UNIT *)
                    385:                                calloc( sampbytes , sizeof (unsigned UNIT) );
                    386:                if ( samples == 0 ) {
                    387:                        printf( "prof: No room for %d sample pc's\n" , 
                    388:                                sampbytes / sizeof (unsigned UNIT) );
                    389:                        done();
                    390:                }
                    391:        }
                    392:        for ( i = 0 ; ; i++ ) {
                    393:                fread( &sample , sizeof (unsigned UNIT) , 1 , pfile );
                    394:                if ( feof( pfile ) ) {
                    395:                        break;
                    396:                }
                    397:                samples[ i ] += sample;
                    398:        }
                    399:        if ( i != nsamples ) {
                    400:                fprintf( stderr ,
                    401:                        "prof: unexpected EOF after reading %d/%d samples\n" ,
                    402:                        --i , nsamples );
                    403:                done();
                    404:        }
                    405: }
                    406: /*
                    407:  * Assign samples to the procedures to which they belong.
                    408:  */
                    409: asgnsamples()
                    410: {
                    411:        register j;
                    412:        unsigned UNIT   ccnt;
                    413:        double time;
                    414:        unsigned pcl, pch;
                    415:        register int i;
                    416:        int overlap;
                    417: 
                    418:        /* read samples and assign to namelist symbols */
                    419:        scale = highpc - lowpc;
                    420:        scale /= nsamples;
                    421:        for(i=0 ; i < nsamples ; i++) {
                    422:                ccnt = samples[i];
                    423:                if (ccnt == 0)
                    424:                        continue;
                    425:                pcl = lowpc + scale*i;
                    426:                pch = lowpc + scale*(i+1);
                    427:                time = ccnt;
                    428:                totime += time;
                    429:                if(time > maxtime)
                    430:                        maxtime = time;
                    431:                for (j=0; j<nname; j++) {
                    432:                        if (pch < nl[j].value)
                    433:                                break;
                    434:                        if (pcl >= nl[j+1].value)
                    435:                                continue;
                    436:                        overlap=(min(pch,nl[j+1].value)-max(pcl,nl[j].value));
                    437:                        if (overlap>0)
                    438:                                nl[j].time += overlap*time/scale;
                    439:                }
                    440:        }
                    441:        if (totime==0.0) {
                    442:                fprintf(stderr, "No time accumulated\n");
                    443: /*
                    444:                done();
                    445:  */
                    446:                totime=1.0;
                    447:        }
                    448: }
                    449: 
                    450:        /*
                    451:         *      dump what you have out to a mon.out style file.
                    452:         */
                    453: putprof()
                    454: {
                    455:        FILE            *sfile;
                    456:        struct nl       *np;
                    457:        struct cnt      kp;
                    458:        int             i;
                    459: 
                    460:        sfile = fopen( MON_SUMNAME , "w" );
                    461:        if ( sfile == NULL ) {
                    462:                perror( MON_SUMNAME );
                    463:                done();
                    464:        }
                    465:                /*
                    466:                 *      build a new header.
                    467:                 *      h.lowpc and h.highpc are already fine.
                    468:                 *      fix h.ncount to count non-zero calls,
                    469:                 *      and the one zero call which marks the end.
                    470:                 */
                    471:        h.ncount = 0;
                    472:        for ( np = nl ; np < npe -1 ; np++ ) {
                    473:                if ( np -> ncall > 0 ) {
                    474:                        h.ncount++;
                    475:                }
                    476:        }
                    477:        h.ncount++;
                    478:        fwrite( &h , sizeof (struct hdr) , 1 , sfile );
                    479:                /*
                    480:                 *      write out the counters
                    481:                 */
                    482:        for ( np = nl ; np < npe - 1 ; np++ ) {
                    483:                if ( np -> ncall > 0 ) {
                    484:                        kp.cvalue = np -> value * sizeof (unsigned UNIT);
                    485:                        kp.cncall = np -> ncall;
                    486:                        fwrite( &kp , sizeof (struct cnt) , 1 , sfile );
                    487:                }
                    488:        }
                    489:        kp.cvalue = 0;
                    490:        kp.cncall = 0;
                    491:        fwrite( &kp , sizeof (struct cnt) , 1 , sfile );
                    492:                /*
                    493:                 *      write out the samples
                    494:                 */
                    495:        fwrite( samples , sizeof (unsigned UNIT) , nsamples , sfile );
                    496:        fclose( sfile );
                    497: }
                    498: 
                    499: min(a, b)
                    500: {
                    501:        if (a<b)
                    502:                return(a);
                    503:        return(b);
                    504: }
                    505: 
                    506: max(a, b)
                    507: {
                    508:        if (a>b)
                    509:                return(a);
                    510:        return(b);
                    511: }
                    512: 
                    513: valcmp(p1, p2)
                    514:        struct nl *p1, *p2;
                    515: {
                    516: 
                    517:        return(p1->value - p2->value);
                    518: }
                    519: 
                    520: timcmp(p1, p2)
                    521:        struct nl *p1, *p2;
                    522: {
                    523:        float d;
                    524: 
                    525:        if (nflg && p2->ncall != p1->ncall)
                    526:                return (p2->ncall - p1->ncall);
                    527:        d = p2->time - p1->time;
                    528:        if (d > 0.0)
                    529:                return(1);
                    530:        if (d < 0.0)
                    531:                return(-1);
                    532:        return(strcmp(p1->name,p2->name));
                    533: }
                    534: 
                    535: cntcmp(p1, p2)
                    536:        struct cnt *p1, *p2;
                    537: {
                    538: 
                    539:        return(p1->cvalue - p2->cvalue);
                    540: }
                    541: 
                    542: done()
                    543: {
                    544: 
                    545: #ifdef plot
                    546:        if(vflg) {
                    547:                point(0, -2040);
                    548:                closepl();
                    549:        }
                    550: #endif
                    551:        exit(0);
                    552: }
                    553: 
                    554: #ifdef plot
                    555: plotprof()
                    556: {
                    557:        double time, lastx, lasty, lastsx;
                    558:        register        i;
                    559: 
                    560:        openpl();
                    561:        erase();
                    562:        space(-2048, -2048, 2048, 2048);
                    563:        line(-2040, -2040, -2040, 2040);
                    564:        line(0, 2040, 0, -2040);
                    565:        for(i=0; i<11; i++)
                    566:                line(-2040, 2040-i*408, 0, 2040-i*408);
                    567:        lastx = 0.;
                    568:        lasty = ranoff;
                    569:        scale = (4080.*ransca)/(sampbytes/sizeof(UNIT));
                    570:        lastsx = 0.0;
                    571:        for(i = 0 ; i < nsamples ; i++ ) {
                    572:                unsigned UNIT ccnt;
                    573:                double tx, ty;
                    574:                ccnt = samples[i];
                    575:                time = ccnt;
                    576:                tx = lastsx;
                    577:                ty = lasty;
                    578:                lastsx =- 2000.*time/totime;
                    579:                lasty =- scale;
                    580:                if(lasty >= -2040. && ty <= 2040.) {
                    581:                        line((int)tx, (int)ty, (int)lastsx, (int)lasty);
                    582:                        if (ccnt!=0 || lastx!=0.0) {
                    583:                                tx = lastx;
                    584:                                lastx = -time*2000./maxtime;
                    585:                                ty =+ scale/2;
                    586:                                line(0, (int)ty, (int)tx, (int)ty);
                    587:                        }
                    588:                }
                    589:        }
                    590:        scale = (4080.*ransca)/(highpc-lowpc);
                    591:        lastx = 50.;
                    592:        for(np = nl; np<npe;  np++) {
                    593:                if(np->value < lowpc)
                    594:                        continue;
                    595:                if(np->value >= highpc)
                    596:                        continue;
                    597:                time = np->time/totime;
                    598:                lasty = ranoff - (np->value - lowpc)*scale;
                    599:                if(lasty >= -2040. && lasty <= 2040.) {
                    600:                        char bufl[BUFSIZ], *namp;
                    601:                        register j;
                    602:                        line(0, (int)lasty, 50, (int)lasty);
                    603:                        line((int)(lastx-50),(int)lasty,(int)lastx,(int)lasty);
                    604:                        point((int)(lastx+30), (int)(lasty+10));
                    605:                        sprintf(bufl, "%s\n", np->name + np->name[0] == '_');
                    606:                        label(bufl);
                    607:                }
                    608:                lastx =+ 500.;
                    609:                if(lastx > 2000.)
                    610:                        lastx = 50.;
                    611:        }
                    612: }
                    613: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.