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