gmon.c revision 1574
1/*-
2 * Copyright (c) 1983, 1992, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if !defined(lint) && defined(LIBC_SCCS)
35static char sccsid[] = "@(#)gmon.c	8.1 (Berkeley) 6/4/93";
36#endif
37
38#include <sys/param.h>
39#include <sys/time.h>
40#include <sys/gmon.h>
41#include <sys/sysctl.h>
42
43#include <stdio.h>
44#include <fcntl.h>
45#include <unistd.h>
46
47extern char *minbrk asm ("minbrk");
48
49struct gmonparam _gmonparam = { GMON_PROF_OFF };
50
51static int	s_scale;
52/* see profil(2) where this is describe (incorrectly) */
53#define		SCALE_1_TO_1	0x10000L
54
55#define ERR(s) write(2, s, sizeof(s))
56
57void	moncontrol __P((int));
58static int hertz __P((void));
59
60void
61monstartup(lowpc, highpc)
62	u_long lowpc;
63	u_long highpc;
64{
65	register int o;
66	char *cp;
67	struct gmonparam *p = &_gmonparam;
68
69	/*
70	 * round lowpc and highpc to multiples of the density we're using
71	 * so the rest of the scaling (here and in gprof) stays in ints.
72	 */
73	p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
74	p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
75	p->textsize = p->highpc - p->lowpc;
76	p->kcountsize = p->textsize / HISTFRACTION;
77	p->hashfraction = HASHFRACTION;
78	p->fromssize = p->textsize / HASHFRACTION;
79	p->tolimit = p->textsize * ARCDENSITY / 100;
80	if (p->tolimit < MINARCS)
81		p->tolimit = MINARCS;
82	else if (p->tolimit > MAXARCS)
83		p->tolimit = MAXARCS;
84	p->tossize = p->tolimit * sizeof(struct tostruct);
85
86	cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
87	if (cp == (char *)-1) {
88		ERR("monstartup: out of memory\n");
89		return;
90	}
91#ifdef notdef
92	bzero(cp, p->kcountsize + p->fromssize + p->tossize);
93#endif
94	p->tos = (struct tostruct *)cp;
95	cp += p->tossize;
96	p->kcount = (u_short *)cp;
97	cp += p->kcountsize;
98	p->froms = (u_short *)cp;
99
100	minbrk = sbrk(0);
101	p->tos[0].link = 0;
102
103	o = p->highpc - p->lowpc;
104	if (p->kcountsize < o) {
105#ifndef hp300
106		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
107#else /* avoid floating point */
108		int quot = o / p->kcountsize;
109
110		if (quot >= 0x10000)
111			s_scale = 1;
112		else if (quot >= 0x100)
113			s_scale = 0x10000 / quot;
114		else if (o >= 0x800000)
115			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
116		else
117			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
118#endif
119	} else
120		s_scale = SCALE_1_TO_1;
121
122	moncontrol(1);
123}
124
125void
126_mcleanup()
127{
128	int fd;
129	int fromindex;
130	int endfrom;
131	u_long frompc;
132	int toindex;
133	struct rawarc rawarc;
134	struct gmonparam *p = &_gmonparam;
135	struct gmonhdr gmonhdr, *hdr;
136	struct clockinfo clockinfo;
137	int mib[2];
138	size_t size;
139#ifdef DEBUG
140	int log, len;
141	char buf[200];
142#endif
143
144	if (p->state == GMON_PROF_ERROR)
145		ERR("_mcleanup: tos overflow\n");
146
147	size = sizeof(clockinfo);
148	mib[0] = CTL_KERN;
149	mib[1] = KERN_CLOCKRATE;
150	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
151		/*
152		 * Best guess
153		 */
154		clockinfo.profhz = hertz();
155	} else if (clockinfo.profhz == 0) {
156		if (clockinfo.hz != 0)
157			clockinfo.profhz = clockinfo.hz;
158		else
159			clockinfo.profhz = hertz();
160	}
161
162	moncontrol(0);
163	fd = open("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
164	if (fd < 0) {
165		perror("mcount: gmon.out");
166		return;
167	}
168#ifdef DEBUG
169	log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
170	if (log < 0) {
171		perror("mcount: gmon.log");
172		return;
173	}
174	len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n",
175	    p->kcount, p->kcountsize);
176	write(log, buf, len);
177#endif
178	hdr = (struct gmonhdr *)&gmonhdr;
179	hdr->lpc = p->lowpc;
180	hdr->hpc = p->highpc;
181	hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
182	hdr->version = GMONVERSION;
183	hdr->profrate = clockinfo.profhz;
184	write(fd, (char *)hdr, sizeof *hdr);
185	write(fd, p->kcount, p->kcountsize);
186	endfrom = p->fromssize / sizeof(*p->froms);
187	for (fromindex = 0; fromindex < endfrom; fromindex++) {
188		if (p->froms[fromindex] == 0)
189			continue;
190
191		frompc = p->lowpc;
192		frompc += fromindex * p->hashfraction * sizeof(*p->froms);
193		for (toindex = p->froms[fromindex]; toindex != 0;
194		     toindex = p->tos[toindex].link) {
195#ifdef DEBUG
196			len = sprintf(buf,
197			"[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
198				frompc, p->tos[toindex].selfpc,
199				p->tos[toindex].count);
200			write(log, buf, len);
201#endif
202			rawarc.raw_frompc = frompc;
203			rawarc.raw_selfpc = p->tos[toindex].selfpc;
204			rawarc.raw_count = p->tos[toindex].count;
205			write(fd, &rawarc, sizeof rawarc);
206		}
207	}
208	close(fd);
209}
210
211/*
212 * Control profiling
213 *	profiling is what mcount checks to see if
214 *	all the data structures are ready.
215 */
216void
217moncontrol(mode)
218	int mode;
219{
220	struct gmonparam *p = &_gmonparam;
221
222	if (mode) {
223		/* start */
224		profil((char *)p->kcount, p->kcountsize, (int)p->lowpc,
225		    s_scale);
226		p->state = GMON_PROF_ON;
227	} else {
228		/* stop */
229		profil((char *)0, 0, 0, 0);
230		p->state = GMON_PROF_OFF;
231	}
232}
233
234/*
235 * discover the tick frequency of the machine
236 * if something goes wrong, we return 0, an impossible hertz.
237 */
238static int
239hertz()
240{
241	struct itimerval tim;
242
243	tim.it_interval.tv_sec = 0;
244	tim.it_interval.tv_usec = 1;
245	tim.it_value.tv_sec = 0;
246	tim.it_value.tv_usec = 0;
247	setitimer(ITIMER_REAL, &tim, 0);
248	setitimer(ITIMER_REAL, 0, &tim);
249	if (tim.it_interval.tv_usec < 2)
250		return(0);
251	return (1000000 / tim.it_interval.tv_usec);
252}
253
254
255