xref: /csrg-svn/lib/libc/gmon/gmon.c (revision 52814)
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