147884Sbostic /*- 247884Sbostic * Copyright (c) 1983 The Regents of the University of California. 347884Sbostic * All rights reserved. 447884Sbostic * 547884Sbostic * %sccs.include.proprietary.c% 621415Sdist */ 74514Speter 826667Sdonn #if defined(LIBC_SCCS) && !defined(lint) 9*48972Sdonn static char sccsid[] = "@(#)gmon.c 5.6 (Berkeley) 05/03/91"; 1047884Sbostic #endif /* LIBC_SCCS and not lint */ 1121415Sdist 12*48972Sdonn #include <unistd.h> 13*48972Sdonn 144869Smckusic #ifdef DEBUG 154514Speter #include <stdio.h> 1647884Sbostic #endif 174514Speter 189433Smckusick #include "gmon.h" 194514Speter 20*48972Sdonn extern mcount() asm ("mcount"); 21*48972Sdonn extern mcount2() asm ("mcount2"); 22*48972Sdonn extern char *minbrk asm ("minbrk"); 23*48972Sdonn 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 414514Speter #define MSG "No space for monitor buffer(s)\n" 424514Speter 439433Smckusick monstartup(lowpc, highpc) 444564Speter char *lowpc; 454564Speter char *highpc; 464514Speter { 474850Speter int monsize; 484850Speter char *buffer; 494514Speter 509608Speter /* 519608Speter * round lowpc and highpc to multiples of the density we're using 529608Speter * so the rest of the scaling (here and in gprof) stays in ints. 539608Speter */ 549608Speter lowpc = (char *) 559608Speter ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 564564Speter s_lowpc = lowpc; 579608Speter highpc = (char *) 589608Speter ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 594564Speter s_highpc = highpc; 604850Speter s_textsize = highpc - lowpc; 619608Speter monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 624564Speter buffer = sbrk( monsize ); 634564Speter if ( buffer == (char *) -1 ) { 6432074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 654564Speter return; 664564Speter } 6710268Smckusick froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 684564Speter if ( froms == (unsigned short *) -1 ) { 6932074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 704564Speter froms = 0; 714564Speter return; 724564Speter } 7310279Smckusick tolimit = s_textsize * ARCDENSITY / 100; 7410279Smckusick if ( tolimit < MINARCS ) { 7510279Smckusick tolimit = MINARCS; 7610279Smckusick } else if ( tolimit > 65534 ) { 7710279Smckusick tolimit = 65534; 789530Smckusick } 7910279Smckusick tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 804564Speter if ( tos == (struct tostruct *) -1 ) { 8132074Smckusick write( 2 , MSG , sizeof(MSG) - 1 ); 824564Speter froms = 0; 834564Speter tos = 0; 844564Speter return; 854564Speter } 8614127Smckusick minbrk = sbrk(0); 874564Speter tos[0].link = 0; 8810279Smckusick monitor( lowpc , highpc , buffer , monsize , tolimit ); 894514Speter } 904514Speter 914514Speter _mcleanup() 924514Speter { 934869Smckusic int fd; 944869Smckusic int fromindex; 9510268Smckusick int endfrom; 964869Smckusic char *frompc; 974869Smckusic int toindex; 984869Smckusic struct rawarc rawarc; 994514Speter 1004869Smckusic fd = creat( "gmon.out" , 0666 ); 1014869Smckusic if ( fd < 0 ) { 1024564Speter perror( "mcount: gmon.out" ); 1034514Speter return; 1044514Speter } 1054564Speter # ifdef DEBUG 1064564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 1074564Speter # endif DEBUG 1084869Smckusic write( fd , sbuf , ssiz ); 10910268Smckusick endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 11010268Smckusick for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 1114514Speter if ( froms[fromindex] == 0 ) { 1124514Speter continue; 1134514Speter } 11410268Smckusick frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1154514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1164514Speter # ifdef DEBUG 1174748Speter fprintf( stderr , 1184748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1194514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1204514Speter # endif DEBUG 1214869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1224869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1234869Smckusic rawarc.raw_count = tos[toindex].count; 1244869Smckusic write( fd , &rawarc , sizeof rawarc ); 1254514Speter } 1264514Speter } 1274869Smckusic close( fd ); 1284514Speter } 1294514Speter 130*48972Sdonn asm(".text; .globl mcount; mcount: pushl 16(fp); calls $1,mcount2; rsb"); 131*48972Sdonn 132*48972Sdonn mcount2(frompcindex, selfpc) 133*48972Sdonn register unsigned short *frompcindex; 134*48972Sdonn register char *selfpc; 1354514Speter { 136*48972Sdonn register struct tostruct *top; 137*48972Sdonn register struct tostruct *prevtop; 138*48972Sdonn register long toindex; 1394514Speter 1404514Speter /* 1414540Speter * check that we are profiling 1424564Speter * and that we aren't recursively invoked. 1434540Speter */ 144*48972Sdonn if (profiling) 145*48972Sdonn return; 14610279Smckusick profiling++; 1474540Speter /* 1484540Speter * check that frompcindex is a reasonable pc value. 1494540Speter * for example: signal catchers get called from the stack, 1504540Speter * not from text space. too bad. 1514540Speter */ 1529608Speter frompcindex = (unsigned short *)((long)frompcindex - (long)s_lowpc); 1539608Speter if ((unsigned long)frompcindex > s_textsize) { 1549608Speter goto done; 1554514Speter } 1569608Speter frompcindex = 15710268Smckusick &froms[((long)frompcindex) / (HASHFRACTION * sizeof(*froms))]; 1589608Speter toindex = *frompcindex; 1599608Speter if (toindex == 0) { 1609608Speter /* 1619608Speter * first time traversing this arc 1629608Speter */ 1639608Speter toindex = ++tos[0].link; 1649608Speter if (toindex >= tolimit) { 1659608Speter goto overflow; 1669608Speter } 1679608Speter *frompcindex = toindex; 1689608Speter top = &tos[toindex]; 1699608Speter top->selfpc = selfpc; 1709608Speter top->count = 1; 1719608Speter top->link = 0; 1729608Speter goto done; 1734514Speter } 1749608Speter top = &tos[toindex]; 1759608Speter if (top->selfpc == selfpc) { 1769608Speter /* 1779608Speter * arc at front of chain; usual case. 1789608Speter */ 1799608Speter top->count++; 1809608Speter goto done; 1814514Speter } 1829608Speter /* 1839608Speter * have to go looking down chain for it. 1849608Speter * top points to what we are looking at, 1859608Speter * prevtop points to previous top. 1869608Speter * we know it is not at the head of the chain. 1879608Speter */ 1889608Speter for (; /* goto done */; ) { 1899608Speter if (top->link == 0) { 1909608Speter /* 1919608Speter * top is end of the chain and none of the chain 1929608Speter * had top->selfpc == selfpc. 1939608Speter * so we allocate a new tostruct 1949608Speter * and link it to the head of the chain. 1959608Speter */ 1969608Speter toindex = ++tos[0].link; 1979608Speter if (toindex >= tolimit) { 1989608Speter goto overflow; 1999608Speter } 2009608Speter top = &tos[toindex]; 2019608Speter top->selfpc = selfpc; 2029608Speter top->count = 1; 2039608Speter top->link = *frompcindex; 2049608Speter *frompcindex = toindex; 2059608Speter goto done; 2069608Speter } 2079608Speter /* 2089608Speter * otherwise, check the next arc on the chain. 2099608Speter */ 2109608Speter prevtop = top; 2119608Speter top = &tos[top->link]; 2129608Speter if (top->selfpc == selfpc) { 2139608Speter /* 2149608Speter * there it is. 2159608Speter * increment its count 2169608Speter * move it to the head of the chain. 2179608Speter */ 2189608Speter top->count++; 2199608Speter toindex = prevtop->link; 2209608Speter prevtop->link = top->link; 2219608Speter top->link = *frompcindex; 2229608Speter *frompcindex = toindex; 2239608Speter goto done; 2249608Speter } 2259608Speter 2269608Speter } 2274540Speter done: 22810279Smckusick profiling--; 229*48972Sdonn return; 2304514Speter 2314514Speter overflow: 23210279Smckusick profiling++; /* halt further profiling */ 2334514Speter # define TOLIMIT "mcount: tos overflow\n" 23432074Smckusick write(2, TOLIMIT, sizeof(TOLIMIT) - 1); 235*48972Sdonn return; 2364514Speter } 2374514Speter 2389433Smckusick /*VARARGS1*/ 2399433Smckusick monitor( lowpc , highpc , buf , bufsiz , nfunc ) 2404564Speter char *lowpc; 2414564Speter char *highpc; 24211998Speter char *buf; /* declared ``short buffer[]'' in monitor(3) */ 24311998Speter int bufsiz; 2449433Smckusick int nfunc; /* not used, available for compatability only */ 2454514Speter { 2464564Speter register o; 2474514Speter 2484564Speter if ( lowpc == 0 ) { 24911796Speter moncontrol(0); 2509433Smckusick _mcleanup(); 2514564Speter return; 2524564Speter } 2534564Speter sbuf = buf; 2544564Speter ssiz = bufsiz; 2554564Speter ( (struct phdr *) buf ) -> lpc = lowpc; 2564564Speter ( (struct phdr *) buf ) -> hpc = highpc; 2574564Speter ( (struct phdr *) buf ) -> ncnt = ssiz; 25811998Speter bufsiz -= sizeof(struct phdr); 2594564Speter if ( bufsiz <= 0 ) 2604564Speter return; 26111998Speter o = highpc - lowpc; 2624564Speter if( bufsiz < o ) 26311998Speter s_scale = ( (float) bufsiz / o ) * SCALE_1_TO_1; 2644564Speter else 26511998Speter s_scale = SCALE_1_TO_1; 26611796Speter moncontrol(1); 2674514Speter } 2686177Smckusick 2696177Smckusick /* 27011796Speter * Control profiling 27111796Speter * profiling is what mcount checks to see if 27211796Speter * all the data structures are ready. 27311796Speter */ 27411796Speter moncontrol(mode) 27511796Speter int mode; 27611796Speter { 27711796Speter if (mode) { 27811796Speter /* start */ 27911796Speter profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 280*48972Sdonn (int)s_lowpc, s_scale); 28111796Speter profiling = 0; 28211796Speter } else { 28311796Speter /* stop */ 28411796Speter profil((char *)0, 0, 0, 0); 28511796Speter profiling = 3; 28611796Speter } 28711796Speter } 288