xref: /csrg-svn/lib/libc/gmon/gmon.c (revision 61112)
147884Sbostic /*-
2*61112Sbostic  * Copyright (c) 1983, 1992, 1993
3*61112Sbostic  *	The Regents of the University of California.  All rights reserved.
447884Sbostic  *
549278Sbostic  * %sccs.include.redist.c%
621415Sdist  */
74514Speter 
854904Smckusick #if !defined(lint) && defined(LIBC_SCCS)
9*61112Sbostic static char sccsid[] = "@(#)gmon.c	8.1 (Berkeley) 06/04/93";
1054904Smckusick #endif
1121415Sdist 
1259391Sbostic #include <sys/param.h>
1352814Smckusick #include <sys/time.h>
1459391Sbostic #include <sys/gmon.h>
1558901Smckusick #include <sys/sysctl.h>
1648972Sdonn 
174514Speter #include <stdio.h>
1855187Smckusick #include <fcntl.h>
1959391Sbostic #include <unistd.h>
204514Speter 
2148972Sdonn extern char *minbrk asm ("minbrk");
2248972Sdonn 
2354903Smckusick struct gmonparam _gmonparam = { GMON_PROF_OFF };
244514Speter 
2511796Speter static int	s_scale;
2654903Smckusick /* see profil(2) where this is describe (incorrectly) */
2711998Speter #define		SCALE_1_TO_1	0x10000L
284514Speter 
2954903Smckusick #define ERR(s) write(2, s, sizeof(s))
304514Speter 
3160351Storek void	moncontrol __P((int));
3260351Storek static int hertz __P((void));
3360351Storek 
3460351Storek void
monstartup(lowpc,highpc)359433Smckusick monstartup(lowpc, highpc)
3654903Smckusick 	u_long lowpc;
3754903Smckusick 	u_long highpc;
384514Speter {
3954903Smckusick 	register int o;
4054903Smckusick 	char *cp;
4154903Smckusick 	struct gmonparam *p = &_gmonparam;
424514Speter 
439608Speter 	/*
4454903Smckusick 	 * round lowpc and highpc to multiples of the density we're using
4554903Smckusick 	 * so the rest of the scaling (here and in gprof) stays in ints.
469608Speter 	 */
4759560Smckusick 	p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
4859560Smckusick 	p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
4959560Smckusick 	p->textsize = p->highpc - p->lowpc;
5059560Smckusick 	p->kcountsize = p->textsize / HISTFRACTION;
5159560Smckusick 	p->hashfraction = HASHFRACTION;
5259560Smckusick 	p->fromssize = p->textsize / HASHFRACTION;
5359560Smckusick 	p->tolimit = p->textsize * ARCDENSITY / 100;
5459560Smckusick 	if (p->tolimit < MINARCS)
5559560Smckusick 		p->tolimit = MINARCS;
5659560Smckusick 	else if (p->tolimit > MAXARCS)
5759560Smckusick 		p->tolimit = MAXARCS;
5859560Smckusick 	p->tossize = p->tolimit * sizeof(struct tostruct);
5954903Smckusick 
6059560Smckusick 	cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
6154903Smckusick 	if (cp == (char *)-1) {
6254903Smckusick 		ERR("monstartup: out of memory\n");
6354903Smckusick 		return;
6454903Smckusick 	}
6554903Smckusick #ifdef notdef
6659560Smckusick 	bzero(cp, p->kcountsize + p->fromssize + p->tossize);
6754903Smckusick #endif
6854903Smckusick 	p->tos = (struct tostruct *)cp;
6959560Smckusick 	cp += p->tossize;
7059560Smckusick 	p->kcount = (u_short *)cp;
7159560Smckusick 	cp += p->kcountsize;
7254903Smckusick 	p->froms = (u_short *)cp;
7354903Smckusick 
7454903Smckusick 	minbrk = sbrk(0);
7554903Smckusick 	p->tos[0].link = 0;
7654903Smckusick 
7759560Smckusick 	o = p->highpc - p->lowpc;
7859560Smckusick 	if (p->kcountsize < o) {
7952814Smckusick #ifndef hp300
8059560Smckusick 		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
8152814Smckusick #else /* avoid floating point */
8259560Smckusick 		int quot = o / p->kcountsize;
8354903Smckusick 
8454903Smckusick 		if (quot >= 0x10000)
8554903Smckusick 			s_scale = 1;
8654903Smckusick 		else if (quot >= 0x100)
8754903Smckusick 			s_scale = 0x10000 / quot;
8854903Smckusick 		else if (o >= 0x800000)
8959560Smckusick 			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
9054903Smckusick 		else
9159560Smckusick 			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
9254903Smckusick #endif
9354903Smckusick 	} else
9454903Smckusick 		s_scale = SCALE_1_TO_1;
9552814Smckusick 
9654903Smckusick 	moncontrol(1);
974514Speter }
984514Speter 
9960351Storek void
_mcleanup()1004514Speter _mcleanup()
1014514Speter {
10254903Smckusick 	int fd;
10354903Smckusick 	int fromindex;
10454903Smckusick 	int endfrom;
10554903Smckusick 	u_long frompc;
10654903Smckusick 	int toindex;
10754903Smckusick 	struct rawarc rawarc;
10854903Smckusick 	struct gmonparam *p = &_gmonparam;
10959560Smckusick 	struct gmonhdr gmonhdr, *hdr;
11059560Smckusick 	struct clockinfo clockinfo;
11160351Storek 	int mib[2];
11260351Storek 	size_t size;
11360351Storek #ifdef DEBUG
11455187Smckusick 	int log, len;
11555187Smckusick 	char buf[200];
11660351Storek #endif
1174514Speter 
11854903Smckusick 	if (p->state == GMON_PROF_ERROR)
11954903Smckusick 		ERR("_mcleanup: tos overflow\n");
12054903Smckusick 
12159560Smckusick 	size = sizeof(clockinfo);
12259560Smckusick 	mib[0] = CTL_KERN;
12359560Smckusick 	mib[1] = KERN_CLOCKRATE;
12459560Smckusick 	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
12559560Smckusick 		/*
12659560Smckusick 		 * Best guess
12759560Smckusick 		 */
12859560Smckusick 		clockinfo.profhz = hertz();
12959560Smckusick 	} else if (clockinfo.profhz == 0) {
13059560Smckusick 		if (clockinfo.hz != 0)
13159560Smckusick 			clockinfo.profhz = clockinfo.hz;
13259560Smckusick 		else
13359560Smckusick 			clockinfo.profhz = hertz();
13459560Smckusick 	}
13559560Smckusick 
13654903Smckusick 	moncontrol(0);
13760351Storek 	fd = open("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
13854903Smckusick 	if (fd < 0) {
13954903Smckusick 		perror("mcount: gmon.out");
14054903Smckusick 		return;
1414514Speter 	}
14254903Smckusick #ifdef DEBUG
14355187Smckusick 	log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
14455187Smckusick 	if (log < 0) {
14555187Smckusick 		perror("mcount: gmon.log");
14655187Smckusick 		return;
14755187Smckusick 	}
14859560Smckusick 	len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n",
14959560Smckusick 	    p->kcount, p->kcountsize);
15055187Smckusick 	write(log, buf, len);
15154903Smckusick #endif
15259560Smckusick 	hdr = (struct gmonhdr *)&gmonhdr;
15359560Smckusick 	hdr->lpc = p->lowpc;
15459560Smckusick 	hdr->hpc = p->highpc;
15559560Smckusick 	hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
15659560Smckusick 	hdr->version = GMONVERSION;
15759560Smckusick 	hdr->profrate = clockinfo.profhz;
15859560Smckusick 	write(fd, (char *)hdr, sizeof *hdr);
15959560Smckusick 	write(fd, p->kcount, p->kcountsize);
16059560Smckusick 	endfrom = p->fromssize / sizeof(*p->froms);
16154903Smckusick 	for (fromindex = 0; fromindex < endfrom; fromindex++) {
16254903Smckusick 		if (p->froms[fromindex] == 0)
16354903Smckusick 			continue;
16454903Smckusick 
16554903Smckusick 		frompc = p->lowpc;
16659560Smckusick 		frompc += fromindex * p->hashfraction * sizeof(*p->froms);
16754903Smckusick 		for (toindex = p->froms[fromindex]; toindex != 0;
16854903Smckusick 		     toindex = p->tos[toindex].link) {
16954903Smckusick #ifdef DEBUG
17055187Smckusick 			len = sprintf(buf,
17155187Smckusick 			"[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
17254903Smckusick 				frompc, p->tos[toindex].selfpc,
17354903Smckusick 				p->tos[toindex].count);
17455187Smckusick 			write(log, buf, len);
17554903Smckusick #endif
17654903Smckusick 			rawarc.raw_frompc = frompc;
17754903Smckusick 			rawarc.raw_selfpc = p->tos[toindex].selfpc;
17854903Smckusick 			rawarc.raw_count = p->tos[toindex].count;
17954903Smckusick 			write(fd, &rawarc, sizeof rawarc);
18054903Smckusick 		}
1814514Speter 	}
18254903Smckusick 	close(fd);
1834514Speter }
1844514Speter 
1856177Smckusick /*
18611796Speter  * Control profiling
18711796Speter  *	profiling is what mcount checks to see if
18811796Speter  *	all the data structures are ready.
18911796Speter  */
19060351Storek void
moncontrol(mode)19111796Speter moncontrol(mode)
19254903Smckusick 	int mode;
19311796Speter {
19454903Smckusick 	struct gmonparam *p = &_gmonparam;
19554903Smckusick 
19654903Smckusick 	if (mode) {
19754903Smckusick 		/* start */
19859560Smckusick 		profil((char *)p->kcount, p->kcountsize, (int)p->lowpc,
19959560Smckusick 		    s_scale);
20054903Smckusick 		p->state = GMON_PROF_ON;
20154903Smckusick 	} else {
20254903Smckusick 		/* stop */
20354903Smckusick 		profil((char *)0, 0, 0, 0);
20454903Smckusick 		p->state = GMON_PROF_OFF;
20554903Smckusick 	}
20611796Speter }
20752814Smckusick 
20854903Smckusick /*
20954903Smckusick  * discover the tick frequency of the machine
21054903Smckusick  * if something goes wrong, we return 0, an impossible hertz.
21154903Smckusick  */
21260351Storek static int
hertz()21352814Smckusick hertz()
21452814Smckusick {
21552814Smckusick 	struct itimerval tim;
21654903Smckusick 
21752814Smckusick 	tim.it_interval.tv_sec = 0;
21852814Smckusick 	tim.it_interval.tv_usec = 1;
21952814Smckusick 	tim.it_value.tv_sec = 0;
22052814Smckusick 	tim.it_value.tv_usec = 0;
22152814Smckusick 	setitimer(ITIMER_REAL, &tim, 0);
22252814Smckusick 	setitimer(ITIMER_REAL, 0, &tim);
22352814Smckusick 	if (tim.it_interval.tv_usec < 2)
22452814Smckusick 		return(0);
22552814Smckusick 	return (1000000 / tim.it_interval.tv_usec);
22652814Smckusick }
22754903Smckusick 
22854903Smckusick 
229