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