gprof.c revision 8874
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; 555190Swollmanstatic int lflag; 565190Swollmanstatic int Lflag; 571590Srgrimes 581590Srgrimesmain(argc, argv) 591590Srgrimes int argc; 601590Srgrimes char **argv; 611590Srgrimes{ 621590Srgrimes char **sp; 631590Srgrimes nltype **timesortnlp; 641590Srgrimes 651590Srgrimes --argc; 661590Srgrimes argv++; 671590Srgrimes debug = 0; 681590Srgrimes bflag = TRUE; 691590Srgrimes while ( *argv != 0 && **argv == '-' ) { 701590Srgrimes (*argv)++; 711590Srgrimes switch ( **argv ) { 721590Srgrimes case 'a': 731590Srgrimes aflag = TRUE; 741590Srgrimes break; 751590Srgrimes case 'b': 761590Srgrimes bflag = FALSE; 771590Srgrimes break; 781590Srgrimes case 'C': 791590Srgrimes Cflag = TRUE; 801590Srgrimes cyclethreshold = atoi( *++argv ); 811590Srgrimes break; 821590Srgrimes case 'c': 831590Srgrimes#if defined(vax) || defined(tahoe) 841590Srgrimes cflag = TRUE; 851590Srgrimes#else 861590Srgrimes fprintf(stderr, "gprof: -c isn't supported on this architecture yet\n"); 871590Srgrimes exit(1); 881590Srgrimes#endif 891590Srgrimes break; 901590Srgrimes case 'd': 911590Srgrimes dflag = TRUE; 921590Srgrimes setlinebuf(stdout); 931590Srgrimes debug |= atoi( *++argv ); 941590Srgrimes debug |= ANYDEBUG; 951590Srgrimes# ifdef DEBUG 961590Srgrimes printf("[main] debug = %d\n", debug); 971590Srgrimes# else not DEBUG 981590Srgrimes printf("%s: -d ignored\n", whoami); 991590Srgrimes# endif DEBUG 1001590Srgrimes break; 1011590Srgrimes case 'E': 1021590Srgrimes ++argv; 1031590Srgrimes addlist( Elist , *argv ); 1041590Srgrimes Eflag = TRUE; 1051590Srgrimes addlist( elist , *argv ); 1061590Srgrimes eflag = TRUE; 1071590Srgrimes break; 1081590Srgrimes case 'e': 1091590Srgrimes addlist( elist , *++argv ); 1101590Srgrimes eflag = TRUE; 1111590Srgrimes break; 1121590Srgrimes case 'F': 1131590Srgrimes ++argv; 1141590Srgrimes addlist( Flist , *argv ); 1151590Srgrimes Fflag = TRUE; 1161590Srgrimes addlist( flist , *argv ); 1171590Srgrimes fflag = TRUE; 1181590Srgrimes break; 1191590Srgrimes case 'f': 1201590Srgrimes addlist( flist , *++argv ); 1211590Srgrimes fflag = TRUE; 1221590Srgrimes break; 1231590Srgrimes case 'k': 1241590Srgrimes addlist( kfromlist , *++argv ); 1251590Srgrimes addlist( ktolist , *++argv ); 1261590Srgrimes kflag = TRUE; 1271590Srgrimes break; 1285190Swollman case 'l': 1295190Swollman lflag = 1; 1305190Swollman Lflag = 0; 1315190Swollman break; 1325190Swollman case 'L': 1335190Swollman Lflag = 1; 1345190Swollman lflag = 0; 1355190Swollman break; 1365190Swollman case 's': 1371590Srgrimes sflag = TRUE; 1381590Srgrimes break; 1392513Sbde case 'u': 1402513Sbde uflag = TRUE; 1412513Sbde break; 1421590Srgrimes case 'z': 1431590Srgrimes zflag = TRUE; 1441590Srgrimes break; 1451590Srgrimes } 1461590Srgrimes argv++; 1471590Srgrimes } 1481590Srgrimes if ( *argv != 0 ) { 1491590Srgrimes a_outname = *argv; 1501590Srgrimes argv++; 1511590Srgrimes } else { 1521590Srgrimes a_outname = A_OUTNAME; 1531590Srgrimes } 1541590Srgrimes if ( *argv != 0 ) { 1551590Srgrimes gmonname = *argv; 1561590Srgrimes argv++; 1571590Srgrimes } else { 1581590Srgrimes gmonname = GMONNAME; 1591590Srgrimes } 1601590Srgrimes /* 1611590Srgrimes * turn off default functions 1621590Srgrimes */ 1631590Srgrimes for ( sp = &defaultEs[0] ; *sp ; sp++ ) { 1641590Srgrimes Eflag = TRUE; 1651590Srgrimes addlist( Elist , *sp ); 1661590Srgrimes eflag = TRUE; 1671590Srgrimes addlist( elist , *sp ); 1681590Srgrimes } 1691590Srgrimes /* 1701590Srgrimes * get information about a.out file. 1711590Srgrimes */ 1721590Srgrimes getnfile(); 1731590Srgrimes /* 1741590Srgrimes * get information about mon.out file(s). 1751590Srgrimes */ 1761590Srgrimes do { 1771590Srgrimes getpfile( gmonname ); 1781590Srgrimes if ( *argv != 0 ) { 1791590Srgrimes gmonname = *argv; 1801590Srgrimes } 1811590Srgrimes } while ( *argv++ != 0 ); 1821590Srgrimes /* 1831590Srgrimes * how many ticks per second? 1841590Srgrimes * if we can't tell, report time in ticks. 1851590Srgrimes */ 1861590Srgrimes if (hz == 0) { 1871590Srgrimes hz = 1; 1881590Srgrimes fprintf(stderr, "time is in ticks, not seconds\n"); 1891590Srgrimes } 1901590Srgrimes /* 1911590Srgrimes * dump out a gmon.sum file if requested 1921590Srgrimes */ 1931590Srgrimes if ( sflag ) { 1941590Srgrimes dumpsum( GMONSUM ); 1951590Srgrimes } 1961590Srgrimes /* 1971590Srgrimes * assign samples to procedures 1981590Srgrimes */ 1991590Srgrimes asgnsamples(); 2001590Srgrimes /* 2011590Srgrimes * assemble the dynamic profile 2021590Srgrimes */ 2031590Srgrimes timesortnlp = doarcs(); 2041590Srgrimes /* 2051590Srgrimes * print the dynamic profile 2061590Srgrimes */ 2075190Swollman if(!lflag) { 2088874Srgrimes printgprof( timesortnlp ); 2095190Swollman } 2101590Srgrimes /* 2111590Srgrimes * print the flat profile 2121590Srgrimes */ 2135190Swollman if(!Lflag) { 2145190Swollman printprof(); 2155190Swollman } 2161590Srgrimes /* 2171590Srgrimes * print the index 2181590Srgrimes */ 2198874Srgrimes printindex(); 2201590Srgrimes done(); 2211590Srgrimes} 2221590Srgrimes 2231590Srgrimes /* 2241590Srgrimes * Set up string and symbol tables from a.out. 2251590Srgrimes * and optionally the text space. 2261590Srgrimes * On return symbol table is sorted by value. 2271590Srgrimes */ 2281590Srgrimesgetnfile() 2291590Srgrimes{ 2301590Srgrimes FILE *nfile; 2311590Srgrimes int valcmp(); 2321590Srgrimes 2331590Srgrimes nfile = fopen( a_outname ,"r"); 2341590Srgrimes if (nfile == NULL) { 2351590Srgrimes perror( a_outname ); 2361590Srgrimes done(); 2371590Srgrimes } 2381590Srgrimes fread(&xbuf, 1, sizeof(xbuf), nfile); 2391590Srgrimes if (N_BADMAG(xbuf)) { 2401590Srgrimes fprintf(stderr, "%s: %s: bad format\n", whoami , a_outname ); 2411590Srgrimes done(); 2421590Srgrimes } 2431590Srgrimes getstrtab(nfile); 2441590Srgrimes getsymtab(nfile); 2451590Srgrimes gettextspace( nfile ); 2461590Srgrimes qsort(nl, nname, sizeof(nltype), valcmp); 2471590Srgrimes fclose(nfile); 2481590Srgrimes# ifdef DEBUG 2491590Srgrimes if ( debug & AOUTDEBUG ) { 2501590Srgrimes register int j; 2511590Srgrimes 2521590Srgrimes for (j = 0; j < nname; j++){ 2531590Srgrimes printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name); 2541590Srgrimes } 2551590Srgrimes } 2561590Srgrimes# endif DEBUG 2571590Srgrimes} 2581590Srgrimes 2591590Srgrimesgetstrtab(nfile) 2601590Srgrimes FILE *nfile; 2611590Srgrimes{ 2621590Srgrimes 2631590Srgrimes fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0); 2641590Srgrimes if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) { 2651590Srgrimes fprintf(stderr, "%s: %s: no string table (old format?)\n" , 2661590Srgrimes whoami , a_outname ); 2671590Srgrimes done(); 2681590Srgrimes } 2691590Srgrimes strtab = calloc(ssiz, 1); 2701590Srgrimes if (strtab == NULL) { 2711590Srgrimes fprintf(stderr, "%s: %s: no room for %d bytes of string table\n", 2721590Srgrimes whoami , a_outname , ssiz); 2731590Srgrimes done(); 2741590Srgrimes } 2751590Srgrimes if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) { 2761590Srgrimes fprintf(stderr, "%s: %s: error reading string table\n", 2771590Srgrimes whoami , a_outname ); 2781590Srgrimes done(); 2791590Srgrimes } 2801590Srgrimes} 2811590Srgrimes 2821590Srgrimes /* 2831590Srgrimes * Read in symbol table 2841590Srgrimes */ 2851590Srgrimesgetsymtab(nfile) 2861590Srgrimes FILE *nfile; 2871590Srgrimes{ 2881590Srgrimes register long i; 2891590Srgrimes int askfor; 2901590Srgrimes struct nlist nbuf; 2911590Srgrimes 2921590Srgrimes /* pass1 - count symbols */ 2931590Srgrimes fseek(nfile, (long)N_SYMOFF(xbuf), 0); 2941590Srgrimes nname = 0; 2951590Srgrimes for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 2961590Srgrimes fread(&nbuf, sizeof(nbuf), 1, nfile); 2971590Srgrimes if ( ! funcsymbol( &nbuf ) ) { 2981590Srgrimes continue; 2991590Srgrimes } 3001590Srgrimes nname++; 3011590Srgrimes } 3021590Srgrimes if (nname == 0) { 3031590Srgrimes fprintf(stderr, "%s: %s: no symbols\n", whoami , a_outname ); 3041590Srgrimes done(); 3051590Srgrimes } 3061590Srgrimes askfor = nname + 1; 3071590Srgrimes nl = (nltype *) calloc( askfor , sizeof(nltype) ); 3081590Srgrimes if (nl == 0) { 3091590Srgrimes fprintf(stderr, "%s: No room for %d bytes of symbol table\n", 3101590Srgrimes whoami, askfor * sizeof(nltype) ); 3111590Srgrimes done(); 3121590Srgrimes } 3131590Srgrimes 3141590Srgrimes /* pass2 - read symbols */ 3151590Srgrimes fseek(nfile, (long)N_SYMOFF(xbuf), 0); 3161590Srgrimes npe = nl; 3171590Srgrimes nname = 0; 3181590Srgrimes for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) { 3191590Srgrimes fread(&nbuf, sizeof(nbuf), 1, nfile); 3201590Srgrimes if ( ! funcsymbol( &nbuf ) ) { 3211590Srgrimes# ifdef DEBUG 3221590Srgrimes if ( debug & AOUTDEBUG ) { 3231590Srgrimes printf( "[getsymtab] rejecting: 0x%x %s\n" , 3241590Srgrimes nbuf.n_type , strtab + nbuf.n_un.n_strx ); 3251590Srgrimes } 3261590Srgrimes# endif DEBUG 3271590Srgrimes continue; 3281590Srgrimes } 3291590Srgrimes npe->value = nbuf.n_value; 3301590Srgrimes npe->name = strtab+nbuf.n_un.n_strx; 3311590Srgrimes# ifdef DEBUG 3321590Srgrimes if ( debug & AOUTDEBUG ) { 3331590Srgrimes printf( "[getsymtab] %d %s 0x%08x\n" , 3341590Srgrimes nname , npe -> name , npe -> value ); 3351590Srgrimes } 3361590Srgrimes# endif DEBUG 3371590Srgrimes npe++; 3381590Srgrimes nname++; 3391590Srgrimes } 3401590Srgrimes npe->value = -1; 3411590Srgrimes} 3421590Srgrimes 3431590Srgrimes /* 3441590Srgrimes * read in the text space of an a.out file 3451590Srgrimes */ 3461590Srgrimesgettextspace( nfile ) 3471590Srgrimes FILE *nfile; 3481590Srgrimes{ 3491590Srgrimes 3501590Srgrimes if ( cflag == 0 ) { 3511590Srgrimes return; 3521590Srgrimes } 3531590Srgrimes textspace = (u_char *) malloc( xbuf.a_text ); 3541590Srgrimes if ( textspace == 0 ) { 3551590Srgrimes fprintf( stderr , "%s: ran out room for %d bytes of text space: " , 3561590Srgrimes whoami , xbuf.a_text ); 3571590Srgrimes fprintf( stderr , "can't do -c\n" ); 3581590Srgrimes return; 3591590Srgrimes } 3601590Srgrimes (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 ); 3611590Srgrimes if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) { 3621590Srgrimes fprintf( stderr , "%s: couldn't read text space: " , whoami ); 3631590Srgrimes fprintf( stderr , "can't do -c\n" ); 3641590Srgrimes free( textspace ); 3651590Srgrimes textspace = 0; 3661590Srgrimes return; 3671590Srgrimes } 3681590Srgrimes} 3691590Srgrimes /* 3701590Srgrimes * information from a gmon.out file is in two parts: 3711590Srgrimes * an array of sampling hits within pc ranges, 3721590Srgrimes * and the arcs. 3731590Srgrimes */ 3741590Srgrimesgetpfile(filename) 3751590Srgrimes char *filename; 3761590Srgrimes{ 3771590Srgrimes FILE *pfile; 3781590Srgrimes FILE *openpfile(); 3791590Srgrimes struct rawarc arc; 3801590Srgrimes 3811590Srgrimes pfile = openpfile(filename); 3821590Srgrimes readsamples(pfile); 3831590Srgrimes /* 3841590Srgrimes * the rest of the file consists of 3851590Srgrimes * a bunch of <from,self,count> tuples. 3861590Srgrimes */ 3871590Srgrimes while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) { 3881590Srgrimes# ifdef DEBUG 3891590Srgrimes if ( debug & SAMPLEDEBUG ) { 3901590Srgrimes printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" , 3911590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 3921590Srgrimes } 3931590Srgrimes# endif DEBUG 3941590Srgrimes /* 3951590Srgrimes * add this arc 3961590Srgrimes */ 3971590Srgrimes tally( &arc ); 3981590Srgrimes } 3991590Srgrimes fclose(pfile); 4001590Srgrimes} 4011590Srgrimes 4021590SrgrimesFILE * 4031590Srgrimesopenpfile(filename) 4041590Srgrimes char *filename; 4051590Srgrimes{ 4061590Srgrimes struct gmonhdr tmp; 4071590Srgrimes FILE *pfile; 4081590Srgrimes int size; 4091590Srgrimes int rate; 4101590Srgrimes 4111590Srgrimes if((pfile = fopen(filename, "r")) == NULL) { 4121590Srgrimes perror(filename); 4131590Srgrimes done(); 4141590Srgrimes } 4151590Srgrimes fread(&tmp, sizeof(struct gmonhdr), 1, pfile); 4161590Srgrimes if ( s_highpc != 0 && ( tmp.lpc != gmonhdr.lpc || 4171590Srgrimes tmp.hpc != gmonhdr.hpc || tmp.ncnt != gmonhdr.ncnt ) ) { 4181590Srgrimes fprintf(stderr, "%s: incompatible with first gmon file\n", filename); 4191590Srgrimes done(); 4201590Srgrimes } 4211590Srgrimes gmonhdr = tmp; 4221590Srgrimes if ( gmonhdr.version == GMONVERSION ) { 4231590Srgrimes rate = gmonhdr.profrate; 4241590Srgrimes size = sizeof(struct gmonhdr); 4251590Srgrimes } else { 4261590Srgrimes fseek(pfile, sizeof(struct ophdr), SEEK_SET); 4271590Srgrimes size = sizeof(struct ophdr); 4281590Srgrimes gmonhdr.profrate = rate = hertz(); 4291590Srgrimes gmonhdr.version = GMONVERSION; 4301590Srgrimes } 4311590Srgrimes if (hz == 0) { 4321590Srgrimes hz = rate; 4331590Srgrimes } else if (hz != rate) { 4341590Srgrimes fprintf(stderr, 4351590Srgrimes "%s: profile clock rate (%d) %s (%d) in first gmon file\n", 4361590Srgrimes filename, rate, "incompatible with clock rate", hz); 4371590Srgrimes done(); 4381590Srgrimes } 4391590Srgrimes s_lowpc = (unsigned long) gmonhdr.lpc; 4401590Srgrimes s_highpc = (unsigned long) gmonhdr.hpc; 4411590Srgrimes lowpc = (unsigned long)gmonhdr.lpc / sizeof(UNIT); 4421590Srgrimes highpc = (unsigned long)gmonhdr.hpc / sizeof(UNIT); 4431590Srgrimes sampbytes = gmonhdr.ncnt - size; 4441590Srgrimes nsamples = sampbytes / sizeof (UNIT); 4451590Srgrimes# ifdef DEBUG 4461590Srgrimes if ( debug & SAMPLEDEBUG ) { 4471590Srgrimes printf( "[openpfile] hdr.lpc 0x%x hdr.hpc 0x%x hdr.ncnt %d\n", 4481590Srgrimes gmonhdr.lpc , gmonhdr.hpc , gmonhdr.ncnt ); 4491590Srgrimes printf( "[openpfile] s_lowpc 0x%x s_highpc 0x%x\n" , 4501590Srgrimes s_lowpc , s_highpc ); 4511590Srgrimes printf( "[openpfile] lowpc 0x%x highpc 0x%x\n" , 4521590Srgrimes lowpc , highpc ); 4531590Srgrimes printf( "[openpfile] sampbytes %d nsamples %d\n" , 4541590Srgrimes sampbytes , nsamples ); 4551590Srgrimes printf( "[openpfile] sample rate %d\n" , hz ); 4561590Srgrimes } 4571590Srgrimes# endif DEBUG 4581590Srgrimes return(pfile); 4591590Srgrimes} 4601590Srgrimes 4611590Srgrimestally( rawp ) 4621590Srgrimes struct rawarc *rawp; 4631590Srgrimes{ 4641590Srgrimes nltype *parentp; 4651590Srgrimes nltype *childp; 4661590Srgrimes 4671590Srgrimes parentp = nllookup( rawp -> raw_frompc ); 4681590Srgrimes childp = nllookup( rawp -> raw_selfpc ); 4691590Srgrimes if ( parentp == 0 || childp == 0 ) 4701590Srgrimes return; 4711590Srgrimes if ( kflag 4721590Srgrimes && onlist( kfromlist , parentp -> name ) 4731590Srgrimes && onlist( ktolist , childp -> name ) ) { 4741590Srgrimes return; 4751590Srgrimes } 4761590Srgrimes childp -> ncall += rawp -> raw_count; 4771590Srgrimes# ifdef DEBUG 4781590Srgrimes if ( debug & TALLYDEBUG ) { 4791590Srgrimes printf( "[tally] arc from %s to %s traversed %d times\n" , 4801590Srgrimes parentp -> name , childp -> name , rawp -> raw_count ); 4811590Srgrimes } 4821590Srgrimes# endif DEBUG 4831590Srgrimes addarc( parentp , childp , rawp -> raw_count ); 4841590Srgrimes} 4851590Srgrimes 4861590Srgrimes/* 4871590Srgrimes * dump out the gmon.sum file 4881590Srgrimes */ 4891590Srgrimesdumpsum( sumfile ) 4901590Srgrimes char *sumfile; 4911590Srgrimes{ 4921590Srgrimes register nltype *nlp; 4931590Srgrimes register arctype *arcp; 4941590Srgrimes struct rawarc arc; 4951590Srgrimes FILE *sfile; 4961590Srgrimes 4971590Srgrimes if ( ( sfile = fopen ( sumfile , "w" ) ) == NULL ) { 4981590Srgrimes perror( sumfile ); 4991590Srgrimes done(); 5001590Srgrimes } 5011590Srgrimes /* 5021590Srgrimes * dump the header; use the last header read in 5031590Srgrimes */ 5041590Srgrimes if ( fwrite( &gmonhdr , sizeof gmonhdr , 1 , sfile ) != 1 ) { 5051590Srgrimes perror( sumfile ); 5061590Srgrimes done(); 5071590Srgrimes } 5081590Srgrimes /* 5091590Srgrimes * dump the samples 5101590Srgrimes */ 5111590Srgrimes if (fwrite(samples, sizeof (UNIT), nsamples, sfile) != nsamples) { 5121590Srgrimes perror( sumfile ); 5131590Srgrimes done(); 5141590Srgrimes } 5151590Srgrimes /* 5161590Srgrimes * dump the normalized raw arc information 5171590Srgrimes */ 5181590Srgrimes for ( nlp = nl ; nlp < npe ; nlp++ ) { 5191590Srgrimes for ( arcp = nlp -> children ; arcp ; arcp = arcp -> arc_childlist ) { 5201590Srgrimes arc.raw_frompc = arcp -> arc_parentp -> value; 5211590Srgrimes arc.raw_selfpc = arcp -> arc_childp -> value; 5221590Srgrimes arc.raw_count = arcp -> arc_count; 5231590Srgrimes if ( fwrite ( &arc , sizeof arc , 1 , sfile ) != 1 ) { 5241590Srgrimes perror( sumfile ); 5251590Srgrimes done(); 5261590Srgrimes } 5271590Srgrimes# ifdef DEBUG 5281590Srgrimes if ( debug & SAMPLEDEBUG ) { 5291590Srgrimes printf( "[dumpsum] frompc 0x%x selfpc 0x%x count %d\n" , 5301590Srgrimes arc.raw_frompc , arc.raw_selfpc , arc.raw_count ); 5311590Srgrimes } 5321590Srgrimes# endif DEBUG 5331590Srgrimes } 5341590Srgrimes } 5351590Srgrimes fclose( sfile ); 5361590Srgrimes} 5371590Srgrimes 5381590Srgrimesvalcmp(p1, p2) 5391590Srgrimes nltype *p1, *p2; 5401590Srgrimes{ 5411590Srgrimes if ( p1 -> value < p2 -> value ) { 5421590Srgrimes return LESSTHAN; 5431590Srgrimes } 5441590Srgrimes if ( p1 -> value > p2 -> value ) { 5451590Srgrimes return GREATERTHAN; 5461590Srgrimes } 5471590Srgrimes return EQUALTO; 5481590Srgrimes} 5491590Srgrimes 5501590Srgrimesreadsamples(pfile) 5511590Srgrimes FILE *pfile; 5521590Srgrimes{ 5531590Srgrimes register i; 5541590Srgrimes UNIT sample; 5558874Srgrimes 5561590Srgrimes if (samples == 0) { 5571590Srgrimes samples = (UNIT *) calloc(sampbytes, sizeof (UNIT)); 5581590Srgrimes if (samples == 0) { 5598874Srgrimes fprintf( stderr , "%s: No room for %d sample pc's\n", 5601590Srgrimes whoami , sampbytes / sizeof (UNIT)); 5611590Srgrimes done(); 5621590Srgrimes } 5631590Srgrimes } 5641590Srgrimes for (i = 0; i < nsamples; i++) { 5651590Srgrimes fread(&sample, sizeof (UNIT), 1, pfile); 5661590Srgrimes if (feof(pfile)) 5671590Srgrimes break; 5681590Srgrimes samples[i] += sample; 5691590Srgrimes } 5701590Srgrimes if (i != nsamples) { 5711590Srgrimes fprintf(stderr, 5721590Srgrimes "%s: unexpected EOF after reading %d/%d samples\n", 5731590Srgrimes whoami , --i , nsamples ); 5741590Srgrimes done(); 5751590Srgrimes } 5761590Srgrimes} 5771590Srgrimes 5781590Srgrimes/* 5791590Srgrimes * Assign samples to the procedures to which they belong. 5801590Srgrimes * 5811590Srgrimes * There are three cases as to where pcl and pch can be 5821590Srgrimes * with respect to the routine entry addresses svalue0 and svalue1 5831590Srgrimes * as shown in the following diagram. overlap computes the 5841590Srgrimes * distance between the arrows, the fraction of the sample 5851590Srgrimes * that is to be credited to the routine which starts at svalue0. 5861590Srgrimes * 5871590Srgrimes * svalue0 svalue1 5881590Srgrimes * | | 5891590Srgrimes * v v 5901590Srgrimes * 5911590Srgrimes * +-----------------------------------------------+ 5921590Srgrimes * | | 5931590Srgrimes * | ->| |<- ->| |<- ->| |<- | 5941590Srgrimes * | | | | | | 5951590Srgrimes * +---------+ +---------+ +---------+ 5961590Srgrimes * 5971590Srgrimes * ^ ^ ^ ^ ^ ^ 5981590Srgrimes * | | | | | | 5991590Srgrimes * pcl pch pcl pch pcl pch 6001590Srgrimes * 6011590Srgrimes * For the vax we assert that samples will never fall in the first 6021590Srgrimes * two bytes of any routine, since that is the entry mask, 6031590Srgrimes * thus we give call alignentries() to adjust the entry points if 6041590Srgrimes * the entry mask falls in one bucket but the code for the routine 6051590Srgrimes * doesn't start until the next bucket. In conjunction with the 6061590Srgrimes * alignment of routine addresses, this should allow us to have 6071590Srgrimes * only one sample for every four bytes of text space and never 6081590Srgrimes * have any overlap (the two end cases, above). 6091590Srgrimes */ 6101590Srgrimesasgnsamples() 6111590Srgrimes{ 6121590Srgrimes register int j; 6131590Srgrimes UNIT ccnt; 6141590Srgrimes double time; 6151590Srgrimes unsigned long pcl, pch; 6161590Srgrimes register int i; 6171590Srgrimes unsigned long overlap; 6181590Srgrimes unsigned long svalue0, svalue1; 6191590Srgrimes 6201590Srgrimes /* read samples and assign to namelist symbols */ 6211590Srgrimes scale = highpc - lowpc; 6221590Srgrimes scale /= nsamples; 6231590Srgrimes alignentries(); 6241590Srgrimes for (i = 0, j = 1; i < nsamples; i++) { 6251590Srgrimes ccnt = samples[i]; 6261590Srgrimes if (ccnt == 0) 6271590Srgrimes continue; 6281590Srgrimes pcl = lowpc + scale * i; 6291590Srgrimes pch = lowpc + scale * (i + 1); 6301590Srgrimes time = ccnt; 6311590Srgrimes# ifdef DEBUG 6321590Srgrimes if ( debug & SAMPLEDEBUG ) { 6331590Srgrimes printf( "[asgnsamples] pcl 0x%x pch 0x%x ccnt %d\n" , 6341590Srgrimes pcl , pch , ccnt ); 6351590Srgrimes } 6361590Srgrimes# endif DEBUG 6371590Srgrimes totime += time; 6381590Srgrimes for (j = j - 1; j < nname; j++) { 6391590Srgrimes svalue0 = nl[j].svalue; 6401590Srgrimes svalue1 = nl[j+1].svalue; 6411590Srgrimes /* 6428874Srgrimes * if high end of tick is below entry address, 6431590Srgrimes * go for next tick. 6441590Srgrimes */ 6451590Srgrimes if (pch < svalue0) 6461590Srgrimes break; 6471590Srgrimes /* 6481590Srgrimes * if low end of tick into next routine, 6491590Srgrimes * go for next routine. 6501590Srgrimes */ 6511590Srgrimes if (pcl >= svalue1) 6521590Srgrimes continue; 6531590Srgrimes overlap = min(pch, svalue1) - max(pcl, svalue0); 6541590Srgrimes if (overlap > 0) { 6551590Srgrimes# ifdef DEBUG 6561590Srgrimes if (debug & SAMPLEDEBUG) { 6571590Srgrimes printf("[asgnsamples] (0x%x->0x%x-0x%x) %s gets %f ticks %d overlap\n", 6581590Srgrimes nl[j].value/sizeof(UNIT), svalue0, svalue1, 6598874Srgrimes nl[j].name, 6601590Srgrimes overlap * time / scale, overlap); 6611590Srgrimes } 6621590Srgrimes# endif DEBUG 6631590Srgrimes nl[j].time += overlap * time / scale; 6641590Srgrimes } 6651590Srgrimes } 6661590Srgrimes } 6671590Srgrimes# ifdef DEBUG 6681590Srgrimes if (debug & SAMPLEDEBUG) { 6691590Srgrimes printf("[asgnsamples] totime %f\n", totime); 6701590Srgrimes } 6711590Srgrimes# endif DEBUG 6721590Srgrimes} 6731590Srgrimes 6741590Srgrimes 6751590Srgrimesunsigned long 6761590Srgrimesmin(a, b) 6771590Srgrimes unsigned long a,b; 6781590Srgrimes{ 6791590Srgrimes if (a<b) 6801590Srgrimes return(a); 6811590Srgrimes return(b); 6821590Srgrimes} 6831590Srgrimes 6841590Srgrimesunsigned long 6851590Srgrimesmax(a, b) 6861590Srgrimes unsigned long a,b; 6871590Srgrimes{ 6881590Srgrimes if (a>b) 6891590Srgrimes return(a); 6901590Srgrimes return(b); 6911590Srgrimes} 6921590Srgrimes 6931590Srgrimes /* 6941590Srgrimes * calculate scaled entry point addresses (to save time in asgnsamples), 6951590Srgrimes * and possibly push the scaled entry points over the entry mask, 6961590Srgrimes * if it turns out that the entry point is in one bucket and the code 6971590Srgrimes * for a routine is in the next bucket. 6981590Srgrimes */ 6991590Srgrimesalignentries() 7001590Srgrimes{ 7011590Srgrimes register struct nl *nlp; 7021590Srgrimes unsigned long bucket_of_entry; 7031590Srgrimes unsigned long bucket_of_code; 7041590Srgrimes 7051590Srgrimes for (nlp = nl; nlp < npe; nlp++) { 7061590Srgrimes nlp -> svalue = nlp -> value / sizeof(UNIT); 7071590Srgrimes bucket_of_entry = (nlp->svalue - lowpc) / scale; 7081590Srgrimes bucket_of_code = (nlp->svalue + UNITS_TO_CODE - lowpc) / scale; 7091590Srgrimes if (bucket_of_entry < bucket_of_code) { 7101590Srgrimes# ifdef DEBUG 7111590Srgrimes if (debug & SAMPLEDEBUG) { 7121590Srgrimes printf("[alignentries] pushing svalue 0x%x to 0x%x\n", 7131590Srgrimes nlp->svalue, nlp->svalue + UNITS_TO_CODE); 7141590Srgrimes } 7151590Srgrimes# endif DEBUG 7161590Srgrimes nlp->svalue += UNITS_TO_CODE; 7171590Srgrimes } 7181590Srgrimes } 7191590Srgrimes} 7201590Srgrimes 7211590Srgrimesbool 7221590Srgrimesfuncsymbol( nlistp ) 7231590Srgrimes struct nlist *nlistp; 7241590Srgrimes{ 7251590Srgrimes char *name, c; 7261590Srgrimes 7271590Srgrimes /* 7281590Srgrimes * must be a text symbol, 7291590Srgrimes * and static text symbols don't qualify if aflag set. 7301590Srgrimes */ 7311590Srgrimes if ( ! ( ( nlistp -> n_type == ( N_TEXT | N_EXT ) ) 7321590Srgrimes || ( ( nlistp -> n_type == N_TEXT ) && ( aflag == 0 ) ) ) ) { 7331590Srgrimes return FALSE; 7341590Srgrimes } 7351590Srgrimes /* 7362513Sbde * name must start with an underscore if uflag is set. 7371590Srgrimes * can't have any `funny' characters in name, 7381590Srgrimes * where `funny' includes `.', .o file names 7391590Srgrimes * and `$', pascal labels. 7401590Srgrimes * need to make an exception for sparc .mul & co. 7411590Srgrimes * perhaps we should just drop this code entirely... 7421590Srgrimes */ 7431590Srgrimes name = strtab + nlistp -> n_un.n_strx; 7442513Sbde if ( uflag && *name != '_' ) 7452513Sbde return FALSE; 7461590Srgrimes#ifdef sparc 7471590Srgrimes if ( *name == '.' ) { 7481590Srgrimes char *p = name + 1; 7491590Srgrimes if ( *p == 'u' ) 7501590Srgrimes p++; 7511590Srgrimes if ( strcmp ( p, "mul" ) == 0 || strcmp ( p, "div" ) == 0 || 7521590Srgrimes strcmp ( p, "rem" ) == 0 ) 7531590Srgrimes return TRUE; 7541590Srgrimes } 7551590Srgrimes#endif 7561590Srgrimes while ( c = *name++ ) { 7571590Srgrimes if ( c == '.' || c == '$' ) { 7581590Srgrimes return FALSE; 7591590Srgrimes } 7601590Srgrimes } 7611590Srgrimes return TRUE; 7621590Srgrimes} 7631590Srgrimes 7641590Srgrimesdone() 7651590Srgrimes{ 7661590Srgrimes 7671590Srgrimes exit(0); 7681590Srgrimes} 769