147884Sbostic /*- 247884Sbostic * Copyright (c) 1983 The Regents of the University of California. 347884Sbostic * All rights reserved. 447884Sbostic * 549278Sbostic * %sccs.include.redist.c% 621415Sdist */ 74514Speter 849278Sbostic #ifndef lint 9*49895Smckusick static char sccsid[] = "@(#)gmon.c 5.8 (Berkeley) 05/27/91"; 1049278Sbostic #endif /* not lint */ 1121415Sdist 1248972Sdonn #include <unistd.h> 1348972Sdonn 144869Smckusic #ifdef DEBUG 154514Speter #include <stdio.h> 1647884Sbostic #endif 174514Speter 189433Smckusick #include "gmon.h" 194514Speter 2048972Sdonn extern mcount() asm ("mcount"); 2148972Sdonn extern mcount2() asm ("mcount2"); 2248972Sdonn extern char *minbrk asm ("minbrk"); 2348972Sdonn 244564Speter /* 254564Speter * froms is actually a bunch of unsigned shorts indexing tos 264564Speter */ 2710279Smckusick static int profiling = 3; 284514Speter static unsigned short *froms; 294514Speter static struct tostruct *tos = 0; 309608Speter static long tolimit = 0; 314514Speter static char *s_lowpc = 0; 324514Speter static char *s_highpc = 0; 334850Speter static unsigned long s_textsize = 0; 344514Speter 354564Speter static int ssiz; 3611998Speter static char *sbuf; 3711796Speter static int s_scale; 3811998Speter /* see profil(2) where this is describe (incorrectly) */ 3911998Speter #define SCALE_1_TO_1 0x10000L 404514Speter 41*49895Smckusick #define MSG "No space for profiling buffer(s)\n" 424514Speter 439433Smckusick monstartup(lowpc, highpc) 444564Speter char *lowpc; 454564Speter char *highpc; 464514Speter { 474850Speter int monsize; 484850Speter char *buffer; 49*49895Smckusick register int o; 504514Speter 519608Speter /* 529608Speter * round lowpc and highpc to multiples of the density we're using 539608Speter * so the rest of the scaling (here and in gprof) stays in ints. 549608Speter */ 559608Speter lowpc = (char *) 569608Speter ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 574564Speter s_lowpc = lowpc; 589608Speter highpc = (char *) 599608Speter ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 604564Speter s_highpc = highpc; 614850Speter s_textsize = highpc - lowpc; 629608Speter monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 634564Speter buffer = sbrk( monsize ); 644564Speter if ( buffer == (char *) -1 ) { 6532074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 664564Speter return; 674564Speter } 6810268Smckusick froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 694564Speter if ( froms == (unsigned short *) -1 ) { 7032074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 714564Speter froms = 0; 724564Speter return; 734564Speter } 7410279Smckusick tolimit = s_textsize * ARCDENSITY / 100; 7510279Smckusick if ( tolimit < MINARCS ) { 7610279Smckusick tolimit = MINARCS; 7710279Smckusick } else if ( tolimit > 65534 ) { 7810279Smckusick tolimit = 65534; 799530Smckusick } 8010279Smckusick tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 814564Speter if ( tos == (struct tostruct *) -1 ) { 8232074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 834564Speter froms = 0; 844564Speter tos = 0; 854564Speter return; 864564Speter } 8714127Smckusick minbrk = sbrk(0); 884564Speter tos[0].link = 0; 89*49895Smckusick sbuf = buffer; 90*49895Smckusick ssiz = monsize; 91*49895Smckusick ( (struct phdr *) buffer ) -> lpc = lowpc; 92*49895Smckusick ( (struct phdr *) buffer ) -> hpc = highpc; 93*49895Smckusick ( (struct phdr *) buffer ) -> ncnt = ssiz; 94*49895Smckusick monsize -= sizeof(struct phdr); 95*49895Smckusick if ( monsize <= 0 ) 96*49895Smckusick return; 97*49895Smckusick o = highpc - lowpc; 98*49895Smckusick if( monsize < o ) 99*49895Smckusick s_scale = ( (float) monsize / o ) * SCALE_1_TO_1; 100*49895Smckusick else 101*49895Smckusick s_scale = SCALE_1_TO_1; 102*49895Smckusick moncontrol(1); 1034514Speter } 1044514Speter 1054514Speter _mcleanup() 1064514Speter { 1074869Smckusic int fd; 1084869Smckusic int fromindex; 10910268Smckusick int endfrom; 1104869Smckusic char *frompc; 1114869Smckusic int toindex; 1124869Smckusic struct rawarc rawarc; 1134514Speter 114*49895Smckusick moncontrol(0); 1154869Smckusic fd = creat( "gmon.out" , 0666 ); 1164869Smckusic if ( fd < 0 ) { 1174564Speter perror( "mcount: gmon.out" ); 1184514Speter return; 1194514Speter } 1204564Speter # ifdef DEBUG 1214564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 1224564Speter # endif DEBUG 1234869Smckusic write( fd , sbuf , ssiz ); 12410268Smckusick endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 12510268Smckusick for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 1264514Speter if ( froms[fromindex] == 0 ) { 1274514Speter continue; 1284514Speter } 12910268Smckusick frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1304514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1314514Speter # ifdef DEBUG 1324748Speter fprintf( stderr , 1334748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1344514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1354514Speter # endif DEBUG 1364869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1374869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1384869Smckusic rawarc.raw_count = tos[toindex].count; 1394869Smckusic write( fd , &rawarc , sizeof rawarc ); 1404514Speter } 1414514Speter } 1424869Smckusic close( fd ); 1434514Speter } 1444514Speter 14548972Sdonn asm(".text; .globl mcount; mcount: pushl 16(fp); calls $1,mcount2; rsb"); 14648972Sdonn 14748972Sdonn mcount2(frompcindex, selfpc) 14848972Sdonn register unsigned short *frompcindex; 14948972Sdonn register char *selfpc; 1504514Speter { 15148972Sdonn register struct tostruct *top; 15248972Sdonn register struct tostruct *prevtop; 15348972Sdonn register long toindex; 1544514Speter 1554514Speter /* 1564540Speter * check that we are profiling 1574564Speter * and that we aren't recursively invoked. 1584540Speter */ 15948972Sdonn if (profiling) 16048972Sdonn return; 16110279Smckusick profiling++; 1624540Speter /* 1634540Speter * check that frompcindex is a reasonable pc value. 1644540Speter * for example: signal catchers get called from the stack, 1654540Speter * not from text space. too bad. 1664540Speter */ 1679608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 1689608Speter if ((unsigned long)frompcindex > s_textsize) { 1699608Speter goto done; 1704514Speter } 1719608Speter frompcindex = 17210268Smckusick &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1739608Speter toindex = *frompcindex; 1749608Speter if (toindex == 0) { 1759608Speter /* 1769608Speter * first time traversing this arc 1779608Speter */ 1789608Speter toindex = ++tos[0].link; 1799608Speter if (toindex >= tolimit) { 1809608Speter goto overflow; 1819608Speter } 1829608Speter *frompcindex = toindex; 1839608Speter top = &tos[toindex]; 1849608Speter top->selfpc = selfpc; 1859608Speter top->count = 1; 1869608Speter top->link = 0; 1879608Speter goto done; 1884514Speter } 1899608Speter top = &tos[toindex]; 1909608Speter if (top->selfpc == selfpc) { 1919608Speter /* 1929608Speter * arc at front of chain; usual case. 1939608Speter */ 1949608Speter top->count++; 1959608Speter goto done; 1964514Speter } 1979608Speter /* 1989608Speter * have to go looking down chain for it. 1999608Speter * top points to what we are looking at, 2009608Speter * prevtop points to previous top. 2019608Speter * we know it is not at the head of the chain. 2029608Speter */ 2039608Speter for (; /* goto done */; ) { 2049608Speter if (top->link == 0) { 2059608Speter /* 2069608Speter * top is end of the chain and none of the chain 2079608Speter * had top->selfpc == selfpc. 2089608Speter * so we allocate a new tostruct 2099608Speter * and link it to the head of the chain. 2109608Speter */ 2119608Speter toindex = ++tos[0].link; 2129608Speter if (toindex >= tolimit) { 2139608Speter goto overflow; 2149608Speter } 2159608Speter top = &tos[toindex]; 2169608Speter top->selfpc = selfpc; 2179608Speter top->count = 1; 2189608Speter top->link = *frompcindex; 2199608Speter *frompcindex = toindex; 2209608Speter goto done; 2219608Speter } 2229608Speter /* 2239608Speter * otherwise, check the next arc on the chain. 2249608Speter */ 2259608Speter prevtop = top; 2269608Speter top = &tos[top->link]; 2279608Speter if (top->selfpc == selfpc) { 2289608Speter /* 2299608Speter * there it is. 2309608Speter * increment its count 2319608Speter * move it to the head of the chain. 2329608Speter */ 2339608Speter top->count++; 2349608Speter toindex = prevtop->link; 2359608Speter prevtop->link = top->link; 2369608Speter top->link = *frompcindex; 2379608Speter *frompcindex = toindex; 2389608Speter goto done; 2399608Speter } 2409608Speter 2419608Speter } 2424540Speter done: 24310279Smckusick profiling--; 24448972Sdonn return; 2454514Speter 2464514Speter overflow: 24710279Smckusick profiling++; /* halt further profiling */ 2484514Speter # define TOLIMIT "mcount: tos overflow\n" 24932074Smckusick write(2, TOLIMIT, sizeof(TOLIMIT) - 1); 25048972Sdonn return; 2514514Speter } 2524514Speter 2536177Smckusick /* 25411796Speter * Control profiling 25511796Speter * profiling is what mcount checks to see if 25611796Speter * all the data structures are ready. 25711796Speter */ 25811796Speter moncontrol(mode) 25911796Speter int mode; 26011796Speter { 26111796Speter if (mode) { 26211796Speter /* start */ 26311796Speter profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 26448972Sdonn (int)s_lowpc, s_scale); 26511796Speter profiling = 0; 26611796Speter } else { 26711796Speter /* stop */ 26811796Speter profil((char *)0, 0, 0, 0); 26911796Speter profiling = 3; 27011796Speter } 27111796Speter } 272