154790Storek /*-
263176Sbostic * Copyright (c) 1982, 1986, 1993
363176Sbostic * The Regents of the University of California. All rights reserved.
423380Smckusick *
541966Smckusick * %sccs.include.redist.c%
641966Smckusick *
7*68313Scgd * @(#)subr_prof.c 8.4 (Berkeley) 02/14/95
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>
15*68313Scgd
16*68313Scgd #include <sys/mount.h>
17*68313Scgd #include <sys/syscallargs.h>
18*68313Scgd
1954790Storek #include <machine/cpu.h>
2054790Storek
217332Ssam #ifdef GPROF
2254790Storek #include <sys/malloc.h>
2354790Storek #include <sys/gmon.h>
247332Ssam
257332Ssam /*
267332Ssam * Froms is actually a bunch of unsigned shorts indexing tos
277332Ssam */
2854790Storek struct gmonparam _gmonparam = { GMON_PROF_OFF };
2954790Storek
3054790Storek extern char etext[];
317332Ssam
32*68313Scgd void
kmstartup()337332Ssam kmstartup()
347332Ssam {
3554790Storek char *cp;
3654790Storek struct gmonparam *p = &_gmonparam;
3710292Smckusick /*
3829946Skarels * Round lowpc and highpc to multiples of the density we're using
3929946Skarels * so the rest of the scaling (here and in gprof) stays in ints.
4010292Smckusick */
4154790Storek p->lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
4254790Storek p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
4354790Storek p->textsize = p->highpc - p->lowpc;
4454790Storek printf("Profiling kernel, textsize=%d [%x..%x]\n",
4554790Storek p->textsize, p->lowpc, p->highpc);
4659355Smckusick p->kcountsize = p->textsize / HISTFRACTION;
4759555Smckusick p->hashfraction = HASHFRACTION;
4859355Smckusick p->fromssize = p->textsize / HASHFRACTION;
4954790Storek p->tolimit = p->textsize * ARCDENSITY / 100;
5054790Storek if (p->tolimit < MINARCS)
5154790Storek p->tolimit = MINARCS;
5254790Storek else if (p->tolimit > MAXARCS)
5354790Storek p->tolimit = MAXARCS;
5459355Smckusick p->tossize = p->tolimit * sizeof(struct tostruct);
5559355Smckusick cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize,
5659355Smckusick M_GPROF, M_NOWAIT);
5754790Storek if (cp == 0) {
5854790Storek printf("No memory for profiling.\n");
597332Ssam return;
607332Ssam }
6159355Smckusick bzero(cp, p->kcountsize + p->tossize + p->fromssize);
6254790Storek p->tos = (struct tostruct *)cp;
6359355Smckusick cp += p->tossize;
6459355Smckusick p->kcount = (u_short *)cp;
6559355Smckusick cp += p->kcountsize;
6654790Storek p->froms = (u_short *)cp;
677332Ssam }
687332Ssam
697332Ssam /*
7059355Smckusick * Return kernel profiling information.
7159355Smckusick */
72*68313Scgd int
sysctl_doprof(name,namelen,oldp,oldlenp,newp,newlen,p)7359355Smckusick sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen, p)
7459355Smckusick int *name;
7559355Smckusick u_int namelen;
7659355Smckusick void *oldp;
7759355Smckusick size_t *oldlenp;
7859355Smckusick void *newp;
7959355Smckusick size_t newlen;
8059355Smckusick {
8159355Smckusick struct gmonparam *gp = &_gmonparam;
8259870Smckusick int error;
8359355Smckusick
8459355Smckusick /* all sysctl names at this level are terminal */
8559355Smckusick if (namelen != 1)
8659355Smckusick return (ENOTDIR); /* overloaded */
8759355Smckusick
8859355Smckusick switch (name[0]) {
8959355Smckusick case GPROF_STATE:
9059870Smckusick error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
9159870Smckusick if (error)
9259870Smckusick return (error);
9359870Smckusick if (gp->state == GMON_PROF_OFF)
9459870Smckusick stopprofclock(&proc0);
9559870Smckusick else
9659870Smckusick startprofclock(&proc0);
9759870Smckusick return (0);
9859355Smckusick case GPROF_COUNT:
9959355Smckusick return (sysctl_struct(oldp, oldlenp, newp, newlen,
10059355Smckusick gp->kcount, gp->kcountsize));
10159355Smckusick case GPROF_FROMS:
10259355Smckusick return (sysctl_struct(oldp, oldlenp, newp, newlen,
10359355Smckusick gp->froms, gp->fromssize));
10459355Smckusick case GPROF_TOS:
10559355Smckusick return (sysctl_struct(oldp, oldlenp, newp, newlen,
10659355Smckusick gp->tos, gp->tossize));
10759555Smckusick case GPROF_GMONPARAM:
10859555Smckusick return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
10959355Smckusick default:
11059355Smckusick return (EOPNOTSUPP);
11159355Smckusick }
11259355Smckusick /* NOTREACHED */
11359355Smckusick }
11459355Smckusick #endif /* GPROF */
11559355Smckusick
11659355Smckusick /*
11754790Storek * Profiling system call.
11854790Storek *
11954790Storek * The scale factor is a fixed point number with 16 bits of fraction, so that
12054790Storek * 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling.
1217332Ssam */
12254790Storek /* ARGSUSED */
123*68313Scgd int
profil(p,uap,retval)12454790Storek profil(p, uap, retval)
12554790Storek struct proc *p;
126*68313Scgd register struct profil_args /* {
127*68313Scgd syscallarg(caddr_t) samples;
128*68313Scgd syscallarg(u_int) size;
129*68313Scgd syscallarg(u_int) offset;
130*68313Scgd syscallarg(u_int) scale;
131*68313Scgd } */ *uap;
132*68313Scgd register_t *retval;
1337332Ssam {
13454790Storek register struct uprof *upp;
13554790Storek int s;
1367332Ssam
137*68313Scgd if (SCARG(uap, scale) > (1 << 16))
13854790Storek return (EINVAL);
139*68313Scgd if (SCARG(uap, scale) == 0) {
14054790Storek stopprofclock(p);
14154790Storek return (0);
1427332Ssam }
14354790Storek upp = &p->p_stats->p_prof;
14464529Sbostic
14564529Sbostic /* Block profile interrupts while changing state. */
14664529Sbostic s = splstatclock();
147*68313Scgd upp->pr_off = SCARG(uap, offset);
148*68313Scgd upp->pr_scale = SCARG(uap, scale);
149*68313Scgd upp->pr_base = SCARG(uap, samples);
150*68313Scgd upp->pr_size = SCARG(uap, size);
15154790Storek startprofclock(p);
15254790Storek splx(s);
15364529Sbostic
15454790Storek return (0);
15554790Storek }
15654790Storek
15754790Storek /*
15854790Storek * Scale is a fixed-point number with the binary point 16 bits
15954790Storek * into the value, and is <= 1.0. pc is at most 32 bits, so the
16054790Storek * intermediate result is at most 48 bits.
16154790Storek */
16254790Storek #define PC_TO_INDEX(pc, prof) \
16354790Storek ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
16454790Storek (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
16554790Storek
16654790Storek /*
16754790Storek * Collect user-level profiling statistics; called on a profiling tick,
16854790Storek * when a process is running in user-mode. This routine may be called
16954790Storek * from an interrupt context. We try to update the user profiling buffers
17054790Storek * cheaply with fuswintr() and suswintr(). If that fails, we revert to
17154790Storek * an AST that will vector us to trap() with a context in which copyin
17254790Storek * and copyout will work. Trap will then call addupc_task().
17354790Storek *
17454790Storek * Note that we may (rarely) not get around to the AST soon enough, and
17554790Storek * lose profile ticks when the next tick overwrites this one, but in this
17654790Storek * case the system is overloaded and the profile is probably already
17754790Storek * inaccurate.
17854790Storek */
17954790Storek void
addupc_intr(p,pc,ticks)18054790Storek addupc_intr(p, pc, ticks)
18154790Storek register struct proc *p;
18254790Storek register u_long pc;
18354790Storek u_int ticks;
18454790Storek {
18554790Storek register struct uprof *prof;
18654790Storek register caddr_t addr;
18754790Storek register u_int i;
18854790Storek register int v;
18954790Storek
19054790Storek if (ticks == 0)
19154790Storek return;
19254790Storek prof = &p->p_stats->p_prof;
19354790Storek if (pc < prof->pr_off ||
19454790Storek (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
19554790Storek return; /* out of range; ignore */
19654790Storek
19754790Storek addr = prof->pr_base + i;
19854790Storek if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + ticks) == -1) {
19954790Storek prof->pr_addr = pc;
20054790Storek prof->pr_ticks = ticks;
20154790Storek need_proftick(p);
20210292Smckusick }
20354790Storek }
20410292Smckusick
20554790Storek /*
20654790Storek * Much like before, but we can afford to take faults here. If the
20754790Storek * update fails, we simply turn off profiling.
20854790Storek */
20954790Storek void
addupc_task(p,pc,ticks)21054790Storek addupc_task(p, pc, ticks)
21154790Storek register struct proc *p;
21254790Storek register u_long pc;
21354790Storek u_int ticks;
21454790Storek {
21554790Storek register struct uprof *prof;
21654790Storek register caddr_t addr;
21754790Storek register u_int i;
21854790Storek u_short v;
21954790Storek
22064575Sbostic /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
22164575Sbostic if ((p->p_flag & P_PROFIL) == 0 || ticks == 0)
22254790Storek return;
22354790Storek
22454790Storek prof = &p->p_stats->p_prof;
22554790Storek if (pc < prof->pr_off ||
22654790Storek (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
22754790Storek return;
22854790Storek
22954790Storek addr = prof->pr_base + i;
23054790Storek if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
23154790Storek v += ticks;
23254790Storek if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
23354790Storek return;
2347332Ssam }
23554790Storek stopprofclock(p);
2367332Ssam }
237