gmon.c revision 200150
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: head/lib/libc/gmon/gmon.c 200150 2009-12-05 19:31:38Z ed $"); 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> 441573Srgrimes#include <stdio.h> 4593399Smarkm#include <stdlib.h> 4671579Sdeischen#include <string.h> 471573Srgrimes#include <unistd.h> 4871579Sdeischen#include "un-namespace.h" 491573Srgrimes 5093399Smarkm#include "libc_private.h" 5193399Smarkm 52153814Sgrehan#if defined(__i386__) || defined(__sparc64__) || defined(__amd64__) || defined(__powerpc__) 53115665Sobrienextern char *minbrk __asm (".minbrk"); 5415634Speter#else 55115665Sobrienextern char *minbrk __asm ("minbrk"); 5615634Speter#endif 571573Srgrimes 581573Srgrimesstruct gmonparam _gmonparam = { GMON_PROF_OFF }; 591573Srgrimes 601573Srgrimesstatic int s_scale; 611573Srgrimes/* see profil(2) where this is describe (incorrectly) */ 621573Srgrimes#define SCALE_1_TO_1 0x10000L 631573Srgrimes 6456698Sjasone#define ERR(s) _write(2, s, sizeof(s)) 651573Srgrimes 6690046Sobrienvoid moncontrol(int); 6790046Sobrienstatic int hertz(void); 681573Srgrimes 691573Srgrimesvoid 701573Srgrimesmonstartup(lowpc, highpc) 711573Srgrimes u_long lowpc; 721573Srgrimes u_long highpc; 731573Srgrimes{ 7490046Sobrien int o; 751573Srgrimes char *cp; 761573Srgrimes struct gmonparam *p = &_gmonparam; 771573Srgrimes 781573Srgrimes /* 791573Srgrimes * round lowpc and highpc to multiples of the density we're using 801573Srgrimes * so the rest of the scaling (here and in gprof) stays in ints. 811573Srgrimes */ 821573Srgrimes p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); 831573Srgrimes p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER)); 841573Srgrimes p->textsize = p->highpc - p->lowpc; 851573Srgrimes p->kcountsize = p->textsize / HISTFRACTION; 861573Srgrimes p->hashfraction = HASHFRACTION; 871573Srgrimes p->fromssize = p->textsize / HASHFRACTION; 881573Srgrimes p->tolimit = p->textsize * ARCDENSITY / 100; 891573Srgrimes if (p->tolimit < MINARCS) 901573Srgrimes p->tolimit = MINARCS; 911573Srgrimes else if (p->tolimit > MAXARCS) 921573Srgrimes p->tolimit = MAXARCS; 931573Srgrimes p->tossize = p->tolimit * sizeof(struct tostruct); 941573Srgrimes 951573Srgrimes cp = sbrk(p->kcountsize + p->fromssize + p->tossize); 961573Srgrimes if (cp == (char *)-1) { 971573Srgrimes ERR("monstartup: out of memory\n"); 981573Srgrimes return; 991573Srgrimes } 1001573Srgrimes#ifdef notdef 1011573Srgrimes bzero(cp, p->kcountsize + p->fromssize + p->tossize); 1021573Srgrimes#endif 1031573Srgrimes p->tos = (struct tostruct *)cp; 1041573Srgrimes cp += p->tossize; 1051573Srgrimes p->kcount = (u_short *)cp; 1061573Srgrimes cp += p->kcountsize; 1071573Srgrimes p->froms = (u_short *)cp; 1081573Srgrimes 1091573Srgrimes minbrk = sbrk(0); 1101573Srgrimes p->tos[0].link = 0; 1111573Srgrimes 1121573Srgrimes o = p->highpc - p->lowpc; 1131573Srgrimes if (p->kcountsize < o) { 1141573Srgrimes#ifndef hp300 1151573Srgrimes s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1; 1161573Srgrimes#else /* avoid floating point */ 1171573Srgrimes int quot = o / p->kcountsize; 1188870Srgrimes 1191573Srgrimes if (quot >= 0x10000) 1201573Srgrimes s_scale = 1; 1211573Srgrimes else if (quot >= 0x100) 1221573Srgrimes s_scale = 0x10000 / quot; 1231573Srgrimes else if (o >= 0x800000) 1241573Srgrimes s_scale = 0x1000000 / (o / (p->kcountsize >> 8)); 1251573Srgrimes else 1261573Srgrimes s_scale = 0x1000000 / ((o << 8) / p->kcountsize); 1271573Srgrimes#endif 1281573Srgrimes } else 1291573Srgrimes s_scale = SCALE_1_TO_1; 1301573Srgrimes 1311573Srgrimes moncontrol(1); 1321573Srgrimes} 1331573Srgrimes 1341573Srgrimesvoid 135200150Sed_mcleanup(void) 1361573Srgrimes{ 1371573Srgrimes int fd; 1381573Srgrimes int fromindex; 1391573Srgrimes int endfrom; 1401573Srgrimes u_long frompc; 1411573Srgrimes int toindex; 1421573Srgrimes struct rawarc rawarc; 1431573Srgrimes struct gmonparam *p = &_gmonparam; 1441573Srgrimes struct gmonhdr gmonhdr, *hdr; 1451573Srgrimes struct clockinfo clockinfo; 14638845Sjb char outname[128]; 1471573Srgrimes int mib[2]; 1481573Srgrimes size_t size; 1491573Srgrimes#ifdef DEBUG 1501573Srgrimes int log, len; 1511573Srgrimes char buf[200]; 1521573Srgrimes#endif 1531573Srgrimes 1541573Srgrimes if (p->state == GMON_PROF_ERROR) 1551573Srgrimes ERR("_mcleanup: tos overflow\n"); 1561573Srgrimes 1571573Srgrimes size = sizeof(clockinfo); 1581573Srgrimes mib[0] = CTL_KERN; 1591573Srgrimes mib[1] = KERN_CLOCKRATE; 1601573Srgrimes if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) { 1611573Srgrimes /* 1621573Srgrimes * Best guess 1631573Srgrimes */ 1641573Srgrimes clockinfo.profhz = hertz(); 1651573Srgrimes } else if (clockinfo.profhz == 0) { 1661573Srgrimes if (clockinfo.hz != 0) 1671573Srgrimes clockinfo.profhz = clockinfo.hz; 1681573Srgrimes else 1691573Srgrimes clockinfo.profhz = hertz(); 1701573Srgrimes } 1711573Srgrimes 1721573Srgrimes moncontrol(0); 17393399Smarkm snprintf(outname, sizeof(outname), "%s.gmon", _getprogname()); 17456698Sjasone fd = _open(outname, O_CREAT|O_TRUNC|O_WRONLY, 0666); 1751573Srgrimes if (fd < 0) { 17690667Sbde _warn("_mcleanup: %s", outname); 1771573Srgrimes return; 1781573Srgrimes } 1791573Srgrimes#ifdef DEBUG 18056698Sjasone log = _open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664); 1811573Srgrimes if (log < 0) { 18290667Sbde _warn("_mcleanup: gmon.log"); 1831573Srgrimes return; 1841573Srgrimes } 185135024Skuriyama len = sprintf(buf, "[mcleanup1] kcount 0x%p ssiz %lu\n", 1861573Srgrimes p->kcount, p->kcountsize); 18756698Sjasone _write(log, buf, len); 1881573Srgrimes#endif 1891573Srgrimes hdr = (struct gmonhdr *)&gmonhdr; 19090668Sbde bzero(hdr, sizeof(*hdr)); 1911573Srgrimes hdr->lpc = p->lowpc; 1921573Srgrimes hdr->hpc = p->highpc; 1931573Srgrimes hdr->ncnt = p->kcountsize + sizeof(gmonhdr); 1941573Srgrimes hdr->version = GMONVERSION; 1951573Srgrimes hdr->profrate = clockinfo.profhz; 19656698Sjasone _write(fd, (char *)hdr, sizeof *hdr); 19756698Sjasone _write(fd, p->kcount, p->kcountsize); 1981573Srgrimes endfrom = p->fromssize / sizeof(*p->froms); 1991573Srgrimes for (fromindex = 0; fromindex < endfrom; fromindex++) { 2001573Srgrimes if (p->froms[fromindex] == 0) 2011573Srgrimes continue; 2021573Srgrimes 2031573Srgrimes frompc = p->lowpc; 2041573Srgrimes frompc += fromindex * p->hashfraction * sizeof(*p->froms); 2051573Srgrimes for (toindex = p->froms[fromindex]; toindex != 0; 2061573Srgrimes toindex = p->tos[toindex].link) { 2071573Srgrimes#ifdef DEBUG 2081573Srgrimes len = sprintf(buf, 209135024Skuriyama "[mcleanup2] frompc 0x%lx selfpc 0x%lx count %lu\n" , 2101573Srgrimes frompc, p->tos[toindex].selfpc, 2111573Srgrimes p->tos[toindex].count); 21256698Sjasone _write(log, buf, len); 2131573Srgrimes#endif 2141573Srgrimes rawarc.raw_frompc = frompc; 2151573Srgrimes rawarc.raw_selfpc = p->tos[toindex].selfpc; 2161573Srgrimes rawarc.raw_count = p->tos[toindex].count; 21756698Sjasone _write(fd, &rawarc, sizeof rawarc); 2181573Srgrimes } 2191573Srgrimes } 22056698Sjasone _close(fd); 2211573Srgrimes} 2221573Srgrimes 2231573Srgrimes/* 2241573Srgrimes * Control profiling 2251573Srgrimes * profiling is what mcount checks to see if 2261573Srgrimes * all the data structures are ready. 2271573Srgrimes */ 2281573Srgrimesvoid 2291573Srgrimesmoncontrol(mode) 2301573Srgrimes int mode; 2311573Srgrimes{ 2321573Srgrimes struct gmonparam *p = &_gmonparam; 2331573Srgrimes 2341573Srgrimes if (mode) { 2351573Srgrimes /* start */ 23648838Ssimokawa profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale); 2371573Srgrimes p->state = GMON_PROF_ON; 2381573Srgrimes } else { 2391573Srgrimes /* stop */ 2401573Srgrimes profil((char *)0, 0, 0, 0); 2411573Srgrimes p->state = GMON_PROF_OFF; 2421573Srgrimes } 2431573Srgrimes} 2441573Srgrimes 2451573Srgrimes/* 2461573Srgrimes * discover the tick frequency of the machine 2471573Srgrimes * if something goes wrong, we return 0, an impossible hertz. 2481573Srgrimes */ 2491573Srgrimesstatic int 2501573Srgrimeshertz() 2511573Srgrimes{ 2521573Srgrimes struct itimerval tim; 2538870Srgrimes 2541573Srgrimes tim.it_interval.tv_sec = 0; 2551573Srgrimes tim.it_interval.tv_usec = 1; 2561573Srgrimes tim.it_value.tv_sec = 0; 2571573Srgrimes tim.it_value.tv_usec = 0; 2581573Srgrimes setitimer(ITIMER_REAL, &tim, 0); 2591573Srgrimes setitimer(ITIMER_REAL, 0, &tim); 2601573Srgrimes if (tim.it_interval.tv_usec < 2) 2611573Srgrimes return(0); 2621573Srgrimes return (1000000 / tim.it_interval.tv_usec); 2631573Srgrimes} 264