subr_prof.c revision 129498
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 * 4. Neither the name of the University nor the names of its contributors
141541Srgrimes *    may be used to endorse or promote products derived from this software
151541Srgrimes *    without specific prior written permission.
161541Srgrimes *
171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271541Srgrimes * SUCH DAMAGE.
281541Srgrimes *
291541Srgrimes *	@(#)subr_prof.c	8.3 (Berkeley) 9/23/93
301541Srgrimes */
311541Srgrimes
32116182Sobrien#include <sys/cdefs.h>
33116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/subr_prof.c 129498 2004-05-20 16:12:19Z bde $");
34116182Sobrien
351541Srgrimes#include <sys/param.h>
361541Srgrimes#include <sys/systm.h>
3712221Sbde#include <sys/sysproto.h>
3852147Sbde#include <sys/kernel.h>
3976166Smarkm#include <sys/lock.h>
4076166Smarkm#include <sys/mutex.h>
411541Srgrimes#include <sys/proc.h>
4212657Sbde#include <sys/resourcevar.h>
4352147Sbde#include <sys/sysctl.h>
447090Sbde
451541Srgrimes#include <machine/cpu.h>
461541Srgrimes
471541Srgrimes#ifdef GPROF
481541Srgrimes#include <sys/malloc.h>
491541Srgrimes#include <sys/gmon.h>
5046548Sbde#undef MCOUNT
511541Srgrimes
5230354Sphkstatic MALLOC_DEFINE(M_GPROF, "gprof", "kernel profiling buffer");
5330309Sphk
5492723Salfredstatic void kmstartup(void *);
5510358SjulianSYSINIT(kmem, SI_SUB_KPROF, SI_ORDER_FIRST, kmstartup, NULL)
5610358Sjulian
571541Srgrimesstruct gmonparam _gmonparam = { GMON_PROF_OFF };
581541Srgrimes
5919000Sbde#ifdef GUPROF
6019000Sbdevoid
6119000Sbdenullfunc_loop_profiled()
6219000Sbde{
6319000Sbde	int i;
6419000Sbde
6519000Sbde	for (i = 0; i < CALIB_SCALE; i++)
6619000Sbde		nullfunc_profiled();
6719000Sbde}
6819000Sbde
6920396Sbde#define	nullfunc_loop_profiled_end	nullfunc_profiled	/* XXX */
7020396Sbde
7119000Sbdevoid
7219000Sbdenullfunc_profiled()
7319000Sbde{
7419000Sbde}
7519000Sbde#endif /* GUPROF */
7619000Sbde
7785733Sgreen/*
7885733Sgreen * Update the histograms to support extending the text region arbitrarily.
7985733Sgreen * This is done slightly naively (no sparse regions), so will waste slight
8085733Sgreen * amounts of memory, but will overall work nicely enough to allow profiling
8185733Sgreen * of KLDs.
8285733Sgreen */
8385733Sgreenvoid
8485733Sgreenkmupetext(uintfptr_t nhighpc)
8585733Sgreen{
8685733Sgreen	struct gmonparam np;	/* slightly large */
8785733Sgreen	struct gmonparam *p = &_gmonparam;
8885733Sgreen	char *cp;
8985733Sgreen
9085733Sgreen	GIANT_REQUIRED;
9185733Sgreen	bcopy(p, &np, sizeof(*p));
9285733Sgreen	np.highpc = ROUNDUP(nhighpc, HISTFRACTION * sizeof(HISTCOUNTER));
9385733Sgreen	if (np.highpc <= p->highpc)
9485733Sgreen		return;
9585733Sgreen	np.textsize = np.highpc - p->lowpc;
9685733Sgreen	np.kcountsize = np.textsize / HISTFRACTION;
9785733Sgreen	np.hashfraction = HASHFRACTION;
9885733Sgreen	np.fromssize = np.textsize / HASHFRACTION;
9985733Sgreen	np.tolimit = np.textsize * ARCDENSITY / 100;
10085733Sgreen	if (np.tolimit < MINARCS)
10185733Sgreen		np.tolimit = MINARCS;
10285733Sgreen	else if (np.tolimit > MAXARCS)
10385733Sgreen		np.tolimit = MAXARCS;
10485733Sgreen	np.tossize = np.tolimit * sizeof(struct tostruct);
10585733Sgreen	cp = malloc(np.kcountsize + np.fromssize + np.tossize,
106111119Simp	    M_GPROF, M_WAITOK);
10785733Sgreen	/*
10885733Sgreen	 * Check for something else extending highpc while we slept.
10985733Sgreen	 */
11085733Sgreen	if (np.highpc <= p->highpc) {
11185733Sgreen		free(cp, M_GPROF);
11285733Sgreen		return;
11385733Sgreen	}
11485733Sgreen	np.tos = (struct tostruct *)cp;
11585733Sgreen	cp += np.tossize;
11685733Sgreen	np.kcount = (HISTCOUNTER *)cp;
11785733Sgreen	cp += np.kcountsize;
11885733Sgreen	np.froms = (u_short *)cp;
11985733Sgreen#ifdef GUPROF
12085733Sgreen	/* Reinitialize pointers to overhead counters. */
12185733Sgreen	np.cputime_count = &KCOUNT(&np, PC_TO_I(&np, cputime));
12285733Sgreen	np.mcount_count = &KCOUNT(&np, PC_TO_I(&np, mcount));
12385733Sgreen	np.mexitcount_count = &KCOUNT(&np, PC_TO_I(&np, mexitcount));
12485733Sgreen#endif
12588088Sjhb	critical_enter();
12685733Sgreen	bcopy(p->tos, np.tos, p->tossize);
12785733Sgreen	bzero((char *)np.tos + p->tossize, np.tossize - p->tossize);
12885733Sgreen	bcopy(p->kcount, np.kcount, p->kcountsize);
12985733Sgreen	bzero((char *)np.kcount + p->kcountsize, np.kcountsize -
13085733Sgreen	    p->kcountsize);
13185733Sgreen	bcopy(p->froms, np.froms, p->fromssize);
13285733Sgreen	bzero((char *)np.froms + p->fromssize, np.fromssize - p->fromssize);
13385733Sgreen	cp = (char *)p->tos;
13485733Sgreen	bcopy(&np, p, sizeof(*p));
13588088Sjhb	critical_exit();
13685733Sgreen	free(cp, M_GPROF);
13785733Sgreen}
13885733Sgreen
13910407Sbdestatic void
14012569Sbdekmstartup(dummy)
14112569Sbde	void *dummy;
1421541Srgrimes{
1431541Srgrimes	char *cp;
1441541Srgrimes	struct gmonparam *p = &_gmonparam;
14513107Sbde#ifdef GUPROF
14619000Sbde	int cputime_overhead;
14719000Sbde	int empty_loop_time;
14819000Sbde	int i;
14919000Sbde	int mcount_overhead;
15019000Sbde	int mexitcount_overhead;
15119000Sbde	int nullfunc_loop_overhead;
15219000Sbde	int nullfunc_loop_profiled_time;
15337629Sbde	uintfptr_t tmp_addr;
15413107Sbde#endif
15513107Sbde
1561541Srgrimes	/*
1571541Srgrimes	 * Round lowpc and highpc to multiples of the density we're using
1581541Srgrimes	 * so the rest of the scaling (here and in gprof) stays in ints.
1591541Srgrimes	 */
1606009Sbde	p->lowpc = ROUNDDOWN((u_long)btext, HISTFRACTION * sizeof(HISTCOUNTER));
1611541Srgrimes	p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
1621541Srgrimes	p->textsize = p->highpc - p->lowpc;
16319000Sbde	printf("Profiling kernel, textsize=%lu [%x..%x]\n",
1641541Srgrimes	       p->textsize, p->lowpc, p->highpc);
1651541Srgrimes	p->kcountsize = p->textsize / HISTFRACTION;
1661541Srgrimes	p->hashfraction = HASHFRACTION;
1671541Srgrimes	p->fromssize = p->textsize / HASHFRACTION;
1681541Srgrimes	p->tolimit = p->textsize * ARCDENSITY / 100;
1691541Srgrimes	if (p->tolimit < MINARCS)
1701541Srgrimes		p->tolimit = MINARCS;
1711541Srgrimes	else if (p->tolimit > MAXARCS)
1721541Srgrimes		p->tolimit = MAXARCS;
1731541Srgrimes	p->tossize = p->tolimit * sizeof(struct tostruct);
1741541Srgrimes	cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize,
175111119Simp	    M_GPROF, M_WAITOK | M_ZERO);
1761541Srgrimes	p->tos = (struct tostruct *)cp;
1771541Srgrimes	cp += p->tossize;
17813107Sbde	p->kcount = (HISTCOUNTER *)cp;
1791541Srgrimes	cp += p->kcountsize;
1801541Srgrimes	p->froms = (u_short *)cp;
18113107Sbde
18213107Sbde#ifdef GUPROF
18319000Sbde	/* Initialize pointers to overhead counters. */
18413107Sbde	p->cputime_count = &KCOUNT(p, PC_TO_I(p, cputime));
18513107Sbde	p->mcount_count = &KCOUNT(p, PC_TO_I(p, mcount));
18613107Sbde	p->mexitcount_count = &KCOUNT(p, PC_TO_I(p, mexitcount));
18713107Sbde
18813107Sbde	/*
18919000Sbde	 * Disable interrupts to avoid interference while we calibrate
19019000Sbde	 * things.
19113107Sbde	 */
19288088Sjhb	critical_enter();
19313107Sbde
19419000Sbde	/*
19519000Sbde	 * Determine overheads.
19619000Sbde	 * XXX this needs to be repeated for each useful timer/counter.
19719000Sbde	 */
19819000Sbde	cputime_overhead = 0;
19919000Sbde	startguprof(p);
20013107Sbde	for (i = 0; i < CALIB_SCALE; i++)
20119000Sbde		cputime_overhead += cputime();
20213107Sbde
20319000Sbde	empty_loop();
20419000Sbde	startguprof(p);
20519000Sbde	empty_loop();
20619000Sbde	empty_loop_time = cputime();
20719000Sbde
20819000Sbde	nullfunc_loop_profiled();
20919000Sbde
21019000Sbde	/*
21119000Sbde	 * Start profiling.  There won't be any normal function calls since
21219000Sbde	 * interrupts are disabled, but we will call the profiling routines
21319000Sbde	 * directly to determine their overheads.
21419000Sbde	 */
21519000Sbde	p->state = GMON_PROF_HIRES;
21619000Sbde
21719000Sbde	startguprof(p);
21819000Sbde	nullfunc_loop_profiled();
21919000Sbde
22019000Sbde	startguprof(p);
22113107Sbde	for (i = 0; i < CALIB_SCALE; i++)
222129498Sbde		MCOUNT_OVERHEAD(profil);
22319000Sbde	mcount_overhead = KCOUNT(p, PC_TO_I(p, profil));
22413107Sbde
22519000Sbde	startguprof(p);
22613107Sbde	for (i = 0; i < CALIB_SCALE; i++)
227129498Sbde		MEXITCOUNT_OVERHEAD();
228129498Sbde	MEXITCOUNT_OVERHEAD_GETLABEL(tmp_addr);
22920396Sbde	mexitcount_overhead = KCOUNT(p, PC_TO_I(p, tmp_addr));
23013107Sbde
23113107Sbde	p->state = GMON_PROF_OFF;
23219000Sbde	stopguprof(p);
23319000Sbde
23488088Sjhb	critical_exit();
23513107Sbde
23619000Sbde	nullfunc_loop_profiled_time = 0;
23737629Sbde	for (tmp_addr = (uintfptr_t)nullfunc_loop_profiled;
23837629Sbde	     tmp_addr < (uintfptr_t)nullfunc_loop_profiled_end;
23920396Sbde	     tmp_addr += HISTFRACTION * sizeof(HISTCOUNTER))
24020396Sbde		nullfunc_loop_profiled_time += KCOUNT(p, PC_TO_I(p, tmp_addr));
24119000Sbde#define CALIB_DOSCALE(count)	(((count) + CALIB_SCALE / 3) / CALIB_SCALE)
24219000Sbde#define	c2n(count, freq)	((int)((count) * 1000000000LL / freq))
24319000Sbde	printf("cputime %d, empty_loop %d, nullfunc_loop_profiled %d, mcount %d, mexitcount %d\n",
24419000Sbde	       CALIB_DOSCALE(c2n(cputime_overhead, p->profrate)),
24519000Sbde	       CALIB_DOSCALE(c2n(empty_loop_time, p->profrate)),
24619000Sbde	       CALIB_DOSCALE(c2n(nullfunc_loop_profiled_time, p->profrate)),
24719000Sbde	       CALIB_DOSCALE(c2n(mcount_overhead, p->profrate)),
24819000Sbde	       CALIB_DOSCALE(c2n(mexitcount_overhead, p->profrate)));
24919000Sbde	cputime_overhead -= empty_loop_time;
25019000Sbde	mcount_overhead -= empty_loop_time;
25119000Sbde	mexitcount_overhead -= empty_loop_time;
25219000Sbde
25319000Sbde	/*-
25419000Sbde	 * Profiling overheads are determined by the times between the
25519000Sbde	 * following events:
25619000Sbde	 *	MC1: mcount() is called
25719000Sbde	 *	MC2: cputime() (called from mcount()) latches the timer
25819000Sbde	 *	MC3: mcount() completes
25919000Sbde	 *	ME1: mexitcount() is called
26019000Sbde	 *	ME2: cputime() (called from mexitcount()) latches the timer
26119000Sbde	 *	ME3: mexitcount() completes.
26219000Sbde	 * The times between the events vary slightly depending on instruction
26319000Sbde	 * combination and cache misses, etc.  Attempt to determine the
26419000Sbde	 * minimum times.  These can be subtracted from the profiling times
26519000Sbde	 * without much risk of reducing the profiling times below what they
26619000Sbde	 * would be when profiling is not configured.  Abbreviate:
26719000Sbde	 *	ab = minimum time between MC1 and MC3
26819000Sbde	 *	a  = minumum time between MC1 and MC2
26919000Sbde	 *	b  = minimum time between MC2 and MC3
27019000Sbde	 *	cd = minimum time between ME1 and ME3
27119000Sbde	 *	c  = minimum time between ME1 and ME2
27219000Sbde	 *	d  = minimum time between ME2 and ME3.
27319000Sbde	 * These satisfy the relations:
27419000Sbde	 *	ab            <= mcount_overhead		(just measured)
27519000Sbde	 *	a + b         <= ab
27619000Sbde	 *	        cd    <= mexitcount_overhead		(just measured)
27719000Sbde	 *	        c + d <= cd
27819000Sbde	 *	a         + d <= nullfunc_loop_profiled_time	(just measured)
27919000Sbde	 *	a >= 0, b >= 0, c >= 0, d >= 0.
28019000Sbde	 * Assume that ab and cd are equal to the minimums.
28119000Sbde	 */
28219000Sbde	p->cputime_overhead = CALIB_DOSCALE(cputime_overhead);
28319000Sbde	p->mcount_overhead = CALIB_DOSCALE(mcount_overhead - cputime_overhead);
28419000Sbde	p->mexitcount_overhead = CALIB_DOSCALE(mexitcount_overhead
28519000Sbde					       - cputime_overhead);
28619000Sbde	nullfunc_loop_overhead = nullfunc_loop_profiled_time - empty_loop_time;
28719000Sbde	p->mexitcount_post_overhead = CALIB_DOSCALE((mcount_overhead
28819000Sbde						     - nullfunc_loop_overhead)
28919000Sbde						    / 4);
29019000Sbde	p->mexitcount_pre_overhead = p->mexitcount_overhead
29119000Sbde				     + p->cputime_overhead
29219000Sbde				     - p->mexitcount_post_overhead;
29319000Sbde	p->mcount_pre_overhead = CALIB_DOSCALE(nullfunc_loop_overhead)
29419000Sbde				 - p->mexitcount_post_overhead;
29519000Sbde	p->mcount_post_overhead = p->mcount_overhead
29619000Sbde				  + p->cputime_overhead
29719000Sbde				  - p->mcount_pre_overhead;
29819000Sbde	printf(
29919000Sbde"Profiling overheads: mcount: %d+%d, %d+%d; mexitcount: %d+%d, %d+%d nsec\n",
30019000Sbde	       c2n(p->cputime_overhead, p->profrate),
30119000Sbde	       c2n(p->mcount_overhead, p->profrate),
30219000Sbde	       c2n(p->mcount_pre_overhead, p->profrate),
30319000Sbde	       c2n(p->mcount_post_overhead, p->profrate),
30419000Sbde	       c2n(p->cputime_overhead, p->profrate),
30519000Sbde	       c2n(p->mexitcount_overhead, p->profrate),
30619000Sbde	       c2n(p->mexitcount_pre_overhead, p->profrate),
30719000Sbde	       c2n(p->mexitcount_post_overhead, p->profrate));
30819000Sbde	printf(
30919000Sbde"Profiling overheads: mcount: %d+%d, %d+%d; mexitcount: %d+%d, %d+%d cycles\n",
31019000Sbde	       p->cputime_overhead, p->mcount_overhead,
31119000Sbde	       p->mcount_pre_overhead, p->mcount_post_overhead,
31219000Sbde	       p->cputime_overhead, p->mexitcount_overhead,
31319000Sbde	       p->mexitcount_pre_overhead, p->mexitcount_post_overhead);
31413107Sbde#endif /* GUPROF */
3151541Srgrimes}
3161541Srgrimes
3171541Srgrimes/*
3181541Srgrimes * Return kernel profiling information.
3191541Srgrimes */
32012429Sphkstatic int
32162573Sphksysctl_kern_prof(SYSCTL_HANDLER_ARGS)
3221541Srgrimes{
32312429Sphk	int *name = (int *) arg1;
32412429Sphk	u_int namelen = arg2;
3251541Srgrimes	struct gmonparam *gp = &_gmonparam;
3261541Srgrimes	int error;
32713107Sbde	int state;
3281541Srgrimes
3291541Srgrimes	/* all sysctl names at this level are terminal */
3301541Srgrimes	if (namelen != 1)
3311541Srgrimes		return (ENOTDIR);		/* overloaded */
3321541Srgrimes
3331541Srgrimes	switch (name[0]) {
3341541Srgrimes	case GPROF_STATE:
33513107Sbde		state = gp->state;
33613107Sbde		error = sysctl_handle_int(oidp, &state, 0, req);
3371541Srgrimes		if (error)
3381541Srgrimes			return (error);
33913107Sbde		if (!req->newptr)
34013107Sbde			return (0);
34113107Sbde		if (state == GMON_PROF_OFF) {
34219000Sbde			gp->state = state;
343110530Sjulian			PROC_LOCK(&proc0);
3441541Srgrimes			stopprofclock(&proc0);
345110530Sjulian			PROC_UNLOCK(&proc0);
34619000Sbde			stopguprof(gp);
34713107Sbde		} else if (state == GMON_PROF_ON) {
34819000Sbde			gp->state = GMON_PROF_OFF;
34919000Sbde			stopguprof(gp);
35013107Sbde			gp->profrate = profhz;
351113874Sjhb			PROC_LOCK(&proc0);
35219000Sbde			startprofclock(&proc0);
353113874Sjhb			PROC_UNLOCK(&proc0);
35413107Sbde			gp->state = state;
35513107Sbde#ifdef GUPROF
35613107Sbde		} else if (state == GMON_PROF_HIRES) {
35719000Sbde			gp->state = GMON_PROF_OFF;
358110530Sjulian			PROC_LOCK(&proc0);
35913107Sbde			stopprofclock(&proc0);
360110530Sjulian			PROC_UNLOCK(&proc0);
36119000Sbde			startguprof(gp);
36213107Sbde			gp->state = state;
36313107Sbde#endif
36413107Sbde		} else if (state != gp->state)
36513107Sbde			return (EINVAL);
3661541Srgrimes		return (0);
3671541Srgrimes	case GPROF_COUNT:
36812429Sphk		return (sysctl_handle_opaque(oidp,
36912429Sphk			gp->kcount, gp->kcountsize, req));
3701541Srgrimes	case GPROF_FROMS:
37112429Sphk		return (sysctl_handle_opaque(oidp,
37212429Sphk			gp->froms, gp->fromssize, req));
3731541Srgrimes	case GPROF_TOS:
37412429Sphk		return (sysctl_handle_opaque(oidp,
37512429Sphk			gp->tos, gp->tossize, req));
3761541Srgrimes	case GPROF_GMONPARAM:
37712429Sphk		return (sysctl_handle_opaque(oidp, gp, sizeof *gp, req));
3781541Srgrimes	default:
3791541Srgrimes		return (EOPNOTSUPP);
3801541Srgrimes	}
3811541Srgrimes	/* NOTREACHED */
3821541Srgrimes}
38312429Sphk
38412429SphkSYSCTL_NODE(_kern, KERN_PROF, prof, CTLFLAG_RW, sysctl_kern_prof, "");
3851541Srgrimes#endif /* GPROF */
3861541Srgrimes
3871541Srgrimes/*
3881541Srgrimes * Profiling system call.
3891541Srgrimes *
3901541Srgrimes * The scale factor is a fixed point number with 16 bits of fraction, so that
3911541Srgrimes * 1.0 is represented as 0x10000.  A scale factor of 0 turns off profiling.
3921541Srgrimes */
39312221Sbde#ifndef _SYS_SYSPROTO_H_
3941541Srgrimesstruct profil_args {
3951541Srgrimes	caddr_t	samples;
39638864Sbde	size_t	size;
39738864Sbde	size_t	offset;
3981541Srgrimes	u_int	scale;
3991541Srgrimes};
40012221Sbde#endif
40182717Sdillon/*
40282717Sdillon * MPSAFE
40382717Sdillon */
4041541Srgrimes/* ARGSUSED */
4051549Srgrimesint
40683366Sjulianprofil(td, uap)
40783366Sjulian	struct thread *td;
4081541Srgrimes	register struct profil_args *uap;
4091541Srgrimes{
410110530Sjulian	struct uprof *upp;
411113874Sjhb	struct proc *p;
4121541Srgrimes
413113874Sjhb	if (uap->scale > (1 << 16))
414113874Sjhb		return (EINVAL);
41582717Sdillon
416113874Sjhb	p = td->td_proc;
4171541Srgrimes	if (uap->scale == 0) {
418110530Sjulian		PROC_LOCK(td->td_proc);
41983366Sjulian		stopprofclock(td->td_proc);
420110530Sjulian		PROC_UNLOCK(td->td_proc);
421113874Sjhb		return (0);
4221541Srgrimes	}
42383366Sjulian	upp = &td->td_proc->p_stats->p_prof;
4241541Srgrimes	upp->pr_off = uap->offset;
4251541Srgrimes	upp->pr_scale = uap->scale;
4261541Srgrimes	upp->pr_base = uap->samples;
4271541Srgrimes	upp->pr_size = uap->size;
428113874Sjhb	PROC_LOCK(p);
429113874Sjhb	startprofclock(p);
430113874Sjhb	PROC_UNLOCK(p);
4311541Srgrimes
432113874Sjhb	return (0);
4331541Srgrimes}
4341541Srgrimes
4351541Srgrimes/*
4361541Srgrimes * Scale is a fixed-point number with the binary point 16 bits
4371541Srgrimes * into the value, and is <= 1.0.  pc is at most 32 bits, so the
4381541Srgrimes * intermediate result is at most 48 bits.
4391541Srgrimes */
4401541Srgrimes#define	PC_TO_INDEX(pc, prof) \
4411541Srgrimes	((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
4421541Srgrimes	    (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
4431541Srgrimes
4441541Srgrimes/*
4451541Srgrimes * Collect user-level profiling statistics; called on a profiling tick,
4461541Srgrimes * when a process is running in user-mode.  This routine may be called
4471541Srgrimes * from an interrupt context.  We try to update the user profiling buffers
4481541Srgrimes * cheaply with fuswintr() and suswintr().  If that fails, we revert to
4491541Srgrimes * an AST that will vector us to trap() with a context in which copyin
4501541Srgrimes * and copyout will work.  Trap will then call addupc_task().
4511541Srgrimes *
4521541Srgrimes * Note that we may (rarely) not get around to the AST soon enough, and
4531541Srgrimes * lose profile ticks when the next tick overwrites this one, but in this
4541541Srgrimes * case the system is overloaded and the profile is probably already
4551541Srgrimes * inaccurate.
4561541Srgrimes */
4571541Srgrimesvoid
458111032Sjulianaddupc_intr(struct thread *td, uintptr_t pc, u_int ticks)
4591541Srgrimes{
460110530Sjulian	struct uprof *prof;
461110530Sjulian	caddr_t addr;
462110530Sjulian	u_int i;
463110530Sjulian	int v;
4641541Srgrimes
4651541Srgrimes	if (ticks == 0)
4661541Srgrimes		return;
467111032Sjulian	prof = &td->td_proc->p_stats->p_prof;
4681541Srgrimes	if (pc < prof->pr_off ||
4691541Srgrimes	    (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
4701541Srgrimes		return;			/* out of range; ignore */
4711541Srgrimes
4721541Srgrimes	addr = prof->pr_base + i;
4731541Srgrimes	if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) {
47481493Sjhb		mtx_lock_spin(&sched_lock);
475110190Sjulian		prof->pr_addr = pc;
476110190Sjulian		prof->pr_ticks = ticks;
477111032Sjulian		td->td_flags |= TDF_OWEUPC | TDF_ASTPENDING ;
47881493Sjhb		mtx_unlock_spin(&sched_lock);
4791541Srgrimes	}
4801541Srgrimes}
4811541Srgrimes
4821541Srgrimes/*
4831541Srgrimes * Much like before, but we can afford to take faults here.  If the
4841541Srgrimes * update fails, we simply turn off profiling.
4851541Srgrimes */
48613017Sbdevoid
487111032Sjulianaddupc_task(struct thread *td, uintptr_t pc, u_int ticks)
4881541Srgrimes{
489111032Sjulian	struct proc *p = td->td_proc;
490110530Sjulian	struct uprof *prof;
491110530Sjulian	caddr_t addr;
492110530Sjulian	u_int i;
4931541Srgrimes	u_short v;
494110530Sjulian	int stop = 0;
4951541Srgrimes
49688119Sjhb	if (ticks == 0)
4971541Srgrimes		return;
4981541Srgrimes
499110530Sjulian	PROC_LOCK(p);
500113874Sjhb	if (!(p->p_flag & P_PROFIL)) {
501110530Sjulian		PROC_UNLOCK(p);
502110530Sjulian		return;
503110530Sjulian	}
504110530Sjulian	p->p_profthreads++;
505110530Sjulian	PROC_UNLOCK(p);
5061541Srgrimes	prof = &p->p_stats->p_prof;
5071541Srgrimes	if (pc < prof->pr_off ||
508110530Sjulian	    (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) {
509110530Sjulian		goto out;
510110530Sjulian	}
5111541Srgrimes
5121541Srgrimes	addr = prof->pr_base + i;
51399012Salfred	if (copyin(addr, &v, sizeof(v)) == 0) {
5141541Srgrimes		v += ticks;
51599012Salfred		if (copyout(&v, addr, sizeof(v)) == 0)
516110530Sjulian			goto out;
5171541Srgrimes	}
518110530Sjulian	stop = 1;
519110530Sjulian
520110530Sjulianout:
521110530Sjulian	PROC_LOCK(p);
522110530Sjulian	if (--p->p_profthreads == 0) {
523113874Sjhb		if (p->p_flag & P_STOPPROF) {
524110530Sjulian			wakeup(&p->p_profthreads);
525110530Sjulian			stop = 0;
526110530Sjulian		}
527110530Sjulian	}
528110530Sjulian	if (stop)
529110530Sjulian		stopprofclock(p);
530110530Sjulian	PROC_UNLOCK(p);
5311541Srgrimes}
532108779Sphk
533126891Strhodes#if defined(__i386__) && __GNUC__ >= 2 && !defined(__INTEL_COMPILER)
534108779Sphk/*
535108779Sphk * Support for "--test-coverage --profile-arcs" in GCC.
536108779Sphk *
537108779Sphk * We need to call all the functions in the .ctor section, in order
538108779Sphk * to get all the counter-arrays strung into a list.
539108779Sphk *
540108779Sphk * XXX: the .ctors call __bb_init_func which is located in over in
541108779Sphk * XXX: i386/i386/support.s for historical reasons.  There is probably
542108779Sphk * XXX: no reason for that to be assembler anymore, but doing it right
543108779Sphk * XXX: in MI C code requires one to reverse-engineer the type-selection
544108779Sphk * XXX: inside GCC.  Have fun.
545108779Sphk *
546108779Sphk * XXX: Worrisome perspective: Calling the .ctors may make C++ in the
547108779Sphk * XXX: kernel feasible.  Don't.
548108779Sphk */
549108779Sphktypedef void (*ctor_t)(void);
550108779Sphkextern ctor_t _start_ctors, _stop_ctors;
551108779Sphk
552108779Sphkstatic void
553108779Sphktcov_init(void *foo __unused)
554108779Sphk{
555108779Sphk	ctor_t *p, q;
556108779Sphk
557108779Sphk	for (p = &_start_ctors; p < &_stop_ctors; p++) {
558108779Sphk		q = *p;
559108779Sphk		q();
560108779Sphk	}
561108779Sphk}
562108779Sphk
563108893SphkSYSINIT(tcov_init, SI_SUB_KPROF, SI_ORDER_SECOND, tcov_init, NULL)
564108779Sphk
565108779Sphk/*
566108779Sphk * GCC contains magic to recognize calls to for instance execve() and
567108779Sphk * puts in calls to this function to preserve the profile counters.
568108779Sphk * XXX: Put zinging punchline here.
569108779Sphk */
570108779Sphkvoid __bb_fork_func(void);
571108779Sphkvoid
572108779Sphk__bb_fork_func(void)
573108779Sphk{
574108779Sphk}
575108779Sphk
576108779Sphk#endif
577108779Sphk
578