xref: /original-bsd/lib/libc/gmon/gmon.c (revision c7ac4bd9)
1765c014eSbostic /*-
2*c7ac4bd9Sbostic  * Copyright (c) 1983, 1992, 1993
3*c7ac4bd9Sbostic  *	The Regents of the University of California.  All rights reserved.
4765c014eSbostic  *
592e1012bSbostic  * %sccs.include.redist.c%
61bbdfc7eSdist  */
71bbdfc7eSdist 
879cb2974Smckusick #if !defined(lint) && defined(LIBC_SCCS)
9*c7ac4bd9Sbostic static char sccsid[] = "@(#)gmon.c	8.1 (Berkeley) 06/04/93";
1079cb2974Smckusick #endif
11c06660d0Speter 
12b218084aSbostic #include <sys/param.h>
1351e5c269Smckusick #include <sys/time.h>
14b218084aSbostic #include <sys/gmon.h>
15c16e8556Smckusick #include <sys/sysctl.h>
16368a6872Sdonn 
17c06660d0Speter #include <stdio.h>
186e9962b0Smckusick #include <fcntl.h>
19b218084aSbostic #include <unistd.h>
209699256bSpeter 
21368a6872Sdonn extern char *minbrk asm ("minbrk");
22368a6872Sdonn 
23d06aaf11Smckusick struct gmonparam _gmonparam = { GMON_PROF_OFF };
24c06660d0Speter 
259b3bc73fSpeter static int	s_scale;
265e9f68a9Speter /* see profil(2) where this is describe (incorrectly) */
275e9f68a9Speter #define		SCALE_1_TO_1	0x10000L
28c06660d0Speter 
29d06aaf11Smckusick #define ERR(s) write(2, s, sizeof(s))
30d06aaf11Smckusick 
31b63fca47Storek void	moncontrol __P((int));
32b63fca47Storek static int hertz __P((void));
33b63fca47Storek 
34b63fca47Storek void
monstartup(lowpc,highpc)353252918bSmckusick monstartup(lowpc, highpc)
36d06aaf11Smckusick 	u_long lowpc;
37d06aaf11Smckusick 	u_long highpc;
38c06660d0Speter {
39645f7f03Smckusick 	register int o;
40d06aaf11Smckusick 	char *cp;
41d06aaf11Smckusick 	struct gmonparam *p = &_gmonparam;
42c06660d0Speter 
43f025804bSpeter 	/*
44f025804bSpeter 	 * round lowpc and highpc to multiples of the density we're using
45f025804bSpeter 	 * so the rest of the scaling (here and in gprof) stays in ints.
46f025804bSpeter 	 */
47b9a56342Smckusick 	p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
48b9a56342Smckusick 	p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
49b9a56342Smckusick 	p->textsize = p->highpc - p->lowpc;
50b9a56342Smckusick 	p->kcountsize = p->textsize / HISTFRACTION;
51b9a56342Smckusick 	p->hashfraction = HASHFRACTION;
52b9a56342Smckusick 	p->fromssize = p->textsize / HASHFRACTION;
53b9a56342Smckusick 	p->tolimit = p->textsize * ARCDENSITY / 100;
54b9a56342Smckusick 	if (p->tolimit < MINARCS)
55b9a56342Smckusick 		p->tolimit = MINARCS;
56b9a56342Smckusick 	else if (p->tolimit > MAXARCS)
57b9a56342Smckusick 		p->tolimit = MAXARCS;
58b9a56342Smckusick 	p->tossize = p->tolimit * sizeof(struct tostruct);
59d06aaf11Smckusick 
60b9a56342Smckusick 	cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
61d06aaf11Smckusick 	if (cp == (char *)-1) {
62d06aaf11Smckusick 		ERR("monstartup: out of memory\n");
63c06660d0Speter 		return;
64c06660d0Speter 	}
65d06aaf11Smckusick #ifdef notdef
66b9a56342Smckusick 	bzero(cp, p->kcountsize + p->fromssize + p->tossize);
67d06aaf11Smckusick #endif
68d06aaf11Smckusick 	p->tos = (struct tostruct *)cp;
69b9a56342Smckusick 	cp += p->tossize;
70b9a56342Smckusick 	p->kcount = (u_short *)cp;
71b9a56342Smckusick 	cp += p->kcountsize;
72d06aaf11Smckusick 	p->froms = (u_short *)cp;
73d06aaf11Smckusick 
741f3b6987Smckusick 	minbrk = sbrk(0);
75d06aaf11Smckusick 	p->tos[0].link = 0;
76d06aaf11Smckusick 
77b9a56342Smckusick 	o = p->highpc - p->lowpc;
78b9a56342Smckusick 	if (p->kcountsize < o) {
7951e5c269Smckusick #ifndef hp300
80b9a56342Smckusick 		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
8151e5c269Smckusick #else /* avoid floating point */
82b9a56342Smckusick 		int quot = o / p->kcountsize;
8351e5c269Smckusick 
8451e5c269Smckusick 		if (quot >= 0x10000)
8551e5c269Smckusick 			s_scale = 1;
8651e5c269Smckusick 		else if (quot >= 0x100)
8751e5c269Smckusick 			s_scale = 0x10000 / quot;
8851e5c269Smckusick 		else if (o >= 0x800000)
89b9a56342Smckusick 			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
9051e5c269Smckusick 		else
91b9a56342Smckusick 			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
9251e5c269Smckusick #endif
93d06aaf11Smckusick 	} else
94645f7f03Smckusick 		s_scale = SCALE_1_TO_1;
95d06aaf11Smckusick 
96645f7f03Smckusick 	moncontrol(1);
97c06660d0Speter }
98c06660d0Speter 
99b63fca47Storek void
_mcleanup()100c06660d0Speter _mcleanup()
101c06660d0Speter {
102536340e2Smckusic 	int fd;
103c06660d0Speter 	int fromindex;
104eb6779cfSmckusick 	int endfrom;
105d06aaf11Smckusick 	u_long frompc;
106c06660d0Speter 	int toindex;
107536340e2Smckusic 	struct rawarc rawarc;
108d06aaf11Smckusick 	struct gmonparam *p = &_gmonparam;
109b9a56342Smckusick 	struct gmonhdr gmonhdr, *hdr;
110b9a56342Smckusick 	struct clockinfo clockinfo;
111b63fca47Storek 	int mib[2];
112b63fca47Storek 	size_t size;
113b63fca47Storek #ifdef DEBUG
1146e9962b0Smckusick 	int log, len;
1156e9962b0Smckusick 	char buf[200];
116b63fca47Storek #endif
117d06aaf11Smckusick 
118d06aaf11Smckusick 	if (p->state == GMON_PROF_ERROR)
119d06aaf11Smckusick 		ERR("_mcleanup: tos overflow\n");
120c06660d0Speter 
121b9a56342Smckusick 	size = sizeof(clockinfo);
122b9a56342Smckusick 	mib[0] = CTL_KERN;
123b9a56342Smckusick 	mib[1] = KERN_CLOCKRATE;
124b9a56342Smckusick 	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
125b9a56342Smckusick 		/*
126b9a56342Smckusick 		 * Best guess
127b9a56342Smckusick 		 */
128b9a56342Smckusick 		clockinfo.profhz = hertz();
129b9a56342Smckusick 	} else if (clockinfo.profhz == 0) {
130b9a56342Smckusick 		if (clockinfo.hz != 0)
131b9a56342Smckusick 			clockinfo.profhz = clockinfo.hz;
132b9a56342Smckusick 		else
133b9a56342Smckusick 			clockinfo.profhz = hertz();
134b9a56342Smckusick 	}
135b9a56342Smckusick 
136645f7f03Smckusick 	moncontrol(0);
137b63fca47Storek 	fd = open("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
138536340e2Smckusic 	if (fd < 0) {
1399699256bSpeter 		perror("mcount: gmon.out");
140c06660d0Speter 		return;
141c06660d0Speter 	}
1429699256bSpeter #ifdef DEBUG
1436e9962b0Smckusick 	log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
1446e9962b0Smckusick 	if (log < 0) {
1456e9962b0Smckusick 		perror("mcount: gmon.log");
1466e9962b0Smckusick 		return;
1476e9962b0Smckusick 	}
148b9a56342Smckusick 	len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n",
149b9a56342Smckusick 	    p->kcount, p->kcountsize);
1506e9962b0Smckusick 	write(log, buf, len);
151d06aaf11Smckusick #endif
152b9a56342Smckusick 	hdr = (struct gmonhdr *)&gmonhdr;
153b9a56342Smckusick 	hdr->lpc = p->lowpc;
154b9a56342Smckusick 	hdr->hpc = p->highpc;
155b9a56342Smckusick 	hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
156b9a56342Smckusick 	hdr->version = GMONVERSION;
157b9a56342Smckusick 	hdr->profrate = clockinfo.profhz;
158b9a56342Smckusick 	write(fd, (char *)hdr, sizeof *hdr);
159b9a56342Smckusick 	write(fd, p->kcount, p->kcountsize);
160b9a56342Smckusick 	endfrom = p->fromssize / sizeof(*p->froms);
161eb6779cfSmckusick 	for (fromindex = 0; fromindex < endfrom; fromindex++) {
162d06aaf11Smckusick 		if (p->froms[fromindex] == 0)
163c06660d0Speter 			continue;
164d06aaf11Smckusick 
165d06aaf11Smckusick 		frompc = p->lowpc;
166b9a56342Smckusick 		frompc += fromindex * p->hashfraction * sizeof(*p->froms);
167d06aaf11Smckusick 		for (toindex = p->froms[fromindex]; toindex != 0;
168d06aaf11Smckusick 		     toindex = p->tos[toindex].link) {
169c06660d0Speter #ifdef DEBUG
1706e9962b0Smckusick 			len = sprintf(buf,
1716e9962b0Smckusick 			"[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
172d06aaf11Smckusick 				frompc, p->tos[toindex].selfpc,
173d06aaf11Smckusick 				p->tos[toindex].count);
1746e9962b0Smckusick 			write(log, buf, len);
175d06aaf11Smckusick #endif
176d06aaf11Smckusick 			rawarc.raw_frompc = frompc;
177d06aaf11Smckusick 			rawarc.raw_selfpc = p->tos[toindex].selfpc;
178d06aaf11Smckusick 			rawarc.raw_count = p->tos[toindex].count;
179536340e2Smckusic 			write(fd, &rawarc, sizeof rawarc);
180c06660d0Speter 		}
181c06660d0Speter 	}
182536340e2Smckusic 	close(fd);
183c06660d0Speter }
184c06660d0Speter 
1859b3bc73fSpeter /*
1869b3bc73fSpeter  * Control profiling
1879b3bc73fSpeter  *	profiling is what mcount checks to see if
1889b3bc73fSpeter  *	all the data structures are ready.
1899b3bc73fSpeter  */
190b63fca47Storek void
moncontrol(mode)1919b3bc73fSpeter moncontrol(mode)
1929b3bc73fSpeter 	int mode;
1939b3bc73fSpeter {
194d06aaf11Smckusick 	struct gmonparam *p = &_gmonparam;
195d06aaf11Smckusick 
1969b3bc73fSpeter 	if (mode) {
1979b3bc73fSpeter 		/* start */
198b9a56342Smckusick 		profil((char *)p->kcount, p->kcountsize, (int)p->lowpc,
199b9a56342Smckusick 		    s_scale);
200d06aaf11Smckusick 		p->state = GMON_PROF_ON;
2019b3bc73fSpeter 	} else {
2029b3bc73fSpeter 		/* stop */
2039b3bc73fSpeter 		profil((char *)0, 0, 0, 0);
204d06aaf11Smckusick 		p->state = GMON_PROF_OFF;
2059b3bc73fSpeter 	}
206c06660d0Speter }
20751e5c269Smckusick 
20851e5c269Smckusick /*
20951e5c269Smckusick  * discover the tick frequency of the machine
21051e5c269Smckusick  * if something goes wrong, we return 0, an impossible hertz.
21151e5c269Smckusick  */
212b63fca47Storek static int
hertz()21351e5c269Smckusick hertz()
21451e5c269Smckusick {
21551e5c269Smckusick 	struct itimerval tim;
21651e5c269Smckusick 
21751e5c269Smckusick 	tim.it_interval.tv_sec = 0;
21851e5c269Smckusick 	tim.it_interval.tv_usec = 1;
21951e5c269Smckusick 	tim.it_value.tv_sec = 0;
22051e5c269Smckusick 	tim.it_value.tv_usec = 0;
22151e5c269Smckusick 	setitimer(ITIMER_REAL, &tim, 0);
22251e5c269Smckusick 	setitimer(ITIMER_REAL, 0, &tim);
22351e5c269Smckusick 	if (tim.it_interval.tv_usec < 2)
22451e5c269Smckusick 		return(0);
22551e5c269Smckusick 	return (1000000 / tim.it_interval.tv_usec);
22651e5c269Smckusick }
227d06aaf11Smckusick 
228d06aaf11Smckusick 
229