gmon.c revision 90046
190075Sobrien/*-
2169689Skan * Copyright (c) 1983, 1992, 1993
390075Sobrien *	The Regents of the University of California.  All rights reserved.
490075Sobrien *
5132718Skan * Redistribution and use in source and binary forms, with or without
690075Sobrien * modification, are permitted provided that the following conditions
7132718Skan * are met:
890075Sobrien * 1. Redistributions of source code must retain the above copyright
990075Sobrien *    notice, this list of conditions and the following disclaimer.
1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1190075Sobrien *    notice, this list of conditions and the following disclaimer in the
12132718Skan *    documentation and/or other materials provided with the distribution.
1390075Sobrien * 3. All advertising materials mentioning features or use of this software
1490075Sobrien *    must display the following acknowledgement:
1590075Sobrien *	This product includes software developed by the University of
1690075Sobrien *	California, Berkeley and its contributors.
1790075Sobrien * 4. Neither the name of the University nor the names of its contributors
18132718Skan *    may be used to endorse or promote products derived from this software
19169689Skan *    without specific prior written permission.
20169689Skan *
2190075Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2290075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2390075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24132718Skan * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2690075Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2790075Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2890075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2990075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30169689Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31169689Skan * SUCH DAMAGE.
3290075Sobrien */
33169689Skan
3490075Sobrien#if !defined(lint) && defined(LIBC_SCCS)
35169689Skanstatic char sccsid[] = "@(#)gmon.c	8.1 (Berkeley) 6/4/93";
36169689Skan#endif
3790075Sobrien#include <sys/cdefs.h>
3890075Sobrien__FBSDID("$FreeBSD: head/lib/libc/gmon/gmon.c 90046 2002-02-01 01:39:09Z obrien $");
3990075Sobrien
40169689Skan#include "namespace.h"
41169689Skan#include <sys/param.h>
4290075Sobrien#include <sys/time.h>
43169689Skan#include <sys/gmon.h>
44169689Skan#include <sys/sysctl.h>
4590075Sobrien
4690075Sobrien#include <err.h>
4790075Sobrien#include <errno.h>
48132718Skan#include <stdio.h>
49132718Skan#include <fcntl.h>
50169689Skan#include <string.h>
51169689Skan#include <unistd.h>
52169689Skan#include "un-namespace.h"
53169689Skan
5490075Sobrien#if defined(__ELF__) && (defined(i386) || defined(__sparc64__))
5590075Sobrienextern char *minbrk asm (".minbrk");
5690075Sobrien#else
5790075Sobrienextern char *minbrk asm ("minbrk");
5890075Sobrien#endif
5990075Sobrien
6090075Sobrienextern char *__progname;
6190075Sobrien
6290075Sobrienstruct gmonparam _gmonparam = { GMON_PROF_OFF };
6390075Sobrien
64132718Skanstatic int	s_scale;
6590075Sobrien/* see profil(2) where this is describe (incorrectly) */
66169689Skan#define		SCALE_1_TO_1	0x10000L
6790075Sobrien
6890075Sobrien#define ERR(s) _write(2, s, sizeof(s))
6990075Sobrien
7090075Sobrienvoid	moncontrol(int);
7190075Sobrienstatic int hertz(void);
7290075Sobrien
7390075Sobrienvoid
7490075Sobrienmonstartup(lowpc, highpc)
7590075Sobrien	u_long lowpc;
76132718Skan	u_long highpc;
7790075Sobrien{
7890075Sobrien	int o;
7990075Sobrien	char *cp;
8090075Sobrien	struct gmonparam *p = &_gmonparam;
8190075Sobrien
8290075Sobrien	/*
8390075Sobrien	 * round lowpc and highpc to multiples of the density we're using
8490075Sobrien	 * so the rest of the scaling (here and in gprof) stays in ints.
8590075Sobrien	 */
8690075Sobrien	p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
8790075Sobrien	p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
8890075Sobrien	p->textsize = p->highpc - p->lowpc;
8990075Sobrien	p->kcountsize = p->textsize / HISTFRACTION;
9090075Sobrien	p->hashfraction = HASHFRACTION;
9190075Sobrien	p->fromssize = p->textsize / HASHFRACTION;
9290075Sobrien	p->tolimit = p->textsize * ARCDENSITY / 100;
93132718Skan	if (p->tolimit < MINARCS)
9490075Sobrien		p->tolimit = MINARCS;
9590075Sobrien	else if (p->tolimit > MAXARCS)
9690075Sobrien		p->tolimit = MAXARCS;
9790075Sobrien	p->tossize = p->tolimit * sizeof(struct tostruct);
9890075Sobrien
9990075Sobrien	cp = sbrk(p->kcountsize + p->fromssize + p->tossize);
10090075Sobrien	if (cp == (char *)-1) {
101132718Skan		ERR("monstartup: out of memory\n");
10290075Sobrien		return;
103117395Skan	}
10490075Sobrien#ifdef notdef
10590075Sobrien	bzero(cp, p->kcountsize + p->fromssize + p->tossize);
106169689Skan#endif
10790075Sobrien	p->tos = (struct tostruct *)cp;
10890075Sobrien	cp += p->tossize;
10990075Sobrien	p->kcount = (u_short *)cp;
11090075Sobrien	cp += p->kcountsize;
111169689Skan	p->froms = (u_short *)cp;
11290075Sobrien
113169689Skan	minbrk = sbrk(0);
11490075Sobrien	p->tos[0].link = 0;
11590075Sobrien
116169689Skan	o = p->highpc - p->lowpc;
117169689Skan	if (p->kcountsize < o) {
11890075Sobrien#ifndef hp300
11990075Sobrien		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
12090075Sobrien#else /* avoid floating point */
12190075Sobrien		int quot = o / p->kcountsize;
12290075Sobrien
12390075Sobrien		if (quot >= 0x10000)
12490075Sobrien			s_scale = 1;
12590075Sobrien		else if (quot >= 0x100)
12690075Sobrien			s_scale = 0x10000 / quot;
127169689Skan		else if (o >= 0x800000)
12890075Sobrien			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
12990075Sobrien		else
13090075Sobrien			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
13190075Sobrien#endif
13290075Sobrien	} else
133132718Skan		s_scale = SCALE_1_TO_1;
13490075Sobrien
13590075Sobrien	moncontrol(1);
13690075Sobrien}
13790075Sobrien
138169689Skanvoid
13990075Sobrien_mcleanup()
14090075Sobrien{
14190075Sobrien	int fd;
14290075Sobrien	int fromindex;
143169689Skan	int endfrom;
14490075Sobrien	u_long frompc;
14590075Sobrien	int toindex;
146132718Skan	struct rawarc rawarc;
14790075Sobrien	struct gmonparam *p = &_gmonparam;
14890075Sobrien	struct gmonhdr gmonhdr, *hdr;
14990075Sobrien	struct clockinfo clockinfo;
150169689Skan	char outname[128];
15190075Sobrien	int mib[2];
15290075Sobrien	size_t size;
15390075Sobrien#ifdef DEBUG
15490075Sobrien	int log, len;
15590075Sobrien	char buf[200];
15690075Sobrien#endif
15790075Sobrien
15890075Sobrien	if (p->state == GMON_PROF_ERROR)
159169689Skan		ERR("_mcleanup: tos overflow\n");
160169689Skan
16190075Sobrien	size = sizeof(clockinfo);
162169689Skan	mib[0] = CTL_KERN;
163169689Skan	mib[1] = KERN_CLOCKRATE;
164169689Skan	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
165169689Skan		/*
166169689Skan		 * Best guess
167169689Skan		 */
168169689Skan		clockinfo.profhz = hertz();
169169689Skan	} else if (clockinfo.profhz == 0) {
170169689Skan		if (clockinfo.hz != 0)
171169689Skan			clockinfo.profhz = clockinfo.hz;
172169689Skan		else
173169689Skan			clockinfo.profhz = hertz();
174169689Skan	}
175169689Skan
176169689Skan	moncontrol(0);
177169689Skan	snprintf(outname,sizeof(outname),"%s.gmon",__progname);
178169689Skan	fd = _open(outname, O_CREAT|O_TRUNC|O_WRONLY, 0666);
179169689Skan	if (fd < 0) {
180169689Skan		warnx("_mcleanup: %s - %s",outname,strerror(errno));
181169689Skan		return;
182169689Skan	}
183169689Skan#ifdef DEBUG
184169689Skan	log = _open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
185169689Skan	if (log < 0) {
186169689Skan		perror("_mcleanup: gmon.log");
187169689Skan		return;
188169689Skan	}
189169689Skan	len = sprintf(buf, "[mcleanup1] kcount 0x%x ssiz %d\n",
190169689Skan	    p->kcount, p->kcountsize);
191169689Skan	_write(log, buf, len);
192169689Skan#endif
193169689Skan	hdr = (struct gmonhdr *)&gmonhdr;
194169689Skan	hdr->lpc = p->lowpc;
195169689Skan	hdr->hpc = p->highpc;
196169689Skan	hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
197169689Skan	hdr->version = GMONVERSION;
198169689Skan	hdr->profrate = clockinfo.profhz;
199169689Skan	_write(fd, (char *)hdr, sizeof *hdr);
200169689Skan	_write(fd, p->kcount, p->kcountsize);
201169689Skan	endfrom = p->fromssize / sizeof(*p->froms);
202169689Skan	for (fromindex = 0; fromindex < endfrom; fromindex++) {
203169689Skan		if (p->froms[fromindex] == 0)
204169689Skan			continue;
205169689Skan
206169689Skan		frompc = p->lowpc;
207169689Skan		frompc += fromindex * p->hashfraction * sizeof(*p->froms);
208169689Skan		for (toindex = p->froms[fromindex]; toindex != 0;
209169689Skan		     toindex = p->tos[toindex].link) {
210169689Skan#ifdef DEBUG
211169689Skan			len = sprintf(buf,
212169689Skan			"[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
213169689Skan				frompc, p->tos[toindex].selfpc,
214169689Skan				p->tos[toindex].count);
215169689Skan			_write(log, buf, len);
216169689Skan#endif
217169689Skan			rawarc.raw_frompc = frompc;
218169689Skan			rawarc.raw_selfpc = p->tos[toindex].selfpc;
219169689Skan			rawarc.raw_count = p->tos[toindex].count;
220169689Skan			_write(fd, &rawarc, sizeof rawarc);
221169689Skan		}
222169689Skan	}
223169689Skan	_close(fd);
224169689Skan}
225169689Skan
226169689Skan/*
227169689Skan * Control profiling
228169689Skan *	profiling is what mcount checks to see if
229169689Skan *	all the data structures are ready.
230169689Skan */
231169689Skanvoid
232169689Skanmoncontrol(mode)
233169689Skan	int mode;
234169689Skan{
235169689Skan	struct gmonparam *p = &_gmonparam;
236169689Skan
237169689Skan	if (mode) {
238169689Skan		/* start */
239169689Skan		profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale);
240169689Skan		p->state = GMON_PROF_ON;
241169689Skan	} else {
242169689Skan		/* stop */
243169689Skan		profil((char *)0, 0, 0, 0);
244169689Skan		p->state = GMON_PROF_OFF;
245169689Skan	}
246169689Skan}
247169689Skan
248169689Skan/*
249169689Skan * discover the tick frequency of the machine
250169689Skan * if something goes wrong, we return 0, an impossible hertz.
251169689Skan */
252169689Skanstatic int
253169689Skanhertz()
254169689Skan{
255169689Skan	struct itimerval tim;
256169689Skan
257169689Skan	tim.it_interval.tv_sec = 0;
258169689Skan	tim.it_interval.tv_usec = 1;
259169689Skan	tim.it_value.tv_sec = 0;
260169689Skan	tim.it_value.tv_usec = 0;
261169689Skan	setitimer(ITIMER_REAL, &tim, 0);
262169689Skan	setitimer(ITIMER_REAL, 0, &tim);
263169689Skan	if (tim.it_interval.tv_usec < 2)
264169689Skan		return(0);
265169689Skan	return (1000000 / tim.it_interval.tv_usec);
266169689Skan}
267169689Skan