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*52814Smckusick static char sccsid[] = "@(#)gmon.c 5.9 (Berkeley) 03/03/92"; 1049278Sbostic #endif /* not lint */ 1121415Sdist 1248972Sdonn #include <unistd.h> 13*52814Smckusick #include <sys/types.h> 14*52814Smckusick #include <sys/time.h> 15*52814Smckusick #include <sys/kinfo.h> 1648972Sdonn 174869Smckusic #ifdef DEBUG 184514Speter #include <stdio.h> 1947884Sbostic #endif 204514Speter 219433Smckusick #include "gmon.h" 224514Speter 2348972Sdonn extern char *minbrk asm ("minbrk"); 2448972Sdonn 254564Speter /* 264564Speter * froms is actually a bunch of unsigned shorts indexing tos 274564Speter */ 2810279Smckusick static int profiling = 3; 294514Speter static unsigned short *froms; 304514Speter static struct tostruct *tos = 0; 319608Speter static long tolimit = 0; 324514Speter static char *s_lowpc = 0; 334514Speter static char *s_highpc = 0; 344850Speter static unsigned long s_textsize = 0; 354514Speter 364564Speter static int ssiz; 3711998Speter static char *sbuf; 3811796Speter static int s_scale; 3911998Speter /* see profil(2) where this is describe (incorrectly) */ 4011998Speter #define SCALE_1_TO_1 0x10000L 414514Speter 4249895Smckusick #define MSG "No space for profiling buffer(s)\n" 434514Speter 449433Smckusick monstartup(lowpc, highpc) 454564Speter char *lowpc; 464564Speter char *highpc; 474514Speter { 484850Speter int monsize; 494850Speter char *buffer; 5049895Smckusick register int o; 51*52814Smckusick struct clockinfo clockinfo; 52*52814Smckusick int size; 534514Speter 549608Speter /* 559608Speter * round lowpc and highpc to multiples of the density we're using 569608Speter * so the rest of the scaling (here and in gprof) stays in ints. 579608Speter */ 589608Speter lowpc = (char *) 599608Speter ROUNDDOWN((unsigned)lowpc, HISTFRACTION*sizeof(HISTCOUNTER)); 604564Speter s_lowpc = lowpc; 619608Speter highpc = (char *) 629608Speter ROUNDUP((unsigned)highpc, HISTFRACTION*sizeof(HISTCOUNTER)); 634564Speter s_highpc = highpc; 644850Speter s_textsize = highpc - lowpc; 659608Speter monsize = (s_textsize / HISTFRACTION) + sizeof(struct phdr); 664564Speter buffer = sbrk( monsize ); 674564Speter if ( buffer == (char *) -1 ) { 68*52814Smckusick write( 2 , MSG , sizeof(MSG) ); 694564Speter return; 704564Speter } 7110268Smckusick froms = (unsigned short *) sbrk( s_textsize / HASHFRACTION ); 724564Speter if ( froms == (unsigned short *) -1 ) { 73*52814Smckusick write( 2 , MSG , sizeof(MSG) ); 744564Speter froms = 0; 754564Speter return; 764564Speter } 7710279Smckusick tolimit = s_textsize * ARCDENSITY / 100; 7810279Smckusick if ( tolimit < MINARCS ) { 7910279Smckusick tolimit = MINARCS; 8010279Smckusick } else if ( tolimit > 65534 ) { 8110279Smckusick tolimit = 65534; 829530Smckusick } 8310279Smckusick tos = (struct tostruct *) sbrk( tolimit * sizeof( struct tostruct ) ); 844564Speter if ( tos == (struct tostruct *) -1 ) { 85*52814Smckusick write( 2 , MSG , sizeof(MSG) ); 864564Speter froms = 0; 874564Speter tos = 0; 884564Speter return; 894564Speter } 9014127Smckusick minbrk = sbrk(0); 914564Speter tos[0].link = 0; 9249895Smckusick sbuf = buffer; 9349895Smckusick ssiz = monsize; 9449895Smckusick ( (struct phdr *) buffer ) -> lpc = lowpc; 9549895Smckusick ( (struct phdr *) buffer ) -> hpc = highpc; 9649895Smckusick ( (struct phdr *) buffer ) -> ncnt = ssiz; 97*52814Smckusick ( (struct phdr *) buffer ) -> version = GMONVERSION; 9849895Smckusick monsize -= sizeof(struct phdr); 9949895Smckusick if ( monsize <= 0 ) 10049895Smckusick return; 10149895Smckusick o = highpc - lowpc; 10249895Smckusick if( monsize < o ) 103*52814Smckusick #ifndef hp300 10449895Smckusick s_scale = ( (float) monsize / o ) * SCALE_1_TO_1; 105*52814Smckusick #else /* avoid floating point */ 106*52814Smckusick { 107*52814Smckusick int quot = o / monsize; 108*52814Smckusick 109*52814Smckusick if (quot >= 0x10000) 110*52814Smckusick s_scale = 1; 111*52814Smckusick else if (quot >= 0x100) 112*52814Smckusick s_scale = 0x10000 / quot; 113*52814Smckusick else if (o >= 0x800000) 114*52814Smckusick s_scale = 0x1000000 / (o / (monsize >> 8)); 115*52814Smckusick else 116*52814Smckusick s_scale = 0x1000000 / ((o << 8) / monsize); 117*52814Smckusick } 118*52814Smckusick #endif 11949895Smckusick else 12049895Smckusick s_scale = SCALE_1_TO_1; 12149895Smckusick moncontrol(1); 122*52814Smckusick size = sizeof( clockinfo ); 123*52814Smckusick if ( getkerninfo( KINFO_CLOCKRATE , &clockinfo , &size , 0 ) < 0 ) { 124*52814Smckusick /* 125*52814Smckusick * Best guess 126*52814Smckusick */ 127*52814Smckusick clockinfo.profhz = hertz(); 128*52814Smckusick } else if ( clockinfo.profhz == 0 ) { 129*52814Smckusick if ( clockinfo.hz != 0 ) 130*52814Smckusick clockinfo.profhz = clockinfo.hz; 131*52814Smckusick else 132*52814Smckusick clockinfo.profhz = hertz(); 133*52814Smckusick } 134*52814Smckusick ( (struct phdr *) buffer ) -> profrate = clockinfo.profhz; 1354514Speter } 1364514Speter 1374514Speter _mcleanup() 1384514Speter { 1394869Smckusic int fd; 1404869Smckusic int fromindex; 14110268Smckusick int endfrom; 1424869Smckusic char *frompc; 1434869Smckusic int toindex; 1444869Smckusic struct rawarc rawarc; 1454514Speter 14649895Smckusick moncontrol(0); 1474869Smckusic fd = creat( "gmon.out" , 0666 ); 1484869Smckusic if ( fd < 0 ) { 1494564Speter perror( "mcount: gmon.out" ); 1504514Speter return; 1514514Speter } 1524564Speter # ifdef DEBUG 1534564Speter fprintf( stderr , "[mcleanup] sbuf 0x%x ssiz %d\n" , sbuf , ssiz ); 1544564Speter # endif DEBUG 1554869Smckusic write( fd , sbuf , ssiz ); 15610268Smckusick endfrom = s_textsize / (HASHFRACTION * sizeof(*froms)); 15710268Smckusick for ( fromindex = 0 ; fromindex < endfrom ; fromindex++ ) { 1584514Speter if ( froms[fromindex] == 0 ) { 1594514Speter continue; 1604514Speter } 16110268Smckusick frompc = s_lowpc + (fromindex * HASHFRACTION * sizeof(*froms)); 1624514Speter for (toindex=froms[fromindex]; toindex!=0; toindex=tos[toindex].link) { 1634514Speter # ifdef DEBUG 1644748Speter fprintf( stderr , 1654748Speter "[mcleanup] frompc 0x%x selfpc 0x%x count %d\n" , 1664514Speter frompc , tos[toindex].selfpc , tos[toindex].count ); 1674514Speter # endif DEBUG 1684869Smckusic rawarc.raw_frompc = (unsigned long) frompc; 1694869Smckusic rawarc.raw_selfpc = (unsigned long) tos[toindex].selfpc; 1704869Smckusic rawarc.raw_count = tos[toindex].count; 1714869Smckusic write( fd , &rawarc , sizeof rawarc ); 1724514Speter } 1734514Speter } 1744869Smckusic close( fd ); 1754514Speter } 1764514Speter 1776177Smckusick /* 17811796Speter * Control profiling 17911796Speter * profiling is what mcount checks to see if 18011796Speter * all the data structures are ready. 18111796Speter */ 18211796Speter moncontrol(mode) 18311796Speter int mode; 18411796Speter { 18511796Speter if (mode) { 18611796Speter /* start */ 18711796Speter profil(sbuf + sizeof(struct phdr), ssiz - sizeof(struct phdr), 18848972Sdonn (int)s_lowpc, s_scale); 18911796Speter profiling = 0; 19011796Speter } else { 19111796Speter /* stop */ 19211796Speter profil((char *)0, 0, 0, 0); 19311796Speter profiling = 3; 19411796Speter } 19511796Speter } 196*52814Smckusick 197*52814Smckusick /* 198*52814Smckusick * discover the tick frequency of the machine 199*52814Smckusick * if something goes wrong, we return 0, an impossible hertz. 200*52814Smckusick */ 201*52814Smckusick 202*52814Smckusick hertz() 203*52814Smckusick { 204*52814Smckusick struct itimerval tim; 205*52814Smckusick 206*52814Smckusick tim.it_interval.tv_sec = 0; 207*52814Smckusick tim.it_interval.tv_usec = 1; 208*52814Smckusick tim.it_value.tv_sec = 0; 209*52814Smckusick tim.it_value.tv_usec = 0; 210*52814Smckusick setitimer(ITIMER_REAL, &tim, 0); 211*52814Smckusick setitimer(ITIMER_REAL, 0, &tim); 212*52814Smckusick if (tim.it_interval.tv_usec < 2) 213*52814Smckusick return(0); 214*52814Smckusick return (1000000 / tim.it_interval.tv_usec); 215*52814Smckusick } 216