subr_prof.c revision 13017
11541Srgrimes/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 331541Srgrimes * @(#)subr_prof.c 8.3 (Berkeley) 9/23/93 3413017Sbde * $Id: subr_prof.c,v 1.14 1995/12/14 08:31:44 phk Exp $ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes#include <sys/param.h> 381541Srgrimes#include <sys/systm.h> 3912221Sbde#include <sys/sysproto.h> 401541Srgrimes#include <sys/kernel.h> 411541Srgrimes#include <sys/proc.h> 4212657Sbde#include <sys/resourcevar.h> 437090Sbde#include <sys/sysctl.h> 447090Sbde 451541Srgrimes#include <machine/cpu.h> 461541Srgrimes 471541Srgrimes#ifdef GPROF 481541Srgrimes#include <sys/malloc.h> 491541Srgrimes#include <sys/gmon.h> 501541Srgrimes 5110653Sdgstatic void kmstartup __P((void *)); 5210358SjulianSYSINIT(kmem, SI_SUB_KPROF, SI_ORDER_FIRST, kmstartup, NULL) 5310358Sjulian 541541Srgrimesstruct gmonparam _gmonparam = { GMON_PROF_OFF }; 551541Srgrimes 566009Sbdeextern char btext[]; 571541Srgrimesextern char etext[]; 581541Srgrimes 5910407Sbdestatic void 6012569Sbdekmstartup(dummy) 6112569Sbde void *dummy; 621541Srgrimes{ 631541Srgrimes char *cp; 641541Srgrimes struct gmonparam *p = &_gmonparam; 651541Srgrimes /* 661541Srgrimes * Round lowpc and highpc to multiples of the density we're using 671541Srgrimes * so the rest of the scaling (here and in gprof) stays in ints. 681541Srgrimes */ 696009Sbde p->lowpc = ROUNDDOWN((u_long)btext, HISTFRACTION * sizeof(HISTCOUNTER)); 701541Srgrimes p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER)); 711541Srgrimes p->textsize = p->highpc - p->lowpc; 721541Srgrimes printf("Profiling kernel, textsize=%d [%x..%x]\n", 731541Srgrimes p->textsize, p->lowpc, p->highpc); 741541Srgrimes p->kcountsize = p->textsize / HISTFRACTION; 751541Srgrimes p->hashfraction = HASHFRACTION; 761541Srgrimes p->fromssize = p->textsize / HASHFRACTION; 771541Srgrimes p->tolimit = p->textsize * ARCDENSITY / 100; 781541Srgrimes if (p->tolimit < MINARCS) 791541Srgrimes p->tolimit = MINARCS; 801541Srgrimes else if (p->tolimit > MAXARCS) 811541Srgrimes p->tolimit = MAXARCS; 821541Srgrimes p->tossize = p->tolimit * sizeof(struct tostruct); 831541Srgrimes cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize, 841541Srgrimes M_GPROF, M_NOWAIT); 851541Srgrimes if (cp == 0) { 861541Srgrimes printf("No memory for profiling.\n"); 871541Srgrimes return; 881541Srgrimes } 891541Srgrimes bzero(cp, p->kcountsize + p->tossize + p->fromssize); 901541Srgrimes p->tos = (struct tostruct *)cp; 911541Srgrimes cp += p->tossize; 921541Srgrimes p->kcount = (u_short *)cp; 931541Srgrimes cp += p->kcountsize; 941541Srgrimes p->froms = (u_short *)cp; 951541Srgrimes} 961541Srgrimes 971541Srgrimes/* 981541Srgrimes * Return kernel profiling information. 991541Srgrimes */ 10012429Sphkstatic int 10112429Sphksysctl_kern_prof SYSCTL_HANDLER_ARGS 1021541Srgrimes{ 10312429Sphk int *name = (int *) arg1; 10412429Sphk u_int namelen = arg2; 1051541Srgrimes struct gmonparam *gp = &_gmonparam; 1061541Srgrimes int error; 1071541Srgrimes 1081541Srgrimes /* all sysctl names at this level are terminal */ 1091541Srgrimes if (namelen != 1) 1101541Srgrimes return (ENOTDIR); /* overloaded */ 1111541Srgrimes 1121541Srgrimes switch (name[0]) { 1131541Srgrimes case GPROF_STATE: 11412429Sphk error = sysctl_handle_int(oidp, &gp->state, 0, req); 1151541Srgrimes if (error) 1161541Srgrimes return (error); 1171541Srgrimes if (gp->state == GMON_PROF_OFF) 1181541Srgrimes stopprofclock(&proc0); 1191541Srgrimes else 1201541Srgrimes startprofclock(&proc0); 1211541Srgrimes return (0); 1221541Srgrimes case GPROF_COUNT: 12312429Sphk return (sysctl_handle_opaque(oidp, 12412429Sphk gp->kcount, gp->kcountsize, req)); 1251541Srgrimes case GPROF_FROMS: 12612429Sphk return (sysctl_handle_opaque(oidp, 12712429Sphk gp->froms, gp->fromssize, req)); 1281541Srgrimes case GPROF_TOS: 12912429Sphk return (sysctl_handle_opaque(oidp, 13012429Sphk gp->tos, gp->tossize, req)); 1311541Srgrimes case GPROF_GMONPARAM: 13212429Sphk return (sysctl_handle_opaque(oidp, gp, sizeof *gp, req)); 1331541Srgrimes default: 1341541Srgrimes return (EOPNOTSUPP); 1351541Srgrimes } 1361541Srgrimes /* NOTREACHED */ 1371541Srgrimes} 13812429Sphk 13912429SphkSYSCTL_NODE(_kern, KERN_PROF, prof, CTLFLAG_RW, sysctl_kern_prof, ""); 1401541Srgrimes#endif /* GPROF */ 1411541Srgrimes 1421541Srgrimes/* 1431541Srgrimes * Profiling system call. 1441541Srgrimes * 1451541Srgrimes * The scale factor is a fixed point number with 16 bits of fraction, so that 1461541Srgrimes * 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling. 1471541Srgrimes */ 14812221Sbde#ifndef _SYS_SYSPROTO_H_ 1491541Srgrimesstruct profil_args { 1501541Srgrimes caddr_t samples; 1511541Srgrimes u_int size; 1521541Srgrimes u_int offset; 1531541Srgrimes u_int scale; 1541541Srgrimes}; 15512221Sbde#endif 1561541Srgrimes/* ARGSUSED */ 1571549Srgrimesint 1581541Srgrimesprofil(p, uap, retval) 1591541Srgrimes struct proc *p; 1601541Srgrimes register struct profil_args *uap; 1611541Srgrimes int *retval; 1621541Srgrimes{ 1631541Srgrimes register struct uprof *upp; 1641541Srgrimes int s; 1651541Srgrimes 1661541Srgrimes if (uap->scale > (1 << 16)) 1671541Srgrimes return (EINVAL); 1681541Srgrimes if (uap->scale == 0) { 1691541Srgrimes stopprofclock(p); 1701541Srgrimes return (0); 1711541Srgrimes } 1721541Srgrimes upp = &p->p_stats->p_prof; 1731541Srgrimes 1741541Srgrimes /* Block profile interrupts while changing state. */ 1751541Srgrimes s = splstatclock(); 1761541Srgrimes upp->pr_off = uap->offset; 1771541Srgrimes upp->pr_scale = uap->scale; 1781541Srgrimes upp->pr_base = uap->samples; 1791541Srgrimes upp->pr_size = uap->size; 1801541Srgrimes startprofclock(p); 1811541Srgrimes splx(s); 1821541Srgrimes 1831541Srgrimes return (0); 1841541Srgrimes} 1851541Srgrimes 1861541Srgrimes/* 1871541Srgrimes * Scale is a fixed-point number with the binary point 16 bits 1881541Srgrimes * into the value, and is <= 1.0. pc is at most 32 bits, so the 1891541Srgrimes * intermediate result is at most 48 bits. 1901541Srgrimes */ 1911541Srgrimes#define PC_TO_INDEX(pc, prof) \ 1921541Srgrimes ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \ 1931541Srgrimes (u_quad_t)((prof)->pr_scale)) >> 16) & ~1) 1941541Srgrimes 1951541Srgrimes/* 1961541Srgrimes * Collect user-level profiling statistics; called on a profiling tick, 1971541Srgrimes * when a process is running in user-mode. This routine may be called 1981541Srgrimes * from an interrupt context. We try to update the user profiling buffers 1991541Srgrimes * cheaply with fuswintr() and suswintr(). If that fails, we revert to 2001541Srgrimes * an AST that will vector us to trap() with a context in which copyin 2011541Srgrimes * and copyout will work. Trap will then call addupc_task(). 2021541Srgrimes * 2031541Srgrimes * Note that we may (rarely) not get around to the AST soon enough, and 2041541Srgrimes * lose profile ticks when the next tick overwrites this one, but in this 2051541Srgrimes * case the system is overloaded and the profile is probably already 2061541Srgrimes * inaccurate. 2071541Srgrimes */ 2081541Srgrimesvoid 2091541Srgrimesaddupc_intr(p, pc, ticks) 2101541Srgrimes register struct proc *p; 2111541Srgrimes register u_long pc; 2121541Srgrimes u_int ticks; 2131541Srgrimes{ 2141541Srgrimes register struct uprof *prof; 2151541Srgrimes register caddr_t addr; 2161541Srgrimes register u_int i; 2171541Srgrimes register int v; 2181541Srgrimes 2191541Srgrimes if (ticks == 0) 2201541Srgrimes return; 2211541Srgrimes prof = &p->p_stats->p_prof; 2221541Srgrimes if (pc < prof->pr_off || 2231541Srgrimes (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) 2241541Srgrimes return; /* out of range; ignore */ 2251541Srgrimes 2261541Srgrimes addr = prof->pr_base + i; 2271541Srgrimes if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) { 2281541Srgrimes prof->pr_addr = pc; 2291541Srgrimes prof->pr_ticks = ticks; 2301541Srgrimes need_proftick(p); 2311541Srgrimes } 2321541Srgrimes} 2331541Srgrimes 2341541Srgrimes/* 2351541Srgrimes * Much like before, but we can afford to take faults here. If the 2361541Srgrimes * update fails, we simply turn off profiling. 2371541Srgrimes */ 23813017Sbdevoid 2391541Srgrimesaddupc_task(p, pc, ticks) 2401541Srgrimes register struct proc *p; 2411541Srgrimes register u_long pc; 2421541Srgrimes u_int ticks; 2431541Srgrimes{ 2441541Srgrimes register struct uprof *prof; 2451541Srgrimes register caddr_t addr; 2461541Srgrimes register u_int i; 2471541Srgrimes u_short v; 2481541Srgrimes 2491541Srgrimes /* Testing P_PROFIL may be unnecessary, but is certainly safe. */ 2501541Srgrimes if ((p->p_flag & P_PROFIL) == 0 || ticks == 0) 2511541Srgrimes return; 2521541Srgrimes 2531541Srgrimes prof = &p->p_stats->p_prof; 2541541Srgrimes if (pc < prof->pr_off || 2551541Srgrimes (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) 2561541Srgrimes return; 2571541Srgrimes 2581541Srgrimes addr = prof->pr_base + i; 2591541Srgrimes if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) { 2601541Srgrimes v += ticks; 2611541Srgrimes if (copyout((caddr_t)&v, addr, sizeof(v)) == 0) 2621541Srgrimes return; 2631541Srgrimes } 2641541Srgrimes stopprofclock(p); 2651541Srgrimes} 266