gmon.c revision 15634
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
47#if defined(__ELF__)
48extern char *minbrk asm (".minbrk");
49#else
50extern char *minbrk asm ("minbrk");
51#endif
52
53struct gmonparam _gmonparam = { GMON_PROF_OFF };
54
55static int	s_scale;
56/* see profil(2) where this is describe (incorrectly) */
57#define		SCALE_1_TO_1	0x10000L
58
59#define ERR(s) write(2, s, sizeof(s))
60
61void	moncontrol __P((int));
62static int hertz __P((void));
63
64void
65monstartup(lowpc, highpc)
66	u_long lowpc;
67	u_long highpc;
68{
69	register int o;
70	char *cp;
71	struct gmonparam *p = &_gmonparam;
72
73	/*
74	 * round lowpc and highpc to multiples of the density we're using
75	 * so the rest of the scaling (here and in gprof) stays in ints.
76	 */
77	p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
78	p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
79	p->textsize = p->highpc - p->lowpc;
80	p->kcountsize = p->textsize / HISTFRACTION;
81	p->hashfraction = HASHFRACTION;
82	p->fromssize = p->textsize / HASHFRACTION;
83	p->tolimit = p->textsize * ARCDENSITY / 100;
84	if (p->tolimit < MINARCS)
85		p->tolimit = MINARCS;
86	else if (p->tolimit > MAXARCS)
87		p->tolimit = MAXARCS;
88	p->tossize = p->tolimit * sizeof(struct tostruct);
89
90	cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
91	if (cp == (char *)-1) {
92		ERR("monstartup: out of memory\n");
93		return;
94	}
95#ifdef notdef
96	bzero(cp, p->kcountsize + p->fromssize + p->tossize);
97#endif
98	p->tos = (struct tostruct *)cp;
99	cp += p->tossize;
100	p->kcount = (u_short *)cp;
101	cp += p->kcountsize;
102	p->froms = (u_short *)cp;
103
104	minbrk = sbrk(0);
105	p->tos[0].link = 0;
106
107	o = p->highpc - p->lowpc;
108	if (p->kcountsize < o) {
109#ifndef hp300
110		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
111#else /* avoid floating point */
112		int quot = o / p->kcountsize;
113
114		if (quot >= 0x10000)
115			s_scale = 1;
116		else if (quot >= 0x100)
117			s_scale = 0x10000 / quot;
118		else if (o >= 0x800000)
119			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
120		else
121			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
122#endif
123	} else
124		s_scale = SCALE_1_TO_1;
125
126	moncontrol(1);
127}
128
129void
130_mcleanup()
131{
132	int fd;
133	int fromindex;
134	int endfrom;
135	u_long frompc;
136	int toindex;
137	struct rawarc rawarc;
138	struct gmonparam *p = &_gmonparam;
139	struct gmonhdr gmonhdr, *hdr;
140	struct clockinfo clockinfo;
141	int mib[2];
142	size_t size;
143#ifdef DEBUG
144	int log, len;
145	char buf[200];
146#endif
147
148	if (p->state == GMON_PROF_ERROR)
149		ERR("_mcleanup: tos overflow\n");
150
151	size = sizeof(clockinfo);
152	mib[0] = CTL_KERN;
153	mib[1] = KERN_CLOCKRATE;
154	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
155		/*
156		 * Best guess
157		 */
158		clockinfo.profhz = hertz();
159	} else if (clockinfo.profhz == 0) {
160		if (clockinfo.hz != 0)
161			clockinfo.profhz = clockinfo.hz;
162		else
163			clockinfo.profhz = hertz();
164	}
165
166	moncontrol(0);
167	fd = open("gmon.out", O_CREAT|O_TRUNC|O_WRONLY, 0666);
168	if (fd < 0) {
169		perror("mcount: gmon.out");
170		return;
171	}
172#ifdef DEBUG
173	log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
174	if (log < 0) {
175		perror("mcount: gmon.log");
176		return;
177	}
178	len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n",
179	    p->kcount, p->kcountsize);
180	write(log, buf, len);
181#endif
182	hdr = (struct gmonhdr *)&gmonhdr;
183	hdr->lpc = p->lowpc;
184	hdr->hpc = p->highpc;
185	hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
186	hdr->version = GMONVERSION;
187	hdr->profrate = clockinfo.profhz;
188	write(fd, (char *)hdr, sizeof *hdr);
189	write(fd, p->kcount, p->kcountsize);
190	endfrom = p->fromssize / sizeof(*p->froms);
191	for (fromindex = 0; fromindex < endfrom; fromindex++) {
192		if (p->froms[fromindex] == 0)
193			continue;
194
195		frompc = p->lowpc;
196		frompc += fromindex * p->hashfraction * sizeof(*p->froms);
197		for (toindex = p->froms[fromindex]; toindex != 0;
198		     toindex = p->tos[toindex].link) {
199#ifdef DEBUG
200			len = sprintf(buf,
201			"[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
202				frompc, p->tos[toindex].selfpc,
203				p->tos[toindex].count);
204			write(log, buf, len);
205#endif
206			rawarc.raw_frompc = frompc;
207			rawarc.raw_selfpc = p->tos[toindex].selfpc;
208			rawarc.raw_count = p->tos[toindex].count;
209			write(fd, &rawarc, sizeof rawarc);
210		}
211	}
212	close(fd);
213}
214
215/*
216 * Control profiling
217 *	profiling is what mcount checks to see if
218 *	all the data structures are ready.
219 */
220void
221moncontrol(mode)
222	int mode;
223{
224	struct gmonparam *p = &_gmonparam;
225
226	if (mode) {
227		/* start */
228		profil((char *)p->kcount, p->kcountsize, (int)p->lowpc,
229		    s_scale);
230		p->state = GMON_PROF_ON;
231	} else {
232		/* stop */
233		profil((char *)0, 0, 0, 0);
234		p->state = GMON_PROF_OFF;
235	}
236}
237
238/*
239 * discover the tick frequency of the machine
240 * if something goes wrong, we return 0, an impossible hertz.
241 */
242static int
243hertz()
244{
245	struct itimerval tim;
246
247	tim.it_interval.tv_sec = 0;
248	tim.it_interval.tv_usec = 1;
249	tim.it_value.tv_sec = 0;
250	tim.it_value.tv_usec = 0;
251	setitimer(ITIMER_REAL, &tim, 0);
252	setitimer(ITIMER_REAL, 0, &tim);
253	if (tim.it_interval.tv_usec < 2)
254		return(0);
255	return (1000000 / tim.it_interval.tv_usec);
256}
257
258
259