xref: /minix3/lib/libc/gmon/gmon.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: gmon.c,v 1.35 2014/09/18 13:58:20 christos Exp $	*/
22fe8fb19SBen Gras 
32fe8fb19SBen Gras /*
42fe8fb19SBen Gras  * Copyright (c) 2003, 2004 Wasabi Systems, Inc.
52fe8fb19SBen Gras  * All rights reserved.
62fe8fb19SBen Gras  *
72fe8fb19SBen Gras  * Written by Nathan J. Williams for Wasabi Systems, Inc.
82fe8fb19SBen Gras  *
92fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
102fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
112fe8fb19SBen Gras  * are met:
122fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
132fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
142fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
152fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
162fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
172fe8fb19SBen Gras  * 3. All advertising materials mentioning features or use of this software
182fe8fb19SBen Gras  *    must display the following acknowledgement:
192fe8fb19SBen Gras  *	This product includes software developed for the NetBSD Project by
202fe8fb19SBen Gras  *	Wasabi Systems, Inc.
212fe8fb19SBen Gras  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
222fe8fb19SBen Gras  *    or promote products derived from this software without specific prior
232fe8fb19SBen Gras  *    written permission.
242fe8fb19SBen Gras  *
252fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
262fe8fb19SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
272fe8fb19SBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
282fe8fb19SBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
292fe8fb19SBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
302fe8fb19SBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
312fe8fb19SBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
322fe8fb19SBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
332fe8fb19SBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
342fe8fb19SBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
352fe8fb19SBen Gras  * POSSIBILITY OF SUCH DAMAGE.
362fe8fb19SBen Gras  */
372fe8fb19SBen Gras 
382fe8fb19SBen Gras /*-
392fe8fb19SBen Gras  * Copyright (c) 1983, 1992, 1993
402fe8fb19SBen Gras  *	The Regents of the University of California.  All rights reserved.
412fe8fb19SBen Gras  *
422fe8fb19SBen Gras  * Redistribution and use in source and binary forms, with or without
432fe8fb19SBen Gras  * modification, are permitted provided that the following conditions
442fe8fb19SBen Gras  * are met:
452fe8fb19SBen Gras  * 1. Redistributions of source code must retain the above copyright
462fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer.
472fe8fb19SBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
482fe8fb19SBen Gras  *    notice, this list of conditions and the following disclaimer in the
492fe8fb19SBen Gras  *    documentation and/or other materials provided with the distribution.
502fe8fb19SBen Gras  * 3. Neither the name of the University nor the names of its contributors
512fe8fb19SBen Gras  *    may be used to endorse or promote products derived from this software
522fe8fb19SBen Gras  *    without specific prior written permission.
532fe8fb19SBen Gras  *
542fe8fb19SBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
552fe8fb19SBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
562fe8fb19SBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
572fe8fb19SBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
582fe8fb19SBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
592fe8fb19SBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
602fe8fb19SBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
612fe8fb19SBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
622fe8fb19SBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
632fe8fb19SBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
642fe8fb19SBen Gras  * SUCH DAMAGE.
652fe8fb19SBen Gras  */
662fe8fb19SBen Gras 
672fe8fb19SBen Gras #include <sys/cdefs.h>
682fe8fb19SBen Gras #if !defined(lint) && defined(LIBC_SCCS)
692fe8fb19SBen Gras #if 0
702fe8fb19SBen Gras static char sccsid[] = "@(#)gmon.c	8.1 (Berkeley) 6/4/93";
712fe8fb19SBen Gras #else
72*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: gmon.c,v 1.35 2014/09/18 13:58:20 christos Exp $");
732fe8fb19SBen Gras #endif
742fe8fb19SBen Gras #endif
752fe8fb19SBen Gras 
762fe8fb19SBen Gras #include "namespace.h"
772fe8fb19SBen Gras #include <sys/param.h>
782fe8fb19SBen Gras #include <sys/time.h>
792fe8fb19SBen Gras #include <sys/gmon.h>
802fe8fb19SBen Gras #include <sys/mman.h>
812fe8fb19SBen Gras #include <sys/sysctl.h>
822fe8fb19SBen Gras 
832fe8fb19SBen Gras #include <stdio.h>
842fe8fb19SBen Gras #include <stdlib.h>
852fe8fb19SBen Gras #include <string.h>
862fe8fb19SBen Gras #include <fcntl.h>
872fe8fb19SBen Gras #include <limits.h>
882fe8fb19SBen Gras #include <unistd.h>
892fe8fb19SBen Gras #include <err.h>
902fe8fb19SBen Gras #include "extern.h"
912fe8fb19SBen Gras #include "reentrant.h"
922fe8fb19SBen Gras 
932fe8fb19SBen Gras struct gmonparam _gmonparam = { .state = GMON_PROF_OFF };
942fe8fb19SBen Gras 
952fe8fb19SBen Gras #ifdef _REENTRANT
962fe8fb19SBen Gras struct gmonparam *_gmonfree;
972fe8fb19SBen Gras struct gmonparam *_gmoninuse;
982fe8fb19SBen Gras mutex_t _gmonlock = MUTEX_INITIALIZER;
992fe8fb19SBen Gras thread_key_t _gmonkey;
1002fe8fb19SBen Gras struct gmonparam _gmondummy;
1012fe8fb19SBen Gras #endif
1022fe8fb19SBen Gras 
1032fe8fb19SBen Gras static u_int	s_scale;
1042fe8fb19SBen Gras /* see profil(2) where this is describe (incorrectly) */
1052fe8fb19SBen Gras #define		SCALE_1_TO_1	0x10000L
1062fe8fb19SBen Gras 
1072fe8fb19SBen Gras void	moncontrol(int);
1082fe8fb19SBen Gras void	monstartup(u_long, u_long);
1092fe8fb19SBen Gras void	_mcleanup(void);
1102fe8fb19SBen Gras static int hertz(void);
1112fe8fb19SBen Gras 
1122fe8fb19SBen Gras #ifdef _REENTRANT
1132fe8fb19SBen Gras static void _m_gmon_destructor(void *);
1142fe8fb19SBen Gras struct gmonparam *_m_gmon_alloc(void)
1152fe8fb19SBen Gras     __attribute__((__no_instrument_function__));
1162fe8fb19SBen Gras static void _m_gmon_merge(void);
1172fe8fb19SBen Gras static void _m_gmon_merge_two(struct gmonparam *, struct gmonparam *);
1182fe8fb19SBen Gras #endif
1192fe8fb19SBen Gras 
1202fe8fb19SBen Gras void
monstartup(u_long lowpc,u_long highpc)1212fe8fb19SBen Gras monstartup(u_long lowpc, u_long highpc)
1222fe8fb19SBen Gras {
1232fe8fb19SBen Gras 	u_long o;
1242fe8fb19SBen Gras 	char *cp;
1252fe8fb19SBen Gras 	struct gmonparam *p = &_gmonparam;
1262fe8fb19SBen Gras 
1272fe8fb19SBen Gras 	/*
1282fe8fb19SBen Gras 	 * round lowpc and highpc to multiples of the density we're using
1292fe8fb19SBen Gras 	 * so the rest of the scaling (here and in gprof) stays in ints.
1302fe8fb19SBen Gras 	 */
1312fe8fb19SBen Gras 	p->lowpc = rounddown(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
1322fe8fb19SBen Gras 	p->highpc = roundup(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
1332fe8fb19SBen Gras 	p->textsize = p->highpc - p->lowpc;
1342fe8fb19SBen Gras 	p->kcountsize = p->textsize / HISTFRACTION;
1352fe8fb19SBen Gras 	p->hashfraction = HASHFRACTION;
1362fe8fb19SBen Gras 	p->fromssize = p->textsize / p->hashfraction;
1372fe8fb19SBen Gras 	p->tolimit = p->textsize * ARCDENSITY / 100;
1382fe8fb19SBen Gras 	if (p->tolimit < MINARCS)
1392fe8fb19SBen Gras 		p->tolimit = MINARCS;
1402fe8fb19SBen Gras 	else if (p->tolimit > MAXARCS)
1412fe8fb19SBen Gras 		p->tolimit = MAXARCS;
1422fe8fb19SBen Gras 	p->tossize = p->tolimit * sizeof(struct tostruct);
1432fe8fb19SBen Gras 
1442fe8fb19SBen Gras 	cp = sbrk((intptr_t)(p->kcountsize + p->fromssize + p->tossize));
1452fe8fb19SBen Gras 	if (cp == (char *)-1) {
1462fe8fb19SBen Gras 		warnx("%s: out of memory", __func__);
1472fe8fb19SBen Gras 		return;
1482fe8fb19SBen Gras 	}
1492fe8fb19SBen Gras #ifdef notdef
1502fe8fb19SBen Gras 	(void)memset(cp, 0, p->kcountsize + p->fromssize + p->tossize);
1512fe8fb19SBen Gras #endif
1522fe8fb19SBen Gras 	p->tos = (struct tostruct *)(void *)cp;
1532fe8fb19SBen Gras 	cp += (size_t)p->tossize;
1542fe8fb19SBen Gras 	p->kcount = (u_short *)(void *)cp;
1552fe8fb19SBen Gras 	cp += (size_t)p->kcountsize;
1562fe8fb19SBen Gras 	p->froms = (u_short *)(void *)cp;
1572fe8fb19SBen Gras 
1582fe8fb19SBen Gras 	__minbrk = sbrk((intptr_t)0);
1592fe8fb19SBen Gras 	p->tos[0].link = 0;
1602fe8fb19SBen Gras 
1612fe8fb19SBen Gras 	o = p->highpc - p->lowpc;
1622fe8fb19SBen Gras 	if (p->kcountsize < o) {
1632fe8fb19SBen Gras #ifndef notdef
1642fe8fb19SBen Gras 		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
1652fe8fb19SBen Gras #else /* avoid floating point */
1662fe8fb19SBen Gras 		u_long quot = o / p->kcountsize;
1672fe8fb19SBen Gras 
1682fe8fb19SBen Gras 		if (quot >= 0x10000)
1692fe8fb19SBen Gras 			s_scale = 1;
1702fe8fb19SBen Gras 		else if (quot >= 0x100)
1712fe8fb19SBen Gras 			s_scale = 0x10000 / quot;
1722fe8fb19SBen Gras 		else if (o >= 0x800000)
1732fe8fb19SBen Gras 			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
1742fe8fb19SBen Gras 		else
1752fe8fb19SBen Gras 			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
1762fe8fb19SBen Gras #endif
1772fe8fb19SBen Gras 	} else
1782fe8fb19SBen Gras 		s_scale = SCALE_1_TO_1;
1792fe8fb19SBen Gras 
1802fe8fb19SBen Gras #ifdef _REENTRANT
1812fe8fb19SBen Gras 	_gmondummy.state = GMON_PROF_BUSY;
1822fe8fb19SBen Gras 	thr_keycreate(&_gmonkey, _m_gmon_destructor);
1832fe8fb19SBen Gras #endif
1842fe8fb19SBen Gras 	moncontrol(1);
1852fe8fb19SBen Gras }
1862fe8fb19SBen Gras 
1872fe8fb19SBen Gras #ifdef _REENTRANT
1882fe8fb19SBen Gras static void
_m_gmon_destructor(void * arg)1892fe8fb19SBen Gras _m_gmon_destructor(void *arg)
1902fe8fb19SBen Gras {
1912fe8fb19SBen Gras 	struct gmonparam *p = arg, *q, **prev;
1922fe8fb19SBen Gras 
1932fe8fb19SBen Gras 	if (p == &_gmondummy)
1942fe8fb19SBen Gras 		return;
1952fe8fb19SBen Gras 
1962fe8fb19SBen Gras 	thr_setspecific(_gmonkey, &_gmondummy);
1972fe8fb19SBen Gras 
1982fe8fb19SBen Gras 	mutex_lock(&_gmonlock);
1992fe8fb19SBen Gras 	/* XXX eww, linear list traversal. */
2002fe8fb19SBen Gras 	for (q = _gmoninuse, prev = &_gmoninuse;
2012fe8fb19SBen Gras 	     q != NULL;
2022fe8fb19SBen Gras 	     prev = (struct gmonparam **)(void *)&q->kcount,	/* XXX */
2032fe8fb19SBen Gras 		 q = (struct gmonparam *)(void *)q->kcount) {
2042fe8fb19SBen Gras 		if (q == p)
2052fe8fb19SBen Gras 			*prev = (struct gmonparam *)(void *)q->kcount;
2062fe8fb19SBen Gras 	}
2072fe8fb19SBen Gras 	p->kcount = (u_short *)(void *)_gmonfree;
2082fe8fb19SBen Gras 	_gmonfree = p;
2092fe8fb19SBen Gras 	mutex_unlock(&_gmonlock);
2102fe8fb19SBen Gras 
2112fe8fb19SBen Gras 	thr_setspecific(_gmonkey, NULL);
2122fe8fb19SBen Gras }
2132fe8fb19SBen Gras 
2142fe8fb19SBen Gras struct gmonparam *
_m_gmon_alloc(void)2152fe8fb19SBen Gras _m_gmon_alloc(void)
2162fe8fb19SBen Gras {
2172fe8fb19SBen Gras 	struct gmonparam *p;
2182fe8fb19SBen Gras 	char *cp;
2192fe8fb19SBen Gras 
2202fe8fb19SBen Gras 	mutex_lock(&_gmonlock);
2212fe8fb19SBen Gras 	if (_gmonfree != NULL) {
2222fe8fb19SBen Gras 		p = _gmonfree;
2232fe8fb19SBen Gras 		_gmonfree = (struct gmonparam *)(void *)p->kcount;
2242fe8fb19SBen Gras 		p->kcount = (u_short *)(void *)_gmoninuse;
2252fe8fb19SBen Gras 		_gmoninuse = p;
2262fe8fb19SBen Gras 	} else {
2272fe8fb19SBen Gras 		mutex_unlock(&_gmonlock);
2282fe8fb19SBen Gras 		cp = mmap(NULL,
2292fe8fb19SBen Gras 		    (size_t)(sizeof (struct gmonparam) +
2302fe8fb19SBen Gras 			_gmonparam.fromssize + _gmonparam.tossize),
231f14fb602SLionel Sambuc 		    PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, (off_t)0);
2322fe8fb19SBen Gras 		p = (void *)cp;
2332fe8fb19SBen Gras 		*p = _gmonparam;
2342fe8fb19SBen Gras 		p->kcount = NULL;
2352fe8fb19SBen Gras 		cp += sizeof (struct gmonparam);
2362fe8fb19SBen Gras 		memset(cp, 0, (size_t)(p->fromssize + p->tossize));
2372fe8fb19SBen Gras 		p->froms = (u_short *)(void *)cp;
2382fe8fb19SBen Gras 		p->tos = (struct tostruct *)(void *)(cp + p->fromssize);
2392fe8fb19SBen Gras 		mutex_lock(&_gmonlock);
2402fe8fb19SBen Gras 		p->kcount = (u_short *)(void *)_gmoninuse;
2412fe8fb19SBen Gras 		_gmoninuse = p;
2422fe8fb19SBen Gras 	}
2432fe8fb19SBen Gras 	mutex_unlock(&_gmonlock);
2442fe8fb19SBen Gras 	thr_setspecific(_gmonkey, p);
2452fe8fb19SBen Gras 
2462fe8fb19SBen Gras 	return p;
2472fe8fb19SBen Gras }
2482fe8fb19SBen Gras 
2492fe8fb19SBen Gras static void
_m_gmon_merge_two(struct gmonparam * p,struct gmonparam * q)2502fe8fb19SBen Gras _m_gmon_merge_two(struct gmonparam *p, struct gmonparam *q)
2512fe8fb19SBen Gras {
2522fe8fb19SBen Gras 	u_long fromindex;
2532fe8fb19SBen Gras 	u_short *frompcindex, qtoindex, toindex;
2542fe8fb19SBen Gras 	u_long selfpc;
2552fe8fb19SBen Gras 	u_long endfrom;
2562fe8fb19SBen Gras 	long count;
2572fe8fb19SBen Gras 	struct tostruct *top;
2582fe8fb19SBen Gras 
2592fe8fb19SBen Gras 	endfrom = (q->fromssize / sizeof(*q->froms));
2602fe8fb19SBen Gras 	for (fromindex = 0; fromindex < endfrom; fromindex++) {
2612fe8fb19SBen Gras 		if (q->froms[fromindex] == 0)
2622fe8fb19SBen Gras 			continue;
2632fe8fb19SBen Gras 		for (qtoindex = q->froms[fromindex]; qtoindex != 0;
2642fe8fb19SBen Gras 		     qtoindex = q->tos[qtoindex].link) {
2652fe8fb19SBen Gras 			selfpc = q->tos[qtoindex].selfpc;
2662fe8fb19SBen Gras 			count = q->tos[qtoindex].count;
2672fe8fb19SBen Gras 			/* cribbed from mcount */
2682fe8fb19SBen Gras 			frompcindex = &p->froms[fromindex];
2692fe8fb19SBen Gras 			toindex = *frompcindex;
2702fe8fb19SBen Gras 			if (toindex == 0) {
2712fe8fb19SBen Gras 				/*
2722fe8fb19SBen Gras 				 *	first time traversing this arc
2732fe8fb19SBen Gras 				 */
2742fe8fb19SBen Gras 				toindex = ++p->tos[0].link;
2752fe8fb19SBen Gras 				if (toindex >= p->tolimit)
2762fe8fb19SBen Gras 					/* halt further profiling */
2772fe8fb19SBen Gras 					goto overflow;
2782fe8fb19SBen Gras 
2792fe8fb19SBen Gras 				*frompcindex = (u_short)toindex;
2802fe8fb19SBen Gras 				top = &p->tos[(size_t)toindex];
2812fe8fb19SBen Gras 				top->selfpc = selfpc;
2822fe8fb19SBen Gras 				top->count = count;
2832fe8fb19SBen Gras 				top->link = 0;
2842fe8fb19SBen Gras 				goto done;
2852fe8fb19SBen Gras 			}
2862fe8fb19SBen Gras 			top = &p->tos[(size_t)toindex];
2872fe8fb19SBen Gras 			if (top->selfpc == selfpc) {
2882fe8fb19SBen Gras 				/*
2892fe8fb19SBen Gras 				 * arc at front of chain; usual case.
2902fe8fb19SBen Gras 				 */
2912fe8fb19SBen Gras 				top->count+= count;
2922fe8fb19SBen Gras 				goto done;
2932fe8fb19SBen Gras 			}
2942fe8fb19SBen Gras 			/*
2952fe8fb19SBen Gras 			 * have to go looking down chain for it.
2962fe8fb19SBen Gras 			 * top points to what we are looking at,
2972fe8fb19SBen Gras 			 * we know it is not at the head of the chain.
2982fe8fb19SBen Gras 			 */
2992fe8fb19SBen Gras 			for (; /* goto done */; ) {
3002fe8fb19SBen Gras 				if (top->link == 0) {
3012fe8fb19SBen Gras 					/*
3022fe8fb19SBen Gras 					 * top is end of the chain and
3032fe8fb19SBen Gras 					 * none of the chain had
3042fe8fb19SBen Gras 					 * top->selfpc == selfpc.  so
3052fe8fb19SBen Gras 					 * we allocate a new tostruct
3062fe8fb19SBen Gras 					 * and link it to the head of
3072fe8fb19SBen Gras 					 * the chain.
3082fe8fb19SBen Gras 					 */
3092fe8fb19SBen Gras 					toindex = ++p->tos[0].link;
3102fe8fb19SBen Gras 					if (toindex >= p->tolimit)
3112fe8fb19SBen Gras 						goto overflow;
3122fe8fb19SBen Gras 
3132fe8fb19SBen Gras 					top = &p->tos[(size_t)toindex];
3142fe8fb19SBen Gras 					top->selfpc = selfpc;
3152fe8fb19SBen Gras 					top->count = count;
3162fe8fb19SBen Gras 					top->link = *frompcindex;
3172fe8fb19SBen Gras 					*frompcindex = (u_short)toindex;
3182fe8fb19SBen Gras 					goto done;
3192fe8fb19SBen Gras 				}
3202fe8fb19SBen Gras 				/*
3212fe8fb19SBen Gras 				 * otherwise, check the next arc on the chain.
3222fe8fb19SBen Gras 				 */
3232fe8fb19SBen Gras 				top = &p->tos[top->link];
3242fe8fb19SBen Gras 				if (top->selfpc == selfpc) {
3252fe8fb19SBen Gras 					/*
3262fe8fb19SBen Gras 					 * there it is.
3272fe8fb19SBen Gras 					 * add to its count.
3282fe8fb19SBen Gras 					 */
3292fe8fb19SBen Gras 					top->count += count;
3302fe8fb19SBen Gras 					goto done;
3312fe8fb19SBen Gras 				}
3322fe8fb19SBen Gras 
3332fe8fb19SBen Gras 			}
3342fe8fb19SBen Gras 
3352fe8fb19SBen Gras 		done: ;
3362fe8fb19SBen Gras 		}
3372fe8fb19SBen Gras 
3382fe8fb19SBen Gras 	}
3392fe8fb19SBen Gras  overflow: ;
3402fe8fb19SBen Gras 
3412fe8fb19SBen Gras }
3422fe8fb19SBen Gras 
3432fe8fb19SBen Gras static void
_m_gmon_merge(void)3442fe8fb19SBen Gras _m_gmon_merge(void)
3452fe8fb19SBen Gras {
3462fe8fb19SBen Gras 	struct gmonparam *q;
3472fe8fb19SBen Gras 
3482fe8fb19SBen Gras 	mutex_lock(&_gmonlock);
3492fe8fb19SBen Gras 
3502fe8fb19SBen Gras 	for (q = _gmonfree; q != NULL;
3512fe8fb19SBen Gras 	    q = (struct gmonparam *)(void *)q->kcount)
3522fe8fb19SBen Gras 		_m_gmon_merge_two(&_gmonparam, q);
3532fe8fb19SBen Gras 
3542fe8fb19SBen Gras 	for (q = _gmoninuse; q != NULL;
3552fe8fb19SBen Gras 	    q = (struct gmonparam *)(void *)q->kcount) {
3562fe8fb19SBen Gras 		q->state = GMON_PROF_OFF;
3572fe8fb19SBen Gras 		_m_gmon_merge_two(&_gmonparam, q);
3582fe8fb19SBen Gras 	}
3592fe8fb19SBen Gras 
3602fe8fb19SBen Gras 	mutex_unlock(&_gmonlock);
3612fe8fb19SBen Gras }
3622fe8fb19SBen Gras #endif
3632fe8fb19SBen Gras 
3642fe8fb19SBen Gras void
_mcleanup(void)3652fe8fb19SBen Gras _mcleanup(void)
3662fe8fb19SBen Gras {
3672fe8fb19SBen Gras 	int fd;
3682fe8fb19SBen Gras 	int fromindex;
3692fe8fb19SBen Gras 	int endfrom;
3702fe8fb19SBen Gras 	u_long frompc;
3712fe8fb19SBen Gras 	int toindex;
3722fe8fb19SBen Gras 	struct rawarc rawarc;
3732fe8fb19SBen Gras 	struct gmonparam *p = &_gmonparam;
3742fe8fb19SBen Gras 	struct gmonhdr gmonhdr, *hdr;
3752fe8fb19SBen Gras 	struct clockinfo clockinfo;
37684d9c625SLionel Sambuc #if !defined(__minix)
3772fe8fb19SBen Gras 	int mib[2];
3782fe8fb19SBen Gras 	size_t size;
37984d9c625SLionel Sambuc #endif /* !defined(__minix) */
3802fe8fb19SBen Gras 	char *profdir;
3812fe8fb19SBen Gras 	const char *proffile;
3822fe8fb19SBen Gras 	char  buf[PATH_MAX];
3832fe8fb19SBen Gras #ifdef DEBUG
3842fe8fb19SBen Gras 	int logfd, len;
3852fe8fb19SBen Gras 	char buf2[200];
3862fe8fb19SBen Gras #endif
3872fe8fb19SBen Gras 
3882fe8fb19SBen Gras 	/*
3892fe8fb19SBen Gras 	 * We disallow writing to the profiling file, if we are a
3902fe8fb19SBen Gras 	 * set{u,g}id program and our effective {u,g}id does not match
3912fe8fb19SBen Gras 	 * our real one.
3922fe8fb19SBen Gras 	 */
3932fe8fb19SBen Gras 	if (issetugid() && (geteuid() != getuid() || getegid() != getgid())) {
3942fe8fb19SBen Gras 		warnx("%s: Profiling of set{u,g}id binaries is not"
3952fe8fb19SBen Gras 		    " allowed", __func__);
3962fe8fb19SBen Gras 		return;
3972fe8fb19SBen Gras 	}
3982fe8fb19SBen Gras 
3992fe8fb19SBen Gras 	if (p->state == GMON_PROF_ERROR)
4002fe8fb19SBen Gras 		warnx("%s: tos overflow", __func__);
4012fe8fb19SBen Gras 
40284d9c625SLionel Sambuc #if defined(__minix)
4032fe8fb19SBen Gras 	clockinfo.profhz = sysconf(_SC_CLK_TCK);
40484d9c625SLionel Sambuc #else
4052fe8fb19SBen Gras 	size = sizeof(clockinfo);
4062fe8fb19SBen Gras 	mib[0] = CTL_KERN;
4072fe8fb19SBen Gras 	mib[1] = KERN_CLOCKRATE;
4082fe8fb19SBen Gras 	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
4092fe8fb19SBen Gras 		/*
4102fe8fb19SBen Gras 		 * Best guess
4112fe8fb19SBen Gras 		 */
4122fe8fb19SBen Gras 		clockinfo.profhz = hertz();
4132fe8fb19SBen Gras 	} else if (clockinfo.profhz == 0) {
4142fe8fb19SBen Gras 		if (clockinfo.hz != 0)
4152fe8fb19SBen Gras 			clockinfo.profhz = clockinfo.hz;
4162fe8fb19SBen Gras 		else
4172fe8fb19SBen Gras 			clockinfo.profhz = hertz();
4182fe8fb19SBen Gras 	}
41984d9c625SLionel Sambuc #endif /* defined(__minix) */
4202fe8fb19SBen Gras 
4212fe8fb19SBen Gras 	moncontrol(0);
4222fe8fb19SBen Gras 
4232fe8fb19SBen Gras 	if ((profdir = getenv("PROFDIR")) != NULL) {
4242fe8fb19SBen Gras 		/* If PROFDIR contains a null value, no profiling
4252fe8fb19SBen Gras 		   output is produced */
4262fe8fb19SBen Gras 		if (*profdir == '\0')
4272fe8fb19SBen Gras 			return;
4282fe8fb19SBen Gras 
4292fe8fb19SBen Gras 		if (snprintf(buf, sizeof buf, "%s/%d.%s",
4302fe8fb19SBen Gras 		    profdir, getpid(), getprogname()) >= (int)(sizeof buf)) {
4312fe8fb19SBen Gras 			warnx("%s: internal buffer overflow, PROFDIR too long",
4322fe8fb19SBen Gras 			    __func__);
4332fe8fb19SBen Gras 			return;
4342fe8fb19SBen Gras 		}
4352fe8fb19SBen Gras 
4362fe8fb19SBen Gras 		proffile = buf;
4372fe8fb19SBen Gras 	} else {
4382fe8fb19SBen Gras 		proffile = "gmon.out";
4392fe8fb19SBen Gras 	}
4402fe8fb19SBen Gras 
441*0a6a1f1dSLionel Sambuc #define OPEN_FLAGS (O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC)
442*0a6a1f1dSLionel Sambuc 	fd = open(proffile, OPEN_FLAGS, 0666);
4432fe8fb19SBen Gras 	if (fd < 0) {
4442fe8fb19SBen Gras 		warn("%s: Cannot open `%s'", __func__, proffile);
4452fe8fb19SBen Gras 		return;
4462fe8fb19SBen Gras 	}
4472fe8fb19SBen Gras #ifdef DEBUG
448*0a6a1f1dSLionel Sambuc 	logfd = open("gmon.log", OPEN_FLAGS, 0664);
4492fe8fb19SBen Gras 	if (logfd < 0) {
4502fe8fb19SBen Gras 		warn("%s: Cannot open `%s'", __func__, "gmon.log");
4512fe8fb19SBen Gras 		(void)close(fd);
4522fe8fb19SBen Gras 		return;
4532fe8fb19SBen Gras 	}
4542fe8fb19SBen Gras 	len = snprintf(buf2, sizeof buf2, "[mcleanup1] kcount %p ssiz %lu\n",
4552fe8fb19SBen Gras 	    p->kcount, p->kcountsize);
4562fe8fb19SBen Gras 	(void)write(logfd, buf2, (size_t)len);
4572fe8fb19SBen Gras #endif
4582fe8fb19SBen Gras #ifdef _REENTRANT
4592fe8fb19SBen Gras 	_m_gmon_merge();
4602fe8fb19SBen Gras #endif
4612fe8fb19SBen Gras 	hdr = (struct gmonhdr *)&gmonhdr;
4622fe8fb19SBen Gras 	hdr->lpc = p->lowpc;
4632fe8fb19SBen Gras 	hdr->hpc = p->highpc;
4642fe8fb19SBen Gras 	hdr->ncnt = (int)(p->kcountsize + sizeof(gmonhdr));
4652fe8fb19SBen Gras 	hdr->version = GMONVERSION;
4662fe8fb19SBen Gras 	hdr->profrate = clockinfo.profhz;
4672fe8fb19SBen Gras 	(void)write(fd, hdr, sizeof *hdr);
4682fe8fb19SBen Gras 	(void)write(fd, p->kcount, (size_t)p->kcountsize);
4692fe8fb19SBen Gras 	endfrom = (int)(p->fromssize / sizeof(*p->froms));
4702fe8fb19SBen Gras 	for (fromindex = 0; fromindex < endfrom; fromindex++) {
4712fe8fb19SBen Gras 		if (p->froms[fromindex] == 0)
4722fe8fb19SBen Gras 			continue;
4732fe8fb19SBen Gras 
4742fe8fb19SBen Gras 		frompc = p->lowpc;
4752fe8fb19SBen Gras 		frompc += fromindex * p->hashfraction * sizeof(*p->froms);
4762fe8fb19SBen Gras 		for (toindex = p->froms[fromindex]; toindex != 0;
4772fe8fb19SBen Gras 		     toindex = p->tos[toindex].link) {
4782fe8fb19SBen Gras #ifdef DEBUG
4792fe8fb19SBen Gras 			len = snprintf(buf2, sizeof buf2,
4802fe8fb19SBen Gras 			"[mcleanup2] frompc 0x%lx selfpc 0x%lx count %lu\n" ,
4812fe8fb19SBen Gras 				(u_long)frompc, (u_long)p->tos[toindex].selfpc,
4822fe8fb19SBen Gras 				(u_long)p->tos[toindex].count);
4832fe8fb19SBen Gras 			(void)write(logfd, buf2, (size_t)len);
4842fe8fb19SBen Gras #endif
4852fe8fb19SBen Gras 			rawarc.raw_frompc = frompc;
4862fe8fb19SBen Gras 			rawarc.raw_selfpc = p->tos[toindex].selfpc;
4872fe8fb19SBen Gras 			rawarc.raw_count = p->tos[toindex].count;
4882fe8fb19SBen Gras 			(void)write(fd, &rawarc, sizeof rawarc);
4892fe8fb19SBen Gras 		}
4902fe8fb19SBen Gras 	}
4912fe8fb19SBen Gras 	(void)close(fd);
4922fe8fb19SBen Gras #ifdef DEBUG
4932fe8fb19SBen Gras 	(void)close(logfd);
4942fe8fb19SBen Gras #endif
4952fe8fb19SBen Gras }
4962fe8fb19SBen Gras 
4972fe8fb19SBen Gras /*
4982fe8fb19SBen Gras  * Control profiling
4992fe8fb19SBen Gras  *	profiling is what mcount checks to see if
5002fe8fb19SBen Gras  *	all the data structures are ready.
5012fe8fb19SBen Gras  */
5022fe8fb19SBen Gras void
moncontrol(int mode)5032fe8fb19SBen Gras moncontrol(int mode)
5042fe8fb19SBen Gras {
5052fe8fb19SBen Gras 	struct gmonparam *p = &_gmonparam;
5062fe8fb19SBen Gras 
5072fe8fb19SBen Gras 	if (mode) {
5082fe8fb19SBen Gras 		/* start */
5092fe8fb19SBen Gras 		profil((char *)(void *)p->kcount, (size_t)p->kcountsize,
5102fe8fb19SBen Gras 		    p->lowpc, s_scale);
5112fe8fb19SBen Gras 		p->state = GMON_PROF_ON;
5122fe8fb19SBen Gras 	} else {
5132fe8fb19SBen Gras 		/* stop */
5142fe8fb19SBen Gras 		profil(NULL, 0, (u_long)0, 0);
5152fe8fb19SBen Gras 		p->state = GMON_PROF_OFF;
5162fe8fb19SBen Gras 	}
5172fe8fb19SBen Gras }
5182fe8fb19SBen Gras 
51984d9c625SLionel Sambuc #if !defined(__minix)
5202fe8fb19SBen Gras /*
5212fe8fb19SBen Gras  * discover the tick frequency of the machine
5222fe8fb19SBen Gras  * if something goes wrong, we return 0, an impossible hertz.
5232fe8fb19SBen Gras  */
5242fe8fb19SBen Gras static int
hertz(void)5252fe8fb19SBen Gras hertz(void)
5262fe8fb19SBen Gras {
5272fe8fb19SBen Gras         struct itimerspec tim;
5282fe8fb19SBen Gras 	timer_t t;
5292fe8fb19SBen Gras 	int rv = 0;
5302fe8fb19SBen Gras 
5312fe8fb19SBen Gras         tim.it_interval.tv_sec = 0;
5322fe8fb19SBen Gras         tim.it_interval.tv_nsec = 1;
5332fe8fb19SBen Gras         tim.it_value.tv_sec = 0;
5342fe8fb19SBen Gras         tim.it_value.tv_nsec = 0;
5352fe8fb19SBen Gras 
5362fe8fb19SBen Gras 	if (timer_create(CLOCK_REALTIME, NULL, &t) == -1)
5372fe8fb19SBen Gras 		return 0;
5382fe8fb19SBen Gras 
5392fe8fb19SBen Gras 	if (timer_settime(t, 0, &tim, NULL) == -1)
5402fe8fb19SBen Gras 		goto out;
5412fe8fb19SBen Gras 
5422fe8fb19SBen Gras 	if (timer_gettime(t, &tim) == -1)
5432fe8fb19SBen Gras 		goto out;
5442fe8fb19SBen Gras 
5452fe8fb19SBen Gras         if (tim.it_interval.tv_nsec < 2)
5462fe8fb19SBen Gras 		goto out;
5472fe8fb19SBen Gras 
5482fe8fb19SBen Gras 	rv = (int)(1000000000LL / tim.it_interval.tv_nsec);
5492fe8fb19SBen Gras out:
5502fe8fb19SBen Gras 	(void)timer_delete(t);
5512fe8fb19SBen Gras 	return rv;
5522fe8fb19SBen Gras }
55384d9c625SLionel Sambuc #endif /* !defined(__minix) */
554