xref: /csrg-svn/sys/kern/subr_prof.c (revision 59555)
154790Storek /*-
229100Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
341966Smckusick  * All rights reserved.
423380Smckusick  *
541966Smckusick  * %sccs.include.redist.c%
641966Smckusick  *
7*59555Smckusick  *	@(#)subr_prof.c	7.19 (Berkeley) 04/29/93
823380Smckusick  */
97332Ssam 
1054790Storek #include <sys/param.h>
1154790Storek #include <sys/systm.h>
1254790Storek #include <sys/kernel.h>
1354790Storek #include <sys/proc.h>
1454790Storek #include <sys/user.h>
1554790Storek #include <machine/cpu.h>
1654790Storek 
177332Ssam #ifdef GPROF
1854790Storek #include <sys/malloc.h>
1954790Storek #include <sys/gmon.h>
207332Ssam 
217332Ssam /*
227332Ssam  * Froms is actually a bunch of unsigned shorts indexing tos
237332Ssam  */
2454790Storek struct gmonparam _gmonparam = { GMON_PROF_OFF };
2554790Storek 
2654790Storek extern char etext[];
277332Ssam 
287332Ssam kmstartup()
297332Ssam {
3054790Storek 	char *cp;
3154790Storek 	struct gmonparam *p = &_gmonparam;
3210292Smckusick 	/*
3329946Skarels 	 * Round lowpc and highpc to multiples of the density we're using
3429946Skarels 	 * so the rest of the scaling (here and in gprof) stays in ints.
3510292Smckusick 	 */
3654790Storek 	p->lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
3754790Storek 	p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
3854790Storek 	p->textsize = p->highpc - p->lowpc;
3954790Storek 	printf("Profiling kernel, textsize=%d [%x..%x]\n",
4054790Storek 	       p->textsize, p->lowpc, p->highpc);
4159355Smckusick 	p->kcountsize = p->textsize / HISTFRACTION;
42*59555Smckusick 	p->hashfraction = HASHFRACTION;
4359355Smckusick 	p->fromssize = p->textsize / HASHFRACTION;
4454790Storek 	p->tolimit = p->textsize * ARCDENSITY / 100;
4554790Storek 	if (p->tolimit < MINARCS)
4654790Storek 		p->tolimit = MINARCS;
4754790Storek 	else if (p->tolimit > MAXARCS)
4854790Storek 		p->tolimit = MAXARCS;
4959355Smckusick 	p->tossize = p->tolimit * sizeof(struct tostruct);
5059355Smckusick 	cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize,
5159355Smckusick 	    M_GPROF, M_NOWAIT);
5254790Storek 	if (cp == 0) {
5354790Storek 		printf("No memory for profiling.\n");
547332Ssam 		return;
557332Ssam 	}
5659355Smckusick 	bzero(cp, p->kcountsize + p->tossize + p->fromssize);
5754790Storek 	p->tos = (struct tostruct *)cp;
5859355Smckusick 	cp += p->tossize;
5959355Smckusick 	p->kcount = (u_short *)cp;
6059355Smckusick 	cp += p->kcountsize;
6154790Storek 	p->froms = (u_short *)cp;
6254137Smckusick 	startprofclock(&proc0);
637332Ssam }
647332Ssam 
657332Ssam /*
6659355Smckusick  * Return kernel profiling information.
6759355Smckusick  */
6859355Smckusick sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen, p)
6959355Smckusick 	int *name;
7059355Smckusick 	u_int namelen;
7159355Smckusick 	void *oldp;
7259355Smckusick 	size_t *oldlenp;
7359355Smckusick 	void *newp;
7459355Smckusick 	size_t newlen;
7559355Smckusick {
7659355Smckusick 	struct gmonparam *gp = &_gmonparam;
7759355Smckusick 
7859355Smckusick 	/* all sysctl names at this level are terminal */
7959355Smckusick 	if (namelen != 1)
8059355Smckusick 		return (ENOTDIR);		/* overloaded */
8159355Smckusick 
8259355Smckusick 	switch (name[0]) {
8359355Smckusick 	case GPROF_STATE:
8459355Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &gp->state));
8559355Smckusick 	case GPROF_COUNT:
8659355Smckusick 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
8759355Smckusick 		    gp->kcount, gp->kcountsize));
8859355Smckusick 	case GPROF_FROMS:
8959355Smckusick 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
9059355Smckusick 		    gp->froms, gp->fromssize));
9159355Smckusick 	case GPROF_TOS:
9259355Smckusick 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
9359355Smckusick 		    gp->tos, gp->tossize));
94*59555Smckusick 	case GPROF_GMONPARAM:
95*59555Smckusick 		return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
9659355Smckusick 	default:
9759355Smckusick 		return (EOPNOTSUPP);
9859355Smckusick 	}
9959355Smckusick 	/* NOTREACHED */
10059355Smckusick }
10159355Smckusick #endif /* GPROF */
10259355Smckusick 
10359355Smckusick /*
10454790Storek  * Profiling system call.
10554790Storek  *
10654790Storek  * The scale factor is a fixed point number with 16 bits of fraction, so that
10754790Storek  * 1.0 is represented as 0x10000.  A scale factor of 0 turns off profiling.
1087332Ssam  */
10954929Storek struct profil_args {
11054929Storek 	caddr_t	buf;
11154929Storek 	u_int	bufsize;
11254929Storek 	u_int	offset;
11354929Storek 	u_int	scale;
11454929Storek };
11554790Storek /* ARGSUSED */
11654790Storek profil(p, uap, retval)
11754790Storek 	struct proc *p;
11854929Storek 	register struct profil_args *uap;
11954790Storek 	int *retval;
1207332Ssam {
12154790Storek 	register struct uprof *upp;
12254790Storek 	int s;
1237332Ssam 
12454790Storek 	if (uap->scale > (1 << 16))
12554790Storek 		return (EINVAL);
12654790Storek 	if (uap->scale == 0) {
12754790Storek 		stopprofclock(p);
12854790Storek 		return (0);
1297332Ssam 	}
13054790Storek 	upp = &p->p_stats->p_prof;
13154790Storek 	s = splstatclock(); /* block profile interrupts while changing state */
13254790Storek 	upp->pr_base = uap->buf;
13354790Storek 	upp->pr_size = uap->bufsize;
13454790Storek 	upp->pr_off = uap->offset;
13554790Storek 	upp->pr_scale = uap->scale;
13654790Storek 	startprofclock(p);
13754790Storek 	splx(s);
13854790Storek 	return (0);
13954790Storek }
14054790Storek 
14154790Storek /*
14254790Storek  * Scale is a fixed-point number with the binary point 16 bits
14354790Storek  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
14454790Storek  * intermediate result is at most 48 bits.
14554790Storek  */
14654790Storek #define	PC_TO_INDEX(pc, prof) \
14754790Storek 	((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
14854790Storek 	    (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
14954790Storek 
15054790Storek /*
15154790Storek  * Collect user-level profiling statistics; called on a profiling tick,
15254790Storek  * when a process is running in user-mode.  This routine may be called
15354790Storek  * from an interrupt context.  We try to update the user profiling buffers
15454790Storek  * cheaply with fuswintr() and suswintr().  If that fails, we revert to
15554790Storek  * an AST that will vector us to trap() with a context in which copyin
15654790Storek  * and copyout will work.  Trap will then call addupc_task().
15754790Storek  *
15854790Storek  * Note that we may (rarely) not get around to the AST soon enough, and
15954790Storek  * lose profile ticks when the next tick overwrites this one, but in this
16054790Storek  * case the system is overloaded and the profile is probably already
16154790Storek  * inaccurate.
16254790Storek  */
16354790Storek void
16454790Storek addupc_intr(p, pc, ticks)
16554790Storek 	register struct proc *p;
16654790Storek 	register u_long pc;
16754790Storek 	u_int ticks;
16854790Storek {
16954790Storek 	register struct uprof *prof;
17054790Storek 	register caddr_t addr;
17154790Storek 	register u_int i;
17254790Storek 	register int v;
17354790Storek 
17454790Storek 	if (ticks == 0)
17554790Storek 		return;
17654790Storek 	prof = &p->p_stats->p_prof;
17754790Storek 	if (pc < prof->pr_off ||
17854790Storek 	    (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
17954790Storek 		return;			/* out of range; ignore */
18054790Storek 
18154790Storek 	addr = prof->pr_base + i;
18254790Storek 	if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) {
18354790Storek 		prof->pr_addr = pc;
18454790Storek 		prof->pr_ticks = ticks;
18554790Storek 		need_proftick(p);
18610292Smckusick 	}
18754790Storek }
18810292Smckusick 
18954790Storek /*
19054790Storek  * Much like before, but we can afford to take faults here.  If the
19154790Storek  * update fails, we simply turn off profiling.
19254790Storek  */
19354790Storek void
19454790Storek addupc_task(p, pc, ticks)
19554790Storek 	register struct proc *p;
19654790Storek 	register u_long pc;
19754790Storek 	u_int ticks;
19854790Storek {
19954790Storek 	register struct uprof *prof;
20054790Storek 	register caddr_t addr;
20154790Storek 	register u_int i;
20254790Storek 	u_short v;
20354790Storek 
20454790Storek 	/* testing SPROFIL may be unnecessary, but is certainly safe */
20554790Storek 	if ((p->p_flag & SPROFIL) == 0 || ticks == 0)
20654790Storek 		return;
20754790Storek 
20854790Storek 	prof = &p->p_stats->p_prof;
20954790Storek 	if (pc < prof->pr_off ||
21054790Storek 	    (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
21154790Storek 		return;
21254790Storek 
21354790Storek 	addr = prof->pr_base + i;
21454790Storek 	if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
21554790Storek 		v += ticks;
21654790Storek 		if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
21754790Storek 			return;
2187332Ssam 	}
21954790Storek 	stopprofclock(p);
2207332Ssam }
221