11573Srgrimes/*- 21573Srgrimes * Copyright (c) 1983, 1992, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 4. Neither the name of the University nor the names of its contributors 141573Srgrimes * may be used to endorse or promote products derived from this software 151573Srgrimes * without specific prior written permission. 161573Srgrimes * 171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271573Srgrimes * SUCH DAMAGE. 281573Srgrimes */ 291573Srgrimes 30136582Sobrien#if defined(LIBC_SCCS) && !defined(lint) 311573Srgrimesstatic char sccsid[] = "@(#)gmon.c 8.1 (Berkeley) 6/4/93"; 321573Srgrimes#endif 3390046Sobrien#include <sys/cdefs.h> 3490046Sobrien__FBSDID("$FreeBSD$"); 351573Srgrimes 3671579Sdeischen#include "namespace.h" 371573Srgrimes#include <sys/param.h> 381573Srgrimes#include <sys/time.h> 391573Srgrimes#include <sys/gmon.h> 401573Srgrimes#include <sys/sysctl.h> 411573Srgrimes 4238845Sjb#include <err.h> 4393399Smarkm#include <fcntl.h> 44209620Smarcel#include <inttypes.h> 451573Srgrimes#include <stdio.h> 4693399Smarkm#include <stdlib.h> 4771579Sdeischen#include <string.h> 481573Srgrimes#include <unistd.h> 4971579Sdeischen#include "un-namespace.h" 501573Srgrimes 5193399Smarkm#include "libc_private.h" 5293399Smarkm 53209878Snwhitehorn#if defined(__i386__) || defined(__sparc64__) || defined(__amd64__) || (defined(__powerpc__) && !defined(__powerpc64__)) 54115665Sobrienextern char *minbrk __asm (".minbrk"); 55209878Snwhitehorn#elif defined(__powerpc64__) 56209878Snwhitehornextern char *minbrk __asm ("_minbrk"); 5715634Speter#else 58115665Sobrienextern char *minbrk __asm ("minbrk"); 5915634Speter#endif 601573Srgrimes 611573Srgrimesstruct gmonparam _gmonparam = { GMON_PROF_OFF }; 621573Srgrimes 631573Srgrimesstatic int s_scale; 64209620Smarcel/* See profil(2) where this is described (incorrectly). */ 65209620Smarcel#define SCALE_SHIFT 16 661573Srgrimes 6756698Sjasone#define ERR(s) _write(2, s, sizeof(s)) 681573Srgrimes 6990046Sobrienvoid moncontrol(int); 7090046Sobrienstatic int hertz(void); 711573Srgrimes 721573Srgrimesvoid 731573Srgrimesmonstartup(lowpc, highpc) 741573Srgrimes u_long lowpc; 751573Srgrimes u_long highpc; 761573Srgrimes{ 7790046Sobrien int o; 781573Srgrimes char *cp; 791573Srgrimes struct gmonparam *p = &_gmonparam; 801573Srgrimes 811573Srgrimes /* 821573Srgrimes * round lowpc and highpc to multiples of the density we're using 831573Srgrimes * so the rest of the scaling (here and in gprof) stays in ints. 841573Srgrimes */ 851573Srgrimes p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 861573Srgrimes p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 871573Srgrimes p->textsize = p->highpc - p->lowpc; 881573Srgrimes p->kcountsize = p->textsize / HISTFRACTION; 891573Srgrimes p->hashfraction = HASHFRACTION; 901573Srgrimes p->fromssize = p->textsize / HASHFRACTION; 911573Srgrimes p->tolimit = p->textsize * ARCDENSITY / 100; 921573Srgrimes if (p->tolimit < MINARCS) 931573Srgrimes p->tolimit = MINARCS; 941573Srgrimes else if (p->tolimit > MAXARCS) 951573Srgrimes p->tolimit = MAXARCS; 961573Srgrimes p->tossize = p->tolimit * sizeof(struct tostruct); 971573Srgrimes 981573Srgrimes cp = sbrk(p->kcountsize + p->fromssize + p->tossize); 991573Srgrimes if (cp == (char *)-1) { 1001573Srgrimes ERR("monstartup: out of memory\n"); 1011573Srgrimes return; 1021573Srgrimes } 1031573Srgrimes#ifdef notdef 1041573Srgrimes bzero(cp, p->kcountsize + p->fromssize + p->tossize); 1051573Srgrimes#endif 1061573Srgrimes p->tos = (struct tostruct *)cp; 1071573Srgrimes cp += p->tossize; 1081573Srgrimes p->kcount = (u_short *)cp; 1091573Srgrimes cp += p->kcountsize; 1101573Srgrimes p->froms = (u_short *)cp; 1111573Srgrimes 1121573Srgrimes minbrk = sbrk(0); 1131573Srgrimes p->tos[0].link = 0; 1141573Srgrimes 1151573Srgrimes o = p->highpc - p->lowpc; 116209620Smarcel s_scale = (p->kcountsize < o) ? 117209620Smarcel ((uintmax_t)p->kcountsize << SCALE_SHIFT) / o : (1 << SCALE_SHIFT); 1181573Srgrimes moncontrol(1); 1191573Srgrimes} 1201573Srgrimes 1211573Srgrimesvoid 122200150Sed_mcleanup(void) 1231573Srgrimes{ 1241573Srgrimes int fd; 1251573Srgrimes int fromindex; 1261573Srgrimes int endfrom; 1271573Srgrimes u_long frompc; 1281573Srgrimes int toindex; 1291573Srgrimes struct rawarc rawarc; 1301573Srgrimes struct gmonparam *p = &_gmonparam; 1311573Srgrimes struct gmonhdr gmonhdr, *hdr; 1321573Srgrimes struct clockinfo clockinfo; 13338845Sjb char outname[128]; 1341573Srgrimes int mib[2]; 1351573Srgrimes size_t size; 1361573Srgrimes#ifdef DEBUG 1371573Srgrimes int log, len; 1381573Srgrimes char buf[200]; 1391573Srgrimes#endif 1401573Srgrimes 1411573Srgrimes if (p->state == GMON_PROF_ERROR) 1421573Srgrimes ERR("_mcleanup: tos overflow\n"); 1431573Srgrimes 1441573Srgrimes size = sizeof(clockinfo); 1451573Srgrimes mib[0] = CTL_KERN; 1461573Srgrimes mib[1] = KERN_CLOCKRATE; 1471573Srgrimes if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) { 1481573Srgrimes /* 1491573Srgrimes * Best guess 1501573Srgrimes */ 1511573Srgrimes clockinfo.profhz = hertz(); 1521573Srgrimes } else if (clockinfo.profhz == 0) { 1531573Srgrimes if (clockinfo.hz != 0) 1541573Srgrimes clockinfo.profhz = clockinfo.hz; 1551573Srgrimes else 1561573Srgrimes clockinfo.profhz = hertz(); 1571573Srgrimes } 1581573Srgrimes 1591573Srgrimes moncontrol(0); 160234819Seadler if (getenv("PROFIL_USE_PID")) 161234819Seadler snprintf(outname, sizeof(outname), "%s.%d.gmon", 162234819Seadler _getprogname(), getpid()); 163234819Seadler else 164234819Seadler snprintf(outname, sizeof(outname), "%s.gmon", _getprogname()); 165234819Seadler 166254301Sjilles fd = _open(outname, O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0666); 1671573Srgrimes if (fd < 0) { 16890667Sbde _warn("_mcleanup: %s", outname); 1691573Srgrimes return; 1701573Srgrimes } 1711573Srgrimes#ifdef DEBUG 172254301Sjilles log = _open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0664); 1731573Srgrimes if (log < 0) { 17490667Sbde _warn("_mcleanup: gmon.log"); 1751573Srgrimes return; 1761573Srgrimes } 177135024Skuriyama len = sprintf(buf, "[mcleanup1] kcount 0x%p ssiz %lu\n", 1781573Srgrimes p->kcount, p->kcountsize); 17956698Sjasone _write(log, buf, len); 1801573Srgrimes#endif 1811573Srgrimes hdr = (struct gmonhdr *)&gmonhdr; 18290668Sbde bzero(hdr, sizeof(*hdr)); 1831573Srgrimes hdr->lpc = p->lowpc; 1841573Srgrimes hdr->hpc = p->highpc; 1851573Srgrimes hdr->ncnt = p->kcountsize + sizeof(gmonhdr); 1861573Srgrimes hdr->version = GMONVERSION; 1871573Srgrimes hdr->profrate = clockinfo.profhz; 18856698Sjasone _write(fd, (char *)hdr, sizeof *hdr); 18956698Sjasone _write(fd, p->kcount, p->kcountsize); 1901573Srgrimes endfrom = p->fromssize / sizeof(*p->froms); 1911573Srgrimes for (fromindex = 0; fromindex < endfrom; fromindex++) { 1921573Srgrimes if (p->froms[fromindex] == 0) 1931573Srgrimes continue; 1941573Srgrimes 1951573Srgrimes frompc = p->lowpc; 1961573Srgrimes frompc += fromindex * p->hashfraction * sizeof(*p->froms); 1971573Srgrimes for (toindex = p->froms[fromindex]; toindex != 0; 1981573Srgrimes toindex = p->tos[toindex].link) { 1991573Srgrimes#ifdef DEBUG 2001573Srgrimes len = sprintf(buf, 201135024Skuriyama "[mcleanup2] frompc 0x%lx selfpc 0x%lx count %lu\n" , 2021573Srgrimes frompc, p->tos[toindex].selfpc, 2031573Srgrimes p->tos[toindex].count); 20456698Sjasone _write(log, buf, len); 2051573Srgrimes#endif 2061573Srgrimes rawarc.raw_frompc = frompc; 2071573Srgrimes rawarc.raw_selfpc = p->tos[toindex].selfpc; 2081573Srgrimes rawarc.raw_count = p->tos[toindex].count; 20956698Sjasone _write(fd, &rawarc, sizeof rawarc); 2101573Srgrimes } 2111573Srgrimes } 21256698Sjasone _close(fd); 2131573Srgrimes} 2141573Srgrimes 2151573Srgrimes/* 2161573Srgrimes * Control profiling 2171573Srgrimes * profiling is what mcount checks to see if 2181573Srgrimes * all the data structures are ready. 2191573Srgrimes */ 2201573Srgrimesvoid 2211573Srgrimesmoncontrol(mode) 2221573Srgrimes int mode; 2231573Srgrimes{ 2241573Srgrimes struct gmonparam *p = &_gmonparam; 2251573Srgrimes 2261573Srgrimes if (mode) { 2271573Srgrimes /* start */ 22848838Ssimokawa profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale); 2291573Srgrimes p->state = GMON_PROF_ON; 2301573Srgrimes } else { 2311573Srgrimes /* stop */ 2321573Srgrimes profil((char *)0, 0, 0, 0); 2331573Srgrimes p->state = GMON_PROF_OFF; 2341573Srgrimes } 2351573Srgrimes} 2361573Srgrimes 2371573Srgrimes/* 2381573Srgrimes * discover the tick frequency of the machine 2391573Srgrimes * if something goes wrong, we return 0, an impossible hertz. 2401573Srgrimes */ 2411573Srgrimesstatic int 2421573Srgrimeshertz() 2431573Srgrimes{ 2441573Srgrimes struct itimerval tim; 2458870Srgrimes 2461573Srgrimes tim.it_interval.tv_sec = 0; 2471573Srgrimes tim.it_interval.tv_usec = 1; 2481573Srgrimes tim.it_value.tv_sec = 0; 2491573Srgrimes tim.it_value.tv_usec = 0; 2501573Srgrimes setitimer(ITIMER_REAL, &tim, 0); 2511573Srgrimes setitimer(ITIMER_REAL, 0, &tim); 2521573Srgrimes if (tim.it_interval.tv_usec < 2) 2531573Srgrimes return(0); 2541573Srgrimes return (1000000 / tim.it_interval.tv_usec); 2551573Srgrimes} 256