gprof.c revision 2513
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1983, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 351590Srgrimesstatic char copyright[] = 361590Srgrimes"@(#) Copyright (c) 1983, 1993\n\ 371590Srgrimes The Regents of the University of California. All rights reserved.\n"; 381590Srgrimes#endif /* not lint */ 391590Srgrimes 401590Srgrimes#ifndef lint 411590Srgrimesstatic char sccsid[] = "@(#)gprof.c 8.1 (Berkeley) 6/6/93"; 421590Srgrimes#endif /* not lint */ 431590Srgrimes 441590Srgrimes#include "gprof.h" 451590Srgrimes 461590Srgrimeschar *whoami = "gprof"; 471590Srgrimes 481590Srgrimes /* 491590Srgrimes * things which get -E excluded by default. 501590Srgrimes */ 511590Srgrimeschar *defaultEs[] = { "mcount" , "__mcleanup" , 0 }; 521590Srgrimes 531590Srgrimesstatic struct gmonhdr gmonhdr; 542513Sbdestatic bool uflag; 551590Srgrimes 561590Srgrimesmain(argc, argv) 571590Srgrimes int argc; 581590Srgrimes char **argv; 591590Srgrimes{ 601590Srgrimes char **sp; 611590Srgrimes nltype **timesortnlp; 621590Srgrimes 631590Srgrimes --argc; 641590Srgrimes argv++; 651590Srgrimes debug = 0; 661590Srgrimes bflag = TRUE; 671590Srgrimes while ( *argv != 0 && **argv == '-' ) { 681590Srgrimes (*argv)++; 691590Srgrimes switch ( **argv ) { 701590Srgrimes case 'a': 711590Srgrimes aflag = TRUE; 721590Srgrimes break; 731590Srgrimes case 'b': 741590Srgrimes bflag = FALSE; 751590Srgrimes break; 761590Srgrimes case 'C': 771590Srgrimes Cflag = TRUE; 781590Srgrimes cyclethreshold = atoi( *++argv ); 791590Srgrimes break; 801590Srgrimes case 'c': 811590Srgrimes#if defined(vax) || defined(tahoe) 821590Srgrimes cflag = TRUE; 831590Srgrimes#else 841590Srgrimes fprintf(stderr, "gprof: -c isn't supported on this architecture yet\n"); 851590Srgrimes exit(1); 861590Srgrimes#endif 871590Srgrimes break; 881590Srgrimes case 'd': 891590Srgrimes dflag = TRUE; 901590Srgrimes setlinebuf(stdout); 911590Srgrimes debug |= atoi( *++argv ); 921590Srgrimes debug |= ANYDEBUG; 931590Srgrimes# ifdef DEBUG 941590Srgrimes printf("[main] debug = %d\n", debug); 951590Srgrimes# else not DEBUG 961590Srgrimes printf("%s: -d ignored\n", whoami); 971590Srgrimes# endif DEBUG 981590Srgrimes break; 991590Srgrimes case 'E': 1001590Srgrimes ++argv; 1011590Srgrimes addlist( Elist , *argv ); 1021590Srgrimes Eflag = TRUE; 1031590Srgrimes addlist( elist , *argv ); 1041590Srgrimes eflag = TRUE; 1051590Srgrimes break; 1061590Srgrimes case 'e': 1071590Srgrimes addlist( elist , *++argv ); 1081590Srgrimes eflag = TRUE; 1091590Srgrimes break; 1101590Srgrimes case 'F': 1111590Srgrimes ++argv; 1121590Srgrimes addlist( Flist , *argv ); 1131590Srgrimes Fflag = TRUE; 1141590Srgrimes addlist( flist , *argv ); 1151590Srgrimes fflag = TRUE; 1161590Srgrimes break; 1171590Srgrimes case 'f': 1181590Srgrimes addlist( flist , *++argv ); 1191590Srgrimes fflag = TRUE; 1201590Srgrimes break; 1211590Srgrimes case 'k': 1221590Srgrimes addlist( kfromlist , *++argv ); 1231590Srgrimes addlist( ktolist , *++argv ); 1241590Srgrimes kflag = TRUE; 1251590Srgrimes break; 1261590Srgrimes case 's': 1271590Srgrimes sflag = TRUE; 1281590Srgrimes break; 1292513Sbde case 'u': 1302513Sbde uflag = TRUE; 1312513Sbde break; 1321590Srgrimes case 'z': 1331590Srgrimes zflag = TRUE; 1341590Srgrimes break; 1351590Srgrimes } 1361590Srgrimes argv++; 1371590Srgrimes } 1381590Srgrimes if ( *argv != 0 ) { 1391590Srgrimes a_outname = *argv; 1401590Srgrimes argv++; 1411590Srgrimes } else { 1421590Srgrimes a_outname = A_OUTNAME; 1431590Srgrimes } 1441590Srgrimes if ( *argv != 0 ) { 1451590Srgrimes gmonname = *argv; 1461590Srgrimes argv++; 1471590Srgrimes } else { 1481590Srgrimes gmonname = GMONNAME; 1491590Srgrimes } 1501590Srgrimes /* 1511590Srgrimes * turn off default functions 1521590Srgrimes */ 1531590Srgrimes for ( sp = &defaultEs[0] ; *sp ; sp++ ) { 1541590Srgrimes Eflag = TRUE; 1551590Srgrimes addlist( Elist , *sp ); 1561590Srgrimes eflag = TRUE; 1571590Srgrimes addlist( elist , *sp ); 1581590Srgrimes } 1591590Srgrimes /* 1601590Srgrimes * get information about a.out file. 1611590Srgrimes */ 1621590Srgrimes getnfile(); 1631590Srgrimes /* 1641590Srgrimes * get information about mon.out file(s). 1651590Srgrimes */ 1661590Srgrimes do { 1671590Srgrimes getpfile( gmonname ); 1681590Srgrimes if ( *argv != 0 ) { 1691590Srgrimes gmonname = *argv; 1701590Srgrimes } 1711590Srgrimes } while ( *argv++ != 0 ); 1721590Srgrimes /* 1731590Srgrimes * how many ticks per second? 1741590Srgrimes * if we can't tell, report time in ticks. 1751590Srgrimes */ 1761590Srgrimes if (hz == 0) { 1771590Srgrimes hz = 1; 1781590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 1791590Srgrimes } 1801590Srgrimes /* 1811590Srgrimes * dump out a gmon.sum file if requested 1821590Srgrimes */ 1831590Srgrimes if ( sflag ) { 1841590Srgrimes dumpsum( GMONSUM ); 1851590Srgrimes } 1861590Srgrimes /* 1871590Srgrimes * assign samples to procedures 1881590Srgrimes */ 1891590Srgrimes asgnsamples(); 1901590Srgrimes /* 1911590Srgrimes * assemble the dynamic profile 1921590Srgrimes */ 1931590Srgrimes timesortnlp = doarcs(); 1941590Srgrimes /* 1951590Srgrimes * print the dynamic profile 1961590Srgrimes */ 1971590Srgrimes printgprof( timesortnlp ); 1981590Srgrimes /* 1991590Srgrimes * print the flat profile 2001590Srgrimes */ 2011590Srgrimes printprof(); 2021590Srgrimes /* 2031590Srgrimes * print the index 2041590Srgrimes */ 2051590Srgrimes printindex(); 2061590Srgrimes done(); 2071590Srgrimes} 2081590Srgrimes 2091590Srgrimes /* 2101590Srgrimes * Set up string and symbol tables from a.out. 2111590Srgrimes * and optionally the text space. 2121590Srgrimes * On return symbol table is sorted by value. 2131590Srgrimes */ 2141590Srgrimesgetnfile() 2151590Srgrimes{ 2161590Srgrimes FILE *nfile; 2171590Srgrimes int valcmp(); 2181590Srgrimes 2191590Srgrimes nfile = fopen( a_outname ,"r"); 2201590Srgrimes if (nfile == NULL) { 2211590Srgrimes perror( a_outname ); 2221590Srgrimes done(); 2231590Srgrimes } 2241590Srgrimes fread(&xbuf, 1, sizeof(xbuf), nfile); 2251590Srgrimes if (N_BADMAG(xbuf)) { 2261590Srgrimes fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); 2271590Srgrimes done(); 2281590Srgrimes } 2291590Srgrimes getstrtab(nfile); 2301590Srgrimes getsymtab(nfile); 2311590Srgrimes gettextspace( nfile ); 2321590Srgrimes qsort(nl, nname, sizeof(nltype), valcmp); 2331590Srgrimes fclose(nfile); 2341590Srgrimes# ifdef DEBUG 2351590Srgrimes if ( debug & AOUTDEBUG ) { 2361590Srgrimes register int j; 2371590Srgrimes 2381590Srgrimes for (j = 0; j < nname; j++){ 2391590Srgrimes printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 2401590Srgrimes } 2411590Srgrimes } 2421590Srgrimes# endif DEBUG 2431590Srgrimes} 2441590Srgrimes 2451590Srgrimesgetstrtab(nfile) 2461590Srgrimes FILE *nfile; 2471590Srgrimes{ 2481590Srgrimes 2491590Srgrimes fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 2501590Srgrimes if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 2511590Srgrimes fprintf(stderr, "%s: %s: no string table (old format?)\n" , 2521590Srgrimes whoami , a_outname ); 2531590Srgrimes done(); 2541590Srgrimes } 2551590Srgrimes strtab = calloc(ssiz, 1); 2561590Srgrimes if (strtab == NULL) { 2571590Srgrimes fprintf(stderr, "%s: %s: no room for %d bytes of string table\n", 2581590Srgrimes whoami , a_outname , ssiz); 2591590Srgrimes done(); 2601590Srgrimes } 2611590Srgrimes if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 2621590Srgrimes fprintf(stderr, "%s: %s: error reading string table\n", 2631590Srgrimes whoami , a_outname ); 2641590Srgrimes done(); 2651590Srgrimes } 2661590Srgrimes} 2671590Srgrimes 2681590Srgrimes /* 2691590Srgrimes * Read in symbol table 2701590Srgrimes */ 2711590Srgrimesgetsymtab(nfile) 2721590Srgrimes FILE *nfile; 2731590Srgrimes{ 2741590Srgrimes register long i; 2751590Srgrimes int askfor; 2761590Srgrimes struct nlist nbuf; 2771590Srgrimes 2781590Srgrimes /* pass1 - count symbols */ 2791590Srgrimes fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2801590Srgrimes nname = 0; 2811590Srgrimes for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2821590Srgrimes fread(&nbuf, sizeof(nbuf), 1, nfile); 2831590Srgrimes if ( ! funcsymbol( &nbuf ) ) { 2841590Srgrimes continue; 2851590Srgrimes } 2861590Srgrimes nname++; 2871590Srgrimes } 2881590Srgrimes if (nname == 0) { 2891590Srgrimes fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); 2901590Srgrimes done(); 2911590Srgrimes } 2921590Srgrimes askfor = nname + 1; 2931590Srgrimes nl = (nltype *) calloc( askfor , sizeof(nltype) ); 2941590Srgrimes if (nl == 0) { 2951590Srgrimes fprintf(stderr, "%s: No room for %d bytes of symbol table\n", 2961590Srgrimes whoami, askfor * sizeof(nltype) ); 2971590Srgrimes done(); 2981590Srgrimes } 2991590Srgrimes 3001590Srgrimes /* pass2 - read symbols */ 3011590Srgrimes fseek(nfile, (long)N_SYMOFF(xbuf), 0); 3021590Srgrimes npe = nl; 3031590Srgrimes nname = 0; 3041590Srgrimes for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 3051590Srgrimes fread(&nbuf, sizeof(nbuf), 1, nfile); 3061590Srgrimes if ( ! funcsymbol( &nbuf ) ) { 3071590Srgrimes# ifdef DEBUG 3081590Srgrimes if ( debug & AOUTDEBUG ) { 3091590Srgrimes printf( "[getsymtab] rejecting: 0x%x %s\n" , 3101590Srgrimes nbuf.n_type , strtab + nbuf.n_un.n_strx ); 3111590Srgrimes } 3121590Srgrimes# endif DEBUG 3131590Srgrimes continue; 3141590Srgrimes } 3151590Srgrimes npe->value = nbuf.n_value; 3161590Srgrimes npe->name = strtab+nbuf.n_un.n_strx; 3171590Srgrimes# ifdef DEBUG 3181590Srgrimes if ( debug & AOUTDEBUG ) { 3191590Srgrimes printf( "[getsymtab] %d %s 0x%08x\n" , 3201590Srgrimes nname , npe -> name , npe -> value ); 3211590Srgrimes } 3221590Srgrimes# endif DEBUG 3231590Srgrimes npe++; 3241590Srgrimes nname++; 3251590Srgrimes } 3261590Srgrimes npe->value = -1; 3271590Srgrimes} 3281590Srgrimes 3291590Srgrimes /* 3301590Srgrimes * read in the text space of an a.out file 3311590Srgrimes */ 3321590Srgrimesgettextspace( nfile ) 3331590Srgrimes FILE *nfile; 3341590Srgrimes{ 3351590Srgrimes 3361590Srgrimes if ( cflag == 0 ) { 3371590Srgrimes return; 3381590Srgrimes } 3391590Srgrimes textspace = (u_char *) malloc( xbuf.a_text ); 3401590Srgrimes if ( textspace == 0 ) { 3411590Srgrimes fprintf( stderr , "%s: ran out room for %d bytes of text space: " , 3421590Srgrimes whoami , xbuf.a_text ); 3431590Srgrimes fprintf( stderr , "can't do -c\n" ); 3441590Srgrimes return; 3451590Srgrimes } 3461590Srgrimes (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 3471590Srgrimes if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 3481590Srgrimes fprintf( stderr , "%s: couldn't read text space: " , whoami ); 3491590Srgrimes fprintf( stderr , "can't do -c\n" ); 3501590Srgrimes free( textspace ); 3511590Srgrimes textspace = 0; 3521590Srgrimes return; 3531590Srgrimes } 3541590Srgrimes} 3551590Srgrimes /* 3561590Srgrimes * information from a gmon.out file is in two parts: 3571590Srgrimes * an array of sampling hits within pc ranges, 3581590Srgrimes * and the arcs. 3591590Srgrimes */ 3601590Srgrimesgetpfile(filename) 3611590Srgrimes char *filename; 3621590Srgrimes{ 3631590Srgrimes FILE *pfile; 3641590Srgrimes FILE *openpfile(); 3651590Srgrimes struct rawarc arc; 3661590Srgrimes 3671590Srgrimes pfile = openpfile(filename); 3681590Srgrimes readsamples(pfile); 3691590Srgrimes /* 3701590Srgrimes * the rest of the file consists of 3711590Srgrimes * a bunch of <from,self,count> tuples. 3721590Srgrimes */ 3731590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 3741590Srgrimes# ifdef DEBUG 3751590Srgrimes if ( debug & SAMPLEDEBUG ) { 3761590Srgrimes printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 3771590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3781590Srgrimes } 3791590Srgrimes# endif DEBUG 3801590Srgrimes /* 3811590Srgrimes * add this arc 3821590Srgrimes */ 3831590Srgrimes tally( &arc ); 3841590Srgrimes } 3851590Srgrimes fclose(pfile); 3861590Srgrimes} 3871590Srgrimes 3881590SrgrimesFILE * 3891590Srgrimesopenpfile(filename) 3901590Srgrimes char *filename; 3911590Srgrimes{ 3921590Srgrimes struct gmonhdr tmp; 3931590Srgrimes FILE *pfile; 3941590Srgrimes int size; 3951590Srgrimes int rate; 3961590Srgrimes 3971590Srgrimes if((pfile = fopen(filename, "r")) == NULL) { 3981590Srgrimes perror(filename); 3991590Srgrimes done(); 4001590Srgrimes } 4011590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 4021590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 4031590Srgrimes tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { 4041590Srgrimes fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 4051590Srgrimes done(); 4061590Srgrimes } 4071590Srgrimes gmonhdr = tmp; 4081590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 4091590Srgrimes rate = gmonhdr.profrate; 4101590Srgrimes size = sizeof(struct gmonhdr); 4111590Srgrimes } else { 4121590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 4131590Srgrimes size = sizeof(struct ophdr); 4141590Srgrimes gmonhdr.profrate = rate = hertz(); 4151590Srgrimes gmonhdr.version = GMONVERSION; 4161590Srgrimes } 4171590Srgrimes if (hz == 0) { 4181590Srgrimes hz = rate; 4191590Srgrimes } else if (hz != rate) { 4201590Srgrimes fprintf(stderr, 4211590Srgrimes "%s: profile clock rate (%d) %s (%d) in first gmon file\n", 4221590Srgrimes filename, rate, "incompatible with clock rate", hz); 4231590Srgrimes done(); 4241590Srgrimes } 4251590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 4261590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 4271590Srgrimes lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT); 4281590Srgrimes highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT); 4291590Srgrimes sampbytes = gmonhdr.ncnt - size; 4301590Srgrimes nsamples = sampbytes / sizeof (UNIT); 4311590Srgrimes# ifdef DEBUG 4321590Srgrimes if ( debug & SAMPLEDEBUG ) { 4331590Srgrimes printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n", 4341590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 4351590Srgrimes printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , 4361590Srgrimes s_lowpc , s_highpc ); 4371590Srgrimes printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , 4381590Srgrimes lowpc , highpc ); 4391590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 4401590Srgrimes sampbytes , nsamples ); 4411590Srgrimes printf( "[openpfile] sample rate %d\n" , hz ); 4421590Srgrimes } 4431590Srgrimes# endif DEBUG 4441590Srgrimes return(pfile); 4451590Srgrimes} 4461590Srgrimes 4471590Srgrimestally( rawp ) 4481590Srgrimes struct rawarc *rawp; 4491590Srgrimes{ 4501590Srgrimes nltype *parentp; 4511590Srgrimes nltype *childp; 4521590Srgrimes 4531590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 4541590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 4551590Srgrimes if ( parentp == 0 || childp == 0 ) 4561590Srgrimes return; 4571590Srgrimes if ( kflag 4581590Srgrimes && onlist( kfromlist , parentp -> name ) 4591590Srgrimes && onlist( ktolist , childp -> name ) ) { 4601590Srgrimes return; 4611590Srgrimes } 4621590Srgrimes childp -> ncall += rawp -> raw_count; 4631590Srgrimes# ifdef DEBUG 4641590Srgrimes if ( debug & TALLYDEBUG ) { 4651590Srgrimes printf( "[tally] arc from %s to %s traversed %d times\n" , 4661590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 4671590Srgrimes } 4681590Srgrimes# endif DEBUG 4691590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 4701590Srgrimes} 4711590Srgrimes 4721590Srgrimes/* 4731590Srgrimes * dump out the gmon.sum file 4741590Srgrimes */ 4751590Srgrimesdumpsum( sumfile ) 4761590Srgrimes char *sumfile; 4771590Srgrimes{ 4781590Srgrimes register nltype *nlp; 4791590Srgrimes register arctype *arcp; 4801590Srgrimes struct rawarc arc; 4811590Srgrimes FILE *sfile; 4821590Srgrimes 4831590Srgrimes if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 4841590Srgrimes perror( sumfile ); 4851590Srgrimes done(); 4861590Srgrimes } 4871590Srgrimes /* 4881590Srgrimes * dump the header; use the last header read in 4891590Srgrimes */ 4901590Srgrimes if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { 4911590Srgrimes perror( sumfile ); 4921590Srgrimes done(); 4931590Srgrimes } 4941590Srgrimes /* 4951590Srgrimes * dump the samples 4961590Srgrimes */ 4971590Srgrimes if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) { 4981590Srgrimes perror( sumfile ); 4991590Srgrimes done(); 5001590Srgrimes } 5011590Srgrimes /* 5021590Srgrimes * dump the normalized raw arc information 5031590Srgrimes */ 5041590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 5051590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 5061590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 5071590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 5081590Srgrimes arc.raw_count = arcp -> arc_count; 5091590Srgrimes if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 5101590Srgrimes perror( sumfile ); 5111590Srgrimes done(); 5121590Srgrimes } 5131590Srgrimes# ifdef DEBUG 5141590Srgrimes if ( debug & SAMPLEDEBUG ) { 5151590Srgrimes printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 5161590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 5171590Srgrimes } 5181590Srgrimes# endif DEBUG 5191590Srgrimes } 5201590Srgrimes } 5211590Srgrimes fclose( sfile ); 5221590Srgrimes} 5231590Srgrimes 5241590Srgrimesvalcmp(p1, p2) 5251590Srgrimes nltype *p1, *p2; 5261590Srgrimes{ 5271590Srgrimes if ( p1 -> value < p2 -> value ) { 5281590Srgrimes return LESSTHAN; 5291590Srgrimes } 5301590Srgrimes if ( p1 -> value > p2 -> value ) { 5311590Srgrimes return GREATERTHAN; 5321590Srgrimes } 5331590Srgrimes return EQUALTO; 5341590Srgrimes} 5351590Srgrimes 5361590Srgrimesreadsamples(pfile) 5371590Srgrimes FILE *pfile; 5381590Srgrimes{ 5391590Srgrimes register i; 5401590Srgrimes UNIT sample; 5411590Srgrimes 5421590Srgrimes if (samples == 0) { 5431590Srgrimes samples = (UNIT *) calloc(sampbytes, sizeof (UNIT)); 5441590Srgrimes if (samples == 0) { 5451590Srgrimes fprintf( stderr , "%s: No room for %d sample pc's\n", 5461590Srgrimes whoami , sampbytes / sizeof (UNIT)); 5471590Srgrimes done(); 5481590Srgrimes } 5491590Srgrimes } 5501590Srgrimes for (i = 0; i < nsamples; i++) { 5511590Srgrimes fread(&sample, sizeof (UNIT), 1, pfile); 5521590Srgrimes if (feof(pfile)) 5531590Srgrimes break; 5541590Srgrimes samples[i] += sample; 5551590Srgrimes } 5561590Srgrimes if (i != nsamples) { 5571590Srgrimes fprintf(stderr, 5581590Srgrimes "%s: unexpected EOF after reading %d/%d samples\n", 5591590Srgrimes whoami , --i , nsamples ); 5601590Srgrimes done(); 5611590Srgrimes } 5621590Srgrimes} 5631590Srgrimes 5641590Srgrimes/* 5651590Srgrimes * Assign samples to the procedures to which they belong. 5661590Srgrimes * 5671590Srgrimes * There are three cases as to where pcl and pch can be 5681590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 5691590Srgrimes * as shown in the following diagram. overlap computes the 5701590Srgrimes * distance between the arrows, the fraction of the sample 5711590Srgrimes * that is to be credited to the routine which starts at svalue0. 5721590Srgrimes * 5731590Srgrimes * svalue0 svalue1 5741590Srgrimes * | | 5751590Srgrimes * v v 5761590Srgrimes * 5771590Srgrimes * +-----------------------------------------------+ 5781590Srgrimes * | | 5791590Srgrimes * | ->| |<- ->| |<- ->| |<- | 5801590Srgrimes * | | | | | | 5811590Srgrimes * +---------+ +---------+ +---------+ 5821590Srgrimes * 5831590Srgrimes * ^ ^ ^ ^ ^ ^ 5841590Srgrimes * | | | | | | 5851590Srgrimes * pcl pch pcl pch pcl pch 5861590Srgrimes * 5871590Srgrimes * For the vax we assert that samples will never fall in the first 5881590Srgrimes * two bytes of any routine, since that is the entry mask, 5891590Srgrimes * thus we give call alignentries() to adjust the entry points if 5901590Srgrimes * the entry mask falls in one bucket but the code for the routine 5911590Srgrimes * doesn't start until the next bucket. In conjunction with the 5921590Srgrimes * alignment of routine addresses, this should allow us to have 5931590Srgrimes * only one sample for every four bytes of text space and never 5941590Srgrimes * have any overlap (the two end cases, above). 5951590Srgrimes */ 5961590Srgrimesasgnsamples() 5971590Srgrimes{ 5981590Srgrimes register int j; 5991590Srgrimes UNIT ccnt; 6001590Srgrimes double time; 6011590Srgrimes unsigned long pcl, pch; 6021590Srgrimes register int i; 6031590Srgrimes unsigned long overlap; 6041590Srgrimes unsigned long svalue0, svalue1; 6051590Srgrimes 6061590Srgrimes /* read samples and assign to namelist symbols */ 6071590Srgrimes scale = highpc - lowpc; 6081590Srgrimes scale /= nsamples; 6091590Srgrimes alignentries(); 6101590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 6111590Srgrimes ccnt = samples[i]; 6121590Srgrimes if (ccnt == 0) 6131590Srgrimes continue; 6141590Srgrimes pcl = lowpc + scale * i; 6151590Srgrimes pch = lowpc + scale * (i + 1); 6161590Srgrimes time = ccnt; 6171590Srgrimes# ifdef DEBUG 6181590Srgrimes if ( debug & SAMPLEDEBUG ) { 6191590Srgrimes printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 6201590Srgrimes pcl , pch , ccnt ); 6211590Srgrimes } 6221590Srgrimes# endif DEBUG 6231590Srgrimes totime += time; 6241590Srgrimes for (j = j - 1; j < nname; j++) { 6251590Srgrimes svalue0 = nl[j].svalue; 6261590Srgrimes svalue1 = nl[j+1].svalue; 6271590Srgrimes /* 6281590Srgrimes * if high end of tick is below entry address, 6291590Srgrimes * go for next tick. 6301590Srgrimes */ 6311590Srgrimes if (pch < svalue0) 6321590Srgrimes break; 6331590Srgrimes /* 6341590Srgrimes * if low end of tick into next routine, 6351590Srgrimes * go for next routine. 6361590Srgrimes */ 6371590Srgrimes if (pcl >= svalue1) 6381590Srgrimes continue; 6391590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 6401590Srgrimes if (overlap > 0) { 6411590Srgrimes# ifdef DEBUG 6421590Srgrimes if (debug & SAMPLEDEBUG) { 6431590Srgrimes printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n", 6441590Srgrimes nl[j].value/sizeof(UNIT), svalue0, svalue1, 6451590Srgrimes nl[j].name, 6461590Srgrimes overlap * time / scale, overlap); 6471590Srgrimes } 6481590Srgrimes# endif DEBUG 6491590Srgrimes nl[j].time += overlap * time / scale; 6501590Srgrimes } 6511590Srgrimes } 6521590Srgrimes } 6531590Srgrimes# ifdef DEBUG 6541590Srgrimes if (debug & SAMPLEDEBUG) { 6551590Srgrimes printf("[asgnsamples] totime %f\n", totime); 6561590Srgrimes } 6571590Srgrimes# endif DEBUG 6581590Srgrimes} 6591590Srgrimes 6601590Srgrimes 6611590Srgrimesunsigned long 6621590Srgrimesmin(a, b) 6631590Srgrimes unsigned long a,b; 6641590Srgrimes{ 6651590Srgrimes if (a<b) 6661590Srgrimes return(a); 6671590Srgrimes return(b); 6681590Srgrimes} 6691590Srgrimes 6701590Srgrimesunsigned long 6711590Srgrimesmax(a, b) 6721590Srgrimes unsigned long a,b; 6731590Srgrimes{ 6741590Srgrimes if (a>b) 6751590Srgrimes return(a); 6761590Srgrimes return(b); 6771590Srgrimes} 6781590Srgrimes 6791590Srgrimes /* 6801590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 6811590Srgrimes * and possibly push the scaled entry points over the entry mask, 6821590Srgrimes * if it turns out that the entry point is in one bucket and the code 6831590Srgrimes * for a routine is in the next bucket. 6841590Srgrimes */ 6851590Srgrimesalignentries() 6861590Srgrimes{ 6871590Srgrimes register struct nl *nlp; 6881590Srgrimes unsigned long bucket_of_entry; 6891590Srgrimes unsigned long bucket_of_code; 6901590Srgrimes 6911590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 6921590Srgrimes nlp -> svalue = nlp -> value / sizeof(UNIT); 6931590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 6941590Srgrimes bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; 6951590Srgrimes if (bucket_of_entry < bucket_of_code) { 6961590Srgrimes# ifdef DEBUG 6971590Srgrimes if (debug & SAMPLEDEBUG) { 6981590Srgrimes printf("[alignentries] pushing svalue 0x%x to 0x%x\n", 6991590Srgrimes nlp->svalue, nlp->svalue + UNITS_TO_CODE); 7001590Srgrimes } 7011590Srgrimes# endif DEBUG 7021590Srgrimes nlp->svalue += UNITS_TO_CODE; 7031590Srgrimes } 7041590Srgrimes } 7051590Srgrimes} 7061590Srgrimes 7071590Srgrimesbool 7081590Srgrimesfuncsymbol( nlistp ) 7091590Srgrimes struct nlist *nlistp; 7101590Srgrimes{ 7111590Srgrimes char *name, c; 7121590Srgrimes 7131590Srgrimes /* 7141590Srgrimes * must be a text symbol, 7151590Srgrimes * and static text symbols don't qualify if aflag set. 7161590Srgrimes */ 7171590Srgrimes if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 7181590Srgrimes || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 7191590Srgrimes return FALSE; 7201590Srgrimes } 7211590Srgrimes /* 7222513Sbde * name must start with an underscore if uflag is set. 7231590Srgrimes * can't have any `funny' characters in name, 7241590Srgrimes * where `funny' includes `.', .o file names 7251590Srgrimes * and `$', pascal labels. 7261590Srgrimes * need to make an exception for sparc .mul & co. 7271590Srgrimes * perhaps we should just drop this code entirely... 7281590Srgrimes */ 7291590Srgrimes name = strtab + nlistp -> n_un.n_strx; 7302513Sbde if ( uflag && *name != '_' ) 7312513Sbde return FALSE; 7321590Srgrimes#ifdef sparc 7331590Srgrimes if ( *name == '.' ) { 7341590Srgrimes char *p = name + 1; 7351590Srgrimes if ( *p == 'u' ) 7361590Srgrimes p++; 7371590Srgrimes if ( strcmp ( p, "mul" ) == 0 || strcmp ( p, "div" ) == 0 || 7381590Srgrimes strcmp ( p, "rem" ) == 0 ) 7391590Srgrimes return TRUE; 7401590Srgrimes } 7411590Srgrimes#endif 7421590Srgrimes while ( c = *name++ ) { 7431590Srgrimes if ( c == '.' || c == '$' ) { 7441590Srgrimes return FALSE; 7451590Srgrimes } 7461590Srgrimes } 7471590Srgrimes return TRUE; 7481590Srgrimes} 7491590Srgrimes 7501590Srgrimesdone() 7511590Srgrimes{ 7521590Srgrimes 7531590Srgrimes exit(0); 7541590Srgrimes} 755