Annotation of 43BSDReno/old/prof/prof.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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