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