Home | History | Annotate | Line # | Download | only in gmon
gmon.c revision 1.29.28.1
      1  1.29.28.1       jym /*	$NetBSD: gmon.c,v 1.29.28.1 2009/05/13 19:18:23 jym Exp $	*/
      2       1.22   thorpej 
      3       1.22   thorpej /*
      4       1.22   thorpej  * Copyright (c) 2003, 2004 Wasabi Systems, Inc.
      5       1.22   thorpej  * All rights reserved.
      6       1.22   thorpej  *
      7       1.22   thorpej  * Written by Nathan J. Williams for Wasabi Systems, Inc.
      8       1.22   thorpej  *
      9       1.22   thorpej  * Redistribution and use in source and binary forms, with or without
     10       1.22   thorpej  * modification, are permitted provided that the following conditions
     11       1.22   thorpej  * are met:
     12       1.22   thorpej  * 1. Redistributions of source code must retain the above copyright
     13       1.22   thorpej  *    notice, this list of conditions and the following disclaimer.
     14       1.22   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     15       1.22   thorpej  *    notice, this list of conditions and the following disclaimer in the
     16       1.22   thorpej  *    documentation and/or other materials provided with the distribution.
     17       1.22   thorpej  * 3. All advertising materials mentioning features or use of this software
     18       1.22   thorpej  *    must display the following acknowledgement:
     19       1.22   thorpej  *	This product includes software developed for the NetBSD Project by
     20       1.22   thorpej  *	Wasabi Systems, Inc.
     21       1.22   thorpej  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     22       1.22   thorpej  *    or promote products derived from this software without specific prior
     23       1.22   thorpej  *    written permission.
     24       1.22   thorpej  *
     25       1.22   thorpej  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     26       1.22   thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27       1.22   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28       1.22   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     29       1.22   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30       1.22   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31       1.22   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32       1.22   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33       1.22   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34       1.22   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35       1.22   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     36       1.22   thorpej  */
     37        1.3       cgd 
     38        1.1       cgd /*-
     39        1.1       cgd  * Copyright (c) 1983, 1992, 1993
     40        1.1       cgd  *	The Regents of the University of California.  All rights reserved.
     41        1.1       cgd  *
     42        1.1       cgd  * Redistribution and use in source and binary forms, with or without
     43        1.1       cgd  * modification, are permitted provided that the following conditions
     44        1.1       cgd  * are met:
     45        1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     46        1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     47        1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     48        1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     49        1.1       cgd  *    documentation and/or other materials provided with the distribution.
     50       1.21       agc  * 3. Neither the name of the University nor the names of its contributors
     51        1.1       cgd  *    may be used to endorse or promote products derived from this software
     52        1.1       cgd  *    without specific prior written permission.
     53        1.1       cgd  *
     54        1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     55        1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     56        1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     57        1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     58        1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     59        1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     60        1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     61        1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     62        1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     63        1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     64        1.1       cgd  * SUCH DAMAGE.
     65        1.1       cgd  */
     66        1.1       cgd 
     67       1.10  christos #include <sys/cdefs.h>
     68        1.1       cgd #if !defined(lint) && defined(LIBC_SCCS)
     69        1.3       cgd #if 0
     70        1.3       cgd static char sccsid[] = "@(#)gmon.c	8.1 (Berkeley) 6/4/93";
     71        1.3       cgd #else
     72  1.29.28.1       jym __RCSID("$NetBSD: gmon.c,v 1.29.28.1 2009/05/13 19:18:23 jym Exp $");
     73        1.3       cgd #endif
     74        1.1       cgd #endif
     75        1.1       cgd 
     76       1.10  christos #include "namespace.h"
     77        1.1       cgd #include <sys/param.h>
     78        1.1       cgd #include <sys/time.h>
     79        1.1       cgd #include <sys/gmon.h>
     80       1.22   thorpej #include <sys/mman.h>
     81        1.1       cgd #include <sys/sysctl.h>
     82        1.1       cgd 
     83        1.1       cgd #include <stdio.h>
     84        1.5       jtc #include <stdlib.h>
     85       1.22   thorpej #include <string.h>
     86        1.1       cgd #include <fcntl.h>
     87        1.5       jtc #include <limits.h>
     88        1.1       cgd #include <unistd.h>
     89       1.10  christos #include <err.h>
     90       1.15    kleink #include "extern.h"
     91       1.22   thorpej #include "reentrant.h"
     92        1.1       cgd 
     93       1.29  christos struct gmonparam _gmonparam = { .state = GMON_PROF_OFF };
     94        1.1       cgd 
     95       1.22   thorpej #ifdef _REENTRANT
     96       1.22   thorpej struct gmonparam *_gmonfree;
     97       1.22   thorpej struct gmonparam *_gmoninuse;
     98       1.22   thorpej mutex_t _gmonlock = MUTEX_INITIALIZER;
     99       1.22   thorpej thread_key_t _gmonkey;
    100       1.22   thorpej struct gmonparam _gmondummy;
    101       1.22   thorpej #endif
    102       1.22   thorpej 
    103       1.14  christos static u_int	s_scale;
    104        1.1       cgd /* see profil(2) where this is describe (incorrectly) */
    105        1.1       cgd #define		SCALE_1_TO_1	0x10000L
    106        1.1       cgd 
    107       1.12    kleink #define ERR(s) write(STDERR_FILENO, s, sizeof(s))
    108        1.1       cgd 
    109        1.1       cgd void	moncontrol __P((int));
    110       1.10  christos void	monstartup __P((u_long, u_long));
    111       1.10  christos void	_mcleanup __P((void));
    112        1.1       cgd static int hertz __P((void));
    113        1.1       cgd 
    114       1.22   thorpej #ifdef _REENTRANT
    115       1.22   thorpej static void _m_gmon_destructor(void *);
    116       1.22   thorpej struct gmonparam *_m_gmon_alloc(void)  __attribute__((__no_instrument_function__));
    117       1.22   thorpej static void _m_gmon_merge(void);
    118       1.22   thorpej static void _m_gmon_merge_two(struct gmonparam *, struct gmonparam *);
    119       1.22   thorpej #endif
    120       1.16  christos 
    121        1.1       cgd void
    122        1.1       cgd monstartup(lowpc, highpc)
    123        1.1       cgd 	u_long lowpc;
    124        1.1       cgd 	u_long highpc;
    125        1.1       cgd {
    126       1.19   thorpej 	u_long o;
    127        1.1       cgd 	char *cp;
    128        1.1       cgd 	struct gmonparam *p = &_gmonparam;
    129        1.1       cgd 
    130        1.1       cgd 	/*
    131        1.1       cgd 	 * round lowpc and highpc to multiples of the density we're using
    132        1.1       cgd 	 * so the rest of the scaling (here and in gprof) stays in ints.
    133        1.1       cgd 	 */
    134       1.27    dogcow 	p->lowpc = rounddown(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
    135       1.27    dogcow 	p->highpc = roundup(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
    136        1.1       cgd 	p->textsize = p->highpc - p->lowpc;
    137        1.1       cgd 	p->kcountsize = p->textsize / HISTFRACTION;
    138        1.1       cgd 	p->hashfraction = HASHFRACTION;
    139        1.6       cgd 	p->fromssize = p->textsize / p->hashfraction;
    140        1.1       cgd 	p->tolimit = p->textsize * ARCDENSITY / 100;
    141        1.1       cgd 	if (p->tolimit < MINARCS)
    142        1.1       cgd 		p->tolimit = MINARCS;
    143        1.1       cgd 	else if (p->tolimit > MAXARCS)
    144        1.1       cgd 		p->tolimit = MAXARCS;
    145        1.1       cgd 	p->tossize = p->tolimit * sizeof(struct tostruct);
    146        1.1       cgd 
    147       1.16  christos 	cp = sbrk((intptr_t)(p->kcountsize + p->fromssize + p->tossize));
    148        1.1       cgd 	if (cp == (char *)-1) {
    149        1.1       cgd 		ERR("monstartup: out of memory\n");
    150        1.1       cgd 		return;
    151        1.1       cgd 	}
    152        1.1       cgd #ifdef notdef
    153       1.13     perry 	memset(cp, 0, p->kcountsize + p->fromssize + p->tossize);
    154        1.1       cgd #endif
    155       1.14  christos 	p->tos = (struct tostruct *)(void *)cp;
    156       1.14  christos 	cp += (size_t)p->tossize;
    157       1.14  christos 	p->kcount = (u_short *)(void *)cp;
    158       1.14  christos 	cp += (size_t)p->kcountsize;
    159       1.14  christos 	p->froms = (u_short *)(void *)cp;
    160        1.1       cgd 
    161       1.16  christos 	__minbrk = sbrk((intptr_t)0);
    162        1.1       cgd 	p->tos[0].link = 0;
    163        1.1       cgd 
    164        1.1       cgd 	o = p->highpc - p->lowpc;
    165        1.1       cgd 	if (p->kcountsize < o) {
    166        1.2       cgd #ifndef notdef
    167        1.1       cgd 		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
    168        1.1       cgd #else /* avoid floating point */
    169       1.19   thorpej 		u_long quot = o / p->kcountsize;
    170        1.1       cgd 
    171        1.1       cgd 		if (quot >= 0x10000)
    172        1.1       cgd 			s_scale = 1;
    173        1.1       cgd 		else if (quot >= 0x100)
    174        1.1       cgd 			s_scale = 0x10000 / quot;
    175        1.1       cgd 		else if (o >= 0x800000)
    176        1.1       cgd 			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
    177        1.1       cgd 		else
    178        1.1       cgd 			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
    179        1.1       cgd #endif
    180        1.1       cgd 	} else
    181        1.1       cgd 		s_scale = SCALE_1_TO_1;
    182        1.1       cgd 
    183       1.22   thorpej #ifdef _REENTRANT
    184       1.22   thorpej 	_gmondummy.state = GMON_PROF_BUSY;
    185       1.22   thorpej 	thr_keycreate(&_gmonkey, _m_gmon_destructor);
    186       1.22   thorpej #endif
    187        1.1       cgd 	moncontrol(1);
    188        1.1       cgd }
    189        1.1       cgd 
    190       1.22   thorpej #ifdef _REENTRANT
    191       1.22   thorpej static void
    192       1.22   thorpej _m_gmon_destructor(void *arg)
    193       1.22   thorpej {
    194       1.22   thorpej 	struct gmonparam *p = arg, *q, **prev;
    195       1.22   thorpej 
    196       1.22   thorpej 	if (p == &_gmondummy)
    197       1.22   thorpej 		return;
    198       1.22   thorpej 
    199       1.22   thorpej 	thr_setspecific(_gmonkey, &_gmondummy);
    200       1.22   thorpej 
    201       1.22   thorpej 	mutex_lock(&_gmonlock);
    202       1.22   thorpej 	/* XXX eww, linear list traversal. */
    203       1.22   thorpej 	for (q = _gmoninuse, prev = &_gmoninuse;
    204       1.22   thorpej 	     q != NULL;
    205       1.26       mrg 	     prev = (struct gmonparam **)(void *)&q->kcount,	/* XXX */
    206       1.22   thorpej 		 q = (struct gmonparam *)(void *)q->kcount) {
    207       1.22   thorpej 		if (q == p)
    208       1.22   thorpej 			*prev = (struct gmonparam *)(void *)q->kcount;
    209       1.22   thorpej 	}
    210       1.22   thorpej 	p->kcount = (u_short *)(void *)_gmonfree;
    211       1.22   thorpej 	_gmonfree = p;
    212       1.22   thorpej 	mutex_unlock(&_gmonlock);
    213       1.22   thorpej 
    214       1.22   thorpej 	thr_setspecific(_gmonkey, NULL);
    215       1.22   thorpej }
    216       1.22   thorpej 
    217       1.22   thorpej struct gmonparam *
    218       1.22   thorpej _m_gmon_alloc(void)
    219       1.22   thorpej {
    220       1.22   thorpej 	struct gmonparam *p;
    221       1.22   thorpej 	char *cp;
    222       1.22   thorpej 
    223       1.22   thorpej 	mutex_lock(&_gmonlock);
    224       1.22   thorpej 	if (_gmonfree != NULL) {
    225       1.22   thorpej 		p = _gmonfree;
    226       1.22   thorpej 		_gmonfree = (struct gmonparam *)(void *)p->kcount;
    227       1.22   thorpej 		p->kcount = (u_short *)(void *)_gmoninuse;
    228       1.22   thorpej 		_gmoninuse = p;
    229       1.22   thorpej 	} else {
    230       1.22   thorpej 		mutex_unlock(&_gmonlock);
    231       1.22   thorpej 		cp = mmap(NULL,
    232       1.22   thorpej 		    (size_t)(sizeof (struct gmonparam) +
    233       1.22   thorpej 			_gmonparam.fromssize + _gmonparam.tossize),
    234       1.22   thorpej 		    PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0LL);
    235       1.22   thorpej 		p = (void *)cp;
    236       1.22   thorpej 		*p = _gmonparam;
    237       1.22   thorpej 		p->kcount = NULL;
    238       1.22   thorpej 		cp += sizeof (struct gmonparam);
    239       1.22   thorpej 		memset(cp, 0, (size_t)(p->fromssize + p->tossize));
    240       1.22   thorpej 		p->froms = (u_short *)(void *)cp;
    241       1.22   thorpej 		p->tos = (struct tostruct *)(void *)(cp + p->fromssize);
    242       1.22   thorpej 		mutex_lock(&_gmonlock);
    243       1.22   thorpej 		p->kcount = (u_short *)(void *)_gmoninuse;
    244       1.22   thorpej 		_gmoninuse = p;
    245       1.22   thorpej 	}
    246       1.22   thorpej 	mutex_unlock(&_gmonlock);
    247       1.22   thorpej 	thr_setspecific(_gmonkey, p);
    248       1.22   thorpej 
    249       1.22   thorpej 	return p;
    250       1.22   thorpej }
    251       1.22   thorpej 
    252       1.22   thorpej static void
    253       1.22   thorpej _m_gmon_merge_two(struct gmonparam *p, struct gmonparam *q)
    254       1.22   thorpej {
    255       1.22   thorpej 	u_long fromindex;
    256       1.22   thorpej 	u_short *frompcindex, qtoindex, toindex;
    257       1.22   thorpej 	u_long selfpc;
    258  1.29.28.1       jym 	u_long endfrom;
    259       1.22   thorpej 	long count;
    260       1.22   thorpej 	struct tostruct *top;
    261       1.22   thorpej 
    262  1.29.28.1       jym 	endfrom = (q->fromssize / sizeof(*q->froms));
    263       1.22   thorpej 	for (fromindex = 0; fromindex < endfrom; fromindex++) {
    264       1.22   thorpej 		if (q->froms[fromindex] == 0)
    265       1.22   thorpej 			continue;
    266       1.22   thorpej 		for (qtoindex = q->froms[fromindex]; qtoindex != 0;
    267       1.22   thorpej 		     qtoindex = q->tos[qtoindex].link) {
    268       1.22   thorpej 			selfpc = q->tos[qtoindex].selfpc;
    269       1.22   thorpej 			count = q->tos[qtoindex].count;
    270       1.22   thorpej 			/* cribbed from mcount */
    271       1.22   thorpej 			frompcindex = &p->froms[fromindex];
    272       1.22   thorpej 			toindex = *frompcindex;
    273       1.22   thorpej 			if (toindex == 0) {
    274       1.22   thorpej 				/*
    275       1.22   thorpej 				 *	first time traversing this arc
    276       1.22   thorpej 				 */
    277       1.22   thorpej 				toindex = ++p->tos[0].link;
    278       1.22   thorpej 				if (toindex >= p->tolimit)
    279       1.22   thorpej 					/* halt further profiling */
    280       1.22   thorpej 					goto overflow;
    281       1.22   thorpej 
    282       1.22   thorpej 				*frompcindex = (u_short)toindex;
    283       1.22   thorpej 				top = &p->tos[(size_t)toindex];
    284       1.22   thorpej 				top->selfpc = selfpc;
    285       1.22   thorpej 				top->count = count;
    286       1.22   thorpej 				top->link = 0;
    287       1.22   thorpej 				goto done;
    288       1.22   thorpej 			}
    289       1.22   thorpej 			top = &p->tos[(size_t)toindex];
    290       1.22   thorpej 			if (top->selfpc == selfpc) {
    291       1.22   thorpej 				/*
    292       1.22   thorpej 				 * arc at front of chain; usual case.
    293       1.22   thorpej 				 */
    294       1.22   thorpej 				top->count+= count;
    295       1.22   thorpej 				goto done;
    296       1.22   thorpej 			}
    297       1.22   thorpej 			/*
    298       1.22   thorpej 			 * have to go looking down chain for it.
    299       1.22   thorpej 			 * top points to what we are looking at,
    300       1.22   thorpej 			 * we know it is not at the head of the chain.
    301       1.22   thorpej 			 */
    302       1.22   thorpej 			for (; /* goto done */; ) {
    303       1.22   thorpej 				if (top->link == 0) {
    304       1.22   thorpej 					/*
    305       1.22   thorpej 					 * top is end of the chain and
    306       1.22   thorpej 					 * none of the chain had
    307       1.22   thorpej 					 * top->selfpc == selfpc.  so
    308       1.22   thorpej 					 * we allocate a new tostruct
    309       1.22   thorpej 					 * and link it to the head of
    310       1.22   thorpej 					 * the chain.
    311       1.22   thorpej 					 */
    312       1.22   thorpej 					toindex = ++p->tos[0].link;
    313       1.22   thorpej 					if (toindex >= p->tolimit)
    314       1.22   thorpej 						goto overflow;
    315       1.22   thorpej 
    316       1.22   thorpej 					top = &p->tos[(size_t)toindex];
    317       1.22   thorpej 					top->selfpc = selfpc;
    318       1.22   thorpej 					top->count = count;
    319       1.22   thorpej 					top->link = *frompcindex;
    320       1.22   thorpej 					*frompcindex = (u_short)toindex;
    321       1.22   thorpej 					goto done;
    322       1.22   thorpej 				}
    323       1.22   thorpej 				/*
    324       1.22   thorpej 				 * otherwise, check the next arc on the chain.
    325       1.22   thorpej 				 */
    326       1.22   thorpej 				top = &p->tos[top->link];
    327       1.22   thorpej 				if (top->selfpc == selfpc) {
    328       1.22   thorpej 					/*
    329       1.22   thorpej 					 * there it is.
    330       1.22   thorpej 					 * add to its count.
    331       1.22   thorpej 					 */
    332       1.22   thorpej 					top->count += count;
    333       1.22   thorpej 					goto done;
    334       1.22   thorpej 				}
    335       1.22   thorpej 
    336       1.22   thorpej 			}
    337       1.22   thorpej 
    338       1.22   thorpej 		done: ;
    339       1.22   thorpej 		}
    340       1.22   thorpej 
    341       1.22   thorpej 	}
    342       1.22   thorpej  overflow: ;
    343       1.22   thorpej 
    344       1.22   thorpej }
    345       1.22   thorpej 
    346       1.22   thorpej static void
    347       1.22   thorpej _m_gmon_merge(void)
    348       1.22   thorpej {
    349       1.22   thorpej 	struct gmonparam *q;
    350       1.22   thorpej 
    351       1.22   thorpej 	mutex_lock(&_gmonlock);
    352       1.22   thorpej 
    353       1.22   thorpej 	for (q = _gmonfree; q != NULL; q = (struct gmonparam *)(void *)q->kcount)
    354       1.22   thorpej 		_m_gmon_merge_two(&_gmonparam, q);
    355       1.22   thorpej 
    356       1.22   thorpej 	for (q = _gmoninuse; q != NULL; q = (struct gmonparam *)(void *)q->kcount) {
    357       1.22   thorpej 		q->state = GMON_PROF_OFF;
    358       1.22   thorpej 		_m_gmon_merge_two(&_gmonparam, q);
    359       1.22   thorpej 	}
    360       1.22   thorpej 
    361       1.22   thorpej 	mutex_unlock(&_gmonlock);
    362       1.22   thorpej }
    363       1.22   thorpej #endif
    364       1.22   thorpej 
    365        1.1       cgd void
    366        1.1       cgd _mcleanup()
    367        1.1       cgd {
    368        1.1       cgd 	int fd;
    369        1.1       cgd 	int fromindex;
    370        1.1       cgd 	int endfrom;
    371        1.1       cgd 	u_long frompc;
    372        1.1       cgd 	int toindex;
    373        1.1       cgd 	struct rawarc rawarc;
    374        1.1       cgd 	struct gmonparam *p = &_gmonparam;
    375        1.1       cgd 	struct gmonhdr gmonhdr, *hdr;
    376        1.1       cgd 	struct clockinfo clockinfo;
    377        1.1       cgd 	int mib[2];
    378        1.1       cgd 	size_t size;
    379        1.5       jtc 	char *profdir;
    380       1.23  christos 	const char *proffile;
    381        1.5       jtc 	char  buf[PATH_MAX];
    382        1.1       cgd #ifdef DEBUG
    383       1.25  christos 	int logfd, len;
    384        1.9       mrg 	char buf2[200];
    385        1.1       cgd #endif
    386       1.18  christos 
    387       1.18  christos 	/*
    388       1.18  christos 	 * We disallow writing to the profiling file, if we are a
    389       1.18  christos 	 * set{u,g}id program and our effective {u,g}id does not match
    390       1.18  christos 	 * our real one.
    391       1.18  christos 	 */
    392       1.18  christos 	if (issetugid() && (geteuid() != getuid() || getegid() != getgid())) {
    393       1.18  christos 		warnx("mcount: Profiling of set{u,g}id binaries is not"
    394       1.18  christos 		    " allowed");
    395       1.18  christos 		return;
    396       1.18  christos 	}
    397        1.1       cgd 
    398        1.1       cgd 	if (p->state == GMON_PROF_ERROR)
    399        1.1       cgd 		ERR("_mcleanup: tos overflow\n");
    400        1.1       cgd 
    401        1.1       cgd 	size = sizeof(clockinfo);
    402        1.1       cgd 	mib[0] = CTL_KERN;
    403        1.1       cgd 	mib[1] = KERN_CLOCKRATE;
    404        1.1       cgd 	if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
    405        1.1       cgd 		/*
    406        1.1       cgd 		 * Best guess
    407        1.1       cgd 		 */
    408        1.1       cgd 		clockinfo.profhz = hertz();
    409        1.1       cgd 	} else if (clockinfo.profhz == 0) {
    410        1.1       cgd 		if (clockinfo.hz != 0)
    411        1.1       cgd 			clockinfo.profhz = clockinfo.hz;
    412        1.1       cgd 		else
    413        1.1       cgd 			clockinfo.profhz = hertz();
    414        1.1       cgd 	}
    415        1.1       cgd 
    416        1.1       cgd 	moncontrol(0);
    417        1.5       jtc 
    418        1.5       jtc 	if ((profdir = getenv("PROFDIR")) != NULL) {
    419        1.5       jtc 		/* If PROFDIR contains a null value, no profiling
    420        1.5       jtc 		   output is produced */
    421       1.20       dsl 		if (*profdir == '\0')
    422       1.20       dsl 			return;
    423       1.20       dsl 
    424       1.20       dsl 		if (snprintf(buf, sizeof buf, "%s/%d.%s",
    425  1.29.28.1       jym 			    profdir, getpid(), getprogname()) >= (int)(sizeof buf)) {
    426       1.20       dsl 			warnx("_mcleanup: internal buffer overflow, PROFDIR too long");
    427        1.5       jtc 			return;
    428        1.5       jtc 		}
    429        1.5       jtc 
    430        1.5       jtc 		proffile = buf;
    431        1.5       jtc 	} else {
    432        1.5       jtc 		proffile = "gmon.out";
    433        1.5       jtc 	}
    434        1.5       jtc 
    435        1.5       jtc 	fd = open(proffile , O_CREAT|O_TRUNC|O_WRONLY, 0666);
    436        1.1       cgd 	if (fd < 0) {
    437       1.10  christos 		warn("mcount: Cannot open `%s'", proffile);
    438        1.1       cgd 		return;
    439        1.1       cgd 	}
    440        1.1       cgd #ifdef DEBUG
    441       1.25  christos 	logfd = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
    442       1.25  christos 	if (logfd < 0) {
    443       1.10  christos 		warn("mcount: Cannot open `gmon.log'");
    444        1.1       cgd 		return;
    445        1.1       cgd 	}
    446       1.25  christos 	len = snprintf(buf2, sizeof buf2, "[mcleanup1] kcount %p ssiz %lu\n",
    447        1.1       cgd 	    p->kcount, p->kcountsize);
    448       1.25  christos 	(void)write(logfd, buf2, (size_t)len);
    449        1.1       cgd #endif
    450       1.22   thorpej #ifdef _REENTRANT
    451       1.22   thorpej 	_m_gmon_merge();
    452       1.22   thorpej #endif
    453        1.1       cgd 	hdr = (struct gmonhdr *)&gmonhdr;
    454        1.1       cgd 	hdr->lpc = p->lowpc;
    455        1.1       cgd 	hdr->hpc = p->highpc;
    456       1.14  christos 	hdr->ncnt = (int)(p->kcountsize + sizeof(gmonhdr));
    457        1.1       cgd 	hdr->version = GMONVERSION;
    458        1.1       cgd 	hdr->profrate = clockinfo.profhz;
    459       1.14  christos 	(void)write(fd, hdr, sizeof *hdr);
    460       1.14  christos 	(void)write(fd, p->kcount, (size_t)p->kcountsize);
    461       1.14  christos 	endfrom = (int)(p->fromssize / sizeof(*p->froms));
    462        1.1       cgd 	for (fromindex = 0; fromindex < endfrom; fromindex++) {
    463        1.1       cgd 		if (p->froms[fromindex] == 0)
    464        1.1       cgd 			continue;
    465        1.1       cgd 
    466        1.1       cgd 		frompc = p->lowpc;
    467        1.1       cgd 		frompc += fromindex * p->hashfraction * sizeof(*p->froms);
    468        1.1       cgd 		for (toindex = p->froms[fromindex]; toindex != 0;
    469        1.1       cgd 		     toindex = p->tos[toindex].link) {
    470        1.1       cgd #ifdef DEBUG
    471        1.9       mrg 			len = snprintf(buf2, sizeof buf2,
    472       1.25  christos 			"[mcleanup2] frompc 0x%lx selfpc 0x%lx count %lu\n" ,
    473       1.25  christos 				(u_long)frompc, (u_long)p->tos[toindex].selfpc,
    474       1.25  christos 				(u_long)p->tos[toindex].count);
    475       1.25  christos 			(void)write(logfd, buf2, (size_t)len);
    476        1.1       cgd #endif
    477        1.1       cgd 			rawarc.raw_frompc = frompc;
    478        1.1       cgd 			rawarc.raw_selfpc = p->tos[toindex].selfpc;
    479        1.1       cgd 			rawarc.raw_count = p->tos[toindex].count;
    480        1.1       cgd 			write(fd, &rawarc, sizeof rawarc);
    481        1.1       cgd 		}
    482        1.1       cgd 	}
    483        1.1       cgd 	close(fd);
    484        1.1       cgd }
    485        1.1       cgd 
    486        1.1       cgd /*
    487        1.1       cgd  * Control profiling
    488        1.1       cgd  *	profiling is what mcount checks to see if
    489        1.1       cgd  *	all the data structures are ready.
    490        1.1       cgd  */
    491        1.1       cgd void
    492        1.1       cgd moncontrol(mode)
    493        1.1       cgd 	int mode;
    494        1.1       cgd {
    495        1.1       cgd 	struct gmonparam *p = &_gmonparam;
    496        1.1       cgd 
    497        1.1       cgd 	if (mode) {
    498        1.1       cgd 		/* start */
    499       1.14  christos 		profil((char *)(void *)p->kcount, (size_t)p->kcountsize,
    500       1.14  christos 		    p->lowpc, s_scale);
    501        1.1       cgd 		p->state = GMON_PROF_ON;
    502        1.1       cgd 	} else {
    503        1.1       cgd 		/* stop */
    504       1.14  christos 		profil(NULL, 0, (u_long)0, 0);
    505        1.1       cgd 		p->state = GMON_PROF_OFF;
    506        1.1       cgd 	}
    507        1.1       cgd }
    508        1.1       cgd 
    509        1.1       cgd /*
    510        1.1       cgd  * discover the tick frequency of the machine
    511        1.1       cgd  * if something goes wrong, we return 0, an impossible hertz.
    512        1.1       cgd  */
    513        1.1       cgd static int
    514        1.1       cgd hertz()
    515        1.1       cgd {
    516        1.1       cgd 	struct itimerval tim;
    517        1.1       cgd 
    518        1.1       cgd 	tim.it_interval.tv_sec = 0;
    519        1.1       cgd 	tim.it_interval.tv_usec = 1;
    520        1.1       cgd 	tim.it_value.tv_sec = 0;
    521        1.1       cgd 	tim.it_value.tv_usec = 0;
    522        1.1       cgd 	setitimer(ITIMER_REAL, &tim, 0);
    523        1.1       cgd 	setitimer(ITIMER_REAL, 0, &tim);
    524        1.1       cgd 	if (tim.it_interval.tv_usec < 2)
    525        1.1       cgd 		return(0);
    526       1.14  christos 	return (int)(1000000 / tim.it_interval.tv_usec);
    527        1.1       cgd }
    528