gmon.c revision 1.8
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 rcsid[] = "$OpenBSD: gmon.c,v 1.8 1997/07/23 21:11:27 kstailey Exp $";
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 <stdlib.h>
45#include <string.h>
46#include <fcntl.h>
47#include <limits.h>
48#include <unistd.h>
49
50extern char *minbrk __asm ("minbrk");
51
52struct gmonparam _gmonparam = { GMON_PROF_OFF };
53
54static int	s_scale;
55/* see profil(2) where this is describe (incorrectly) */
56#define		SCALE_1_TO_1	0x10000L
57
58#define ERR(s) write(2, s, sizeof(s))
59
60void	moncontrol __P((int));
61static int hertz __P((void));
62
63void
64monstartup(lowpc, highpc)
65	u_long lowpc;
66	u_long highpc;
67{
68	register int o;
69	char *cp;
70	struct gmonparam *p = &_gmonparam;
71
72	/*
73	 * round lowpc and highpc to multiples of the density we're using
74	 * so the rest of the scaling (here and in gprof) stays in ints.
75	 */
76	p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
77	p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
78	p->textsize = p->highpc - p->lowpc;
79	p->kcountsize = p->textsize / HISTFRACTION;
80	p->hashfraction = HASHFRACTION;
81	p->fromssize = p->textsize / p->hashfraction;
82	p->tolimit = p->textsize * ARCDENSITY / 100;
83	if (p->tolimit < MINARCS)
84		p->tolimit = MINARCS;
85	else if (p->tolimit > MAXARCS)
86		p->tolimit = MAXARCS;
87	p->tossize = p->tolimit * sizeof(struct tostruct);
88
89	cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
90	if (cp == (char *)-1) {
91		ERR("monstartup: out of memory\n");
92		return;
93	}
94#ifdef notdef
95	bzero(cp, p->kcountsize + p->fromssize + p->tossize);
96#endif
97	p->tos = (struct tostruct *)cp;
98	cp += p->tossize;
99	p->kcount = (u_short *)cp;
100	cp += p->kcountsize;
101	p->froms = (u_short *)cp;
102
103	minbrk = sbrk(0);
104	p->tos[0].link = 0;
105
106	o = p->highpc - p->lowpc;
107	if (p->kcountsize < o) {
108#ifndef notdef
109		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
110#else /* avoid floating point */
111		int quot = o / p->kcountsize;
112
113		if (quot >= 0x10000)
114			s_scale = 1;
115		else if (quot >= 0x100)
116			s_scale = 0x10000 / quot;
117		else if (o >= 0x800000)
118			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
119		else
120			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
121#endif
122	} else
123		s_scale = SCALE_1_TO_1;
124
125	moncontrol(1);
126}
127
128void
129_mcleanup()
130{
131	int fd;
132	int fromindex;
133	int endfrom;
134	u_long frompc;
135	int toindex;
136	struct rawarc rawarc;
137	struct gmonparam *p = &_gmonparam;
138	struct gmonhdr gmonhdr, *hdr;
139	struct clockinfo clockinfo;
140	int mib[2];
141	size_t size;
142	char *profdir;
143	char *proffile;
144	char  buf[PATH_MAX];
145#ifdef DEBUG
146	int log, len;
147	char dbuf[200];
148#endif
149
150	if (p->state == GMON_PROF_ERROR)
151		ERR("_mcleanup: tos overflow\n");
152
153	size = sizeof(clockinfo);
154	mib[0] = CTL_KERN;
155	mib[1] = KERN_CLOCKRATE;
156	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
157		/*
158		 * Best guess
159		 */
160		clockinfo.profhz = hertz();
161	} else if (clockinfo.profhz == 0) {
162		if (clockinfo.hz != 0)
163			clockinfo.profhz = clockinfo.hz;
164		else
165			clockinfo.profhz = hertz();
166	}
167
168	moncontrol(0);
169
170	if (issetugid() == 0 && (profdir = getenv("PROFDIR")) != NULL) {
171		extern char *__progname;
172		char *s, *t, *limit;
173		pid_t pid;
174		long divisor;
175
176		/* If PROFDIR contains a null value, no profiling
177		   output is produced */
178		if (*profdir == '\0') {
179			return;
180		}
181
182		limit = buf + sizeof buf - 1 - 10 - 1 -
183		    strlen(__progname) - 1;
184		t = buf;
185		s = profdir;
186		while((*t = *s) != '\0' && t < limit) {
187			t++;
188			s++;
189		}
190		*t++ = '/';
191
192		/*
193		 * Copy and convert pid from a pid_t to a string.  For
194		 * best performance, divisor should be initialized to
195		 * the largest power of 10 less than PID_MAX.
196		 */
197		pid = getpid();
198		divisor=10000;
199		while (divisor > pid) divisor /= 10;	/* skip leading zeros */
200		do {
201			*t++ = (pid/divisor) + '0';
202			pid %= divisor;
203		} while (divisor /= 10);
204		*t++ = '.';
205
206		s = __progname;
207		while ((*t++ = *s++) != '\0')
208			;
209
210		proffile = buf;
211	} else {
212		proffile = "gmon.out";
213	}
214
215	fd = open(proffile , O_CREAT|O_TRUNC|O_WRONLY, 0666);
216	if (fd < 0) {
217		perror( proffile );
218		return;
219	}
220#ifdef DEBUG
221	log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
222	if (log < 0) {
223		perror("mcount: gmon.log");
224		return;
225	}
226	len = sprintf(dbuf, "[mcleanup1] kcount 0x%x ssiz %d\n",
227	    p->kcount, p->kcountsize);
228	write(log, dbuf, len);
229#endif
230	hdr = (struct gmonhdr *)&gmonhdr;
231	hdr->lpc = p->lowpc;
232	hdr->hpc = p->highpc;
233	hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
234	hdr->version = GMONVERSION;
235	hdr->profrate = clockinfo.profhz;
236	write(fd, (char *)hdr, sizeof *hdr);
237	write(fd, p->kcount, p->kcountsize);
238	endfrom = p->fromssize / sizeof(*p->froms);
239	for (fromindex = 0; fromindex < endfrom; fromindex++) {
240		if (p->froms[fromindex] == 0)
241			continue;
242
243		frompc = p->lowpc;
244		frompc += fromindex * p->hashfraction * sizeof(*p->froms);
245		for (toindex = p->froms[fromindex]; toindex != 0;
246		     toindex = p->tos[toindex].link) {
247#ifdef DEBUG
248			len = sprintf(dbuf,
249			"[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
250				frompc, p->tos[toindex].selfpc,
251				p->tos[toindex].count);
252			write(log, dbuf, len);
253#endif
254			rawarc.raw_frompc = frompc;
255			rawarc.raw_selfpc = p->tos[toindex].selfpc;
256			rawarc.raw_count = p->tos[toindex].count;
257			write(fd, &rawarc, sizeof rawarc);
258		}
259	}
260	close(fd);
261}
262
263/*
264 * Control profiling
265 *	profiling is what mcount checks to see if
266 *	all the data structures are ready.
267 */
268void
269moncontrol(mode)
270	int mode;
271{
272	struct gmonparam *p = &_gmonparam;
273
274	if (mode) {
275		/* start */
276		profil((char *)p->kcount, p->kcountsize, p->lowpc,
277		    s_scale);
278		p->state = GMON_PROF_ON;
279	} else {
280		/* stop */
281		profil((char *)0, 0, 0, 0);
282		p->state = GMON_PROF_OFF;
283	}
284}
285
286/*
287 * discover the tick frequency of the machine
288 * if something goes wrong, we return 0, an impossible hertz.
289 */
290static int
291hertz()
292{
293	struct itimerval tim;
294
295	tim.it_interval.tv_sec = 0;
296	tim.it_interval.tv_usec = 1;
297	tim.it_value.tv_sec = 0;
298	tim.it_value.tv_usec = 0;
299	setitimer(ITIMER_REAL, &tim, 0);
300	setitimer(ITIMER_REAL, 0, &tim);
301	if (tim.it_interval.tv_usec < 2)
302		return(0);
303	return (1000000 / tim.it_interval.tv_usec);
304}
305
306
307