xref: /csrg-svn/sys/kern/subr_prof.c (revision 59355)
154790Storek /*-
229100Smckusick  * Copyright (c) 1982, 1986 Regents of the University of California.
341966Smckusick  * All rights reserved.
423380Smckusick  *
541966Smckusick  * %sccs.include.redist.c%
641966Smckusick  *
7*59355Smckusick  *	@(#)subr_prof.c	7.18 (Berkeley) 04/27/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);
41*59355Smckusick 	p->kcountsize = p->textsize / HISTFRACTION;
42*59355Smckusick 	p->fromssize = p->textsize / HASHFRACTION;
4354790Storek 	p->tolimit = p->textsize * ARCDENSITY / 100;
4454790Storek 	if (p->tolimit < MINARCS)
4554790Storek 		p->tolimit = MINARCS;
4654790Storek 	else if (p->tolimit > MAXARCS)
4754790Storek 		p->tolimit = MAXARCS;
48*59355Smckusick 	p->tossize = p->tolimit * sizeof(struct tostruct);
49*59355Smckusick 	cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize,
50*59355Smckusick 	    M_GPROF, M_NOWAIT);
5154790Storek 	if (cp == 0) {
5254790Storek 		printf("No memory for profiling.\n");
537332Ssam 		return;
547332Ssam 	}
55*59355Smckusick 	bzero(cp, p->kcountsize + p->tossize + p->fromssize);
5654790Storek 	p->tos = (struct tostruct *)cp;
57*59355Smckusick 	cp += p->tossize;
58*59355Smckusick 	p->kcount = (u_short *)cp;
59*59355Smckusick 	cp += p->kcountsize;
6054790Storek 	p->froms = (u_short *)cp;
6154137Smckusick 	startprofclock(&proc0);
627332Ssam }
637332Ssam 
647332Ssam /*
65*59355Smckusick  * Return kernel profiling information.
66*59355Smckusick  */
67*59355Smckusick sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen, p)
68*59355Smckusick 	int *name;
69*59355Smckusick 	u_int namelen;
70*59355Smckusick 	void *oldp;
71*59355Smckusick 	size_t *oldlenp;
72*59355Smckusick 	void *newp;
73*59355Smckusick 	size_t newlen;
74*59355Smckusick {
75*59355Smckusick 	struct gmonparam *gp = &_gmonparam;
76*59355Smckusick 
77*59355Smckusick 	/* all sysctl names at this level are terminal */
78*59355Smckusick 	if (namelen != 1)
79*59355Smckusick 		return (ENOTDIR);		/* overloaded */
80*59355Smckusick 
81*59355Smckusick 	switch (name[0]) {
82*59355Smckusick 	case GPROF_STATE:
83*59355Smckusick 		return (sysctl_int(oldp, oldlenp, newp, newlen, &gp->state));
84*59355Smckusick 	case GPROF_COUNT:
85*59355Smckusick 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
86*59355Smckusick 		    gp->kcount, gp->kcountsize));
87*59355Smckusick 	case GPROF_FROMS:
88*59355Smckusick 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
89*59355Smckusick 		    gp->froms, gp->fromssize));
90*59355Smckusick 	case GPROF_TOS:
91*59355Smckusick 		return (sysctl_struct(oldp, oldlenp, newp, newlen,
92*59355Smckusick 		    gp->tos, gp->tossize));
93*59355Smckusick 	default:
94*59355Smckusick 		return (EOPNOTSUPP);
95*59355Smckusick 	}
96*59355Smckusick 	/* NOTREACHED */
97*59355Smckusick }
98*59355Smckusick #endif /* GPROF */
99*59355Smckusick 
100*59355Smckusick /*
10154790Storek  * Profiling system call.
10254790Storek  *
10354790Storek  * The scale factor is a fixed point number with 16 bits of fraction, so that
10454790Storek  * 1.0 is represented as 0x10000.  A scale factor of 0 turns off profiling.
1057332Ssam  */
10654929Storek struct profil_args {
10754929Storek 	caddr_t	buf;
10854929Storek 	u_int	bufsize;
10954929Storek 	u_int	offset;
11054929Storek 	u_int	scale;
11154929Storek };
11254790Storek /* ARGSUSED */
11354790Storek profil(p, uap, retval)
11454790Storek 	struct proc *p;
11554929Storek 	register struct profil_args *uap;
11654790Storek 	int *retval;
1177332Ssam {
11854790Storek 	register struct uprof *upp;
11954790Storek 	int s;
1207332Ssam 
12154790Storek 	if (uap->scale > (1 << 16))
12254790Storek 		return (EINVAL);
12354790Storek 	if (uap->scale == 0) {
12454790Storek 		stopprofclock(p);
12554790Storek 		return (0);
1267332Ssam 	}
12754790Storek 	upp = &p->p_stats->p_prof;
12854790Storek 	s = splstatclock(); /* block profile interrupts while changing state */
12954790Storek 	upp->pr_base = uap->buf;
13054790Storek 	upp->pr_size = uap->bufsize;
13154790Storek 	upp->pr_off = uap->offset;
13254790Storek 	upp->pr_scale = uap->scale;
13354790Storek 	startprofclock(p);
13454790Storek 	splx(s);
13554790Storek 	return (0);
13654790Storek }
13754790Storek 
13854790Storek /*
13954790Storek  * Scale is a fixed-point number with the binary point 16 bits
14054790Storek  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
14154790Storek  * intermediate result is at most 48 bits.
14254790Storek  */
14354790Storek #define	PC_TO_INDEX(pc, prof) \
14454790Storek 	((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
14554790Storek 	    (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
14654790Storek 
14754790Storek /*
14854790Storek  * Collect user-level profiling statistics; called on a profiling tick,
14954790Storek  * when a process is running in user-mode.  This routine may be called
15054790Storek  * from an interrupt context.  We try to update the user profiling buffers
15154790Storek  * cheaply with fuswintr() and suswintr().  If that fails, we revert to
15254790Storek  * an AST that will vector us to trap() with a context in which copyin
15354790Storek  * and copyout will work.  Trap will then call addupc_task().
15454790Storek  *
15554790Storek  * Note that we may (rarely) not get around to the AST soon enough, and
15654790Storek  * lose profile ticks when the next tick overwrites this one, but in this
15754790Storek  * case the system is overloaded and the profile is probably already
15854790Storek  * inaccurate.
15954790Storek  */
16054790Storek void
16154790Storek addupc_intr(p, pc, ticks)
16254790Storek 	register struct proc *p;
16354790Storek 	register u_long pc;
16454790Storek 	u_int ticks;
16554790Storek {
16654790Storek 	register struct uprof *prof;
16754790Storek 	register caddr_t addr;
16854790Storek 	register u_int i;
16954790Storek 	register int v;
17054790Storek 
17154790Storek 	if (ticks == 0)
17254790Storek 		return;
17354790Storek 	prof = &p->p_stats->p_prof;
17454790Storek 	if (pc < prof->pr_off ||
17554790Storek 	    (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
17654790Storek 		return;			/* out of range; ignore */
17754790Storek 
17854790Storek 	addr = prof->pr_base + i;
17954790Storek 	if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) {
18054790Storek 		prof->pr_addr = pc;
18154790Storek 		prof->pr_ticks = ticks;
18254790Storek 		need_proftick(p);
18310292Smckusick 	}
18454790Storek }
18510292Smckusick 
18654790Storek /*
18754790Storek  * Much like before, but we can afford to take faults here.  If the
18854790Storek  * update fails, we simply turn off profiling.
18954790Storek  */
19054790Storek void
19154790Storek addupc_task(p, pc, ticks)
19254790Storek 	register struct proc *p;
19354790Storek 	register u_long pc;
19454790Storek 	u_int ticks;
19554790Storek {
19654790Storek 	register struct uprof *prof;
19754790Storek 	register caddr_t addr;
19854790Storek 	register u_int i;
19954790Storek 	u_short v;
20054790Storek 
20154790Storek 	/* testing SPROFIL may be unnecessary, but is certainly safe */
20254790Storek 	if ((p->p_flag & SPROFIL) == 0 || ticks == 0)
20354790Storek 		return;
20454790Storek 
20554790Storek 	prof = &p->p_stats->p_prof;
20654790Storek 	if (pc < prof->pr_off ||
20754790Storek 	    (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
20854790Storek 		return;
20954790Storek 
21054790Storek 	addr = prof->pr_base + i;
21154790Storek 	if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
21254790Storek 		v += ticks;
21354790Storek 		if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
21454790Storek 			return;
2157332Ssam 	}
21654790Storek 	stopprofclock(p);
2177332Ssam }
218