Annotation of sys/kern/subr_prof.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: subr_prof.c,v 1.17 2007/03/15 10:22:30 art Exp $ */
! 2: /* $NetBSD: subr_prof.c,v 1.12 1996/04/22 01:38:50 christos Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1982, 1986, 1993
! 6: * The Regents of the University of California. All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. Neither the name of the University nor the names of its contributors
! 17: * may be used to endorse or promote products derived from this software
! 18: * without specific prior written permission.
! 19: *
! 20: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 21: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 22: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 23: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 24: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 25: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 26: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 27: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 28: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 29: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 30: * SUCH DAMAGE.
! 31: *
! 32: * @(#)subr_prof.c 8.3 (Berkeley) 9/23/93
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/kernel.h>
! 38: #include <sys/proc.h>
! 39: #include <sys/user.h>
! 40: #include <sys/mount.h>
! 41: #include <sys/syscallargs.h>
! 42:
! 43: #include <machine/cpu.h>
! 44:
! 45: #ifdef GPROF
! 46: #include <sys/malloc.h>
! 47: #include <sys/gmon.h>
! 48: #include <uvm/uvm_extern.h>
! 49:
! 50: /*
! 51: * Froms is actually a bunch of unsigned shorts indexing tos
! 52: */
! 53: struct gmonparam _gmonparam = { GMON_PROF_OFF };
! 54:
! 55: extern char etext[];
! 56:
! 57:
! 58: void
! 59: kmstartup(void)
! 60: {
! 61: char *cp;
! 62: struct gmonparam *p = &_gmonparam;
! 63: int size;
! 64:
! 65: /*
! 66: * Round lowpc and highpc to multiples of the density we're using
! 67: * so the rest of the scaling (here and in gprof) stays in ints.
! 68: */
! 69: p->lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
! 70: p->highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
! 71: p->textsize = p->highpc - p->lowpc;
! 72: printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
! 73: p->textsize, p->lowpc, p->highpc);
! 74: p->kcountsize = p->textsize / HISTFRACTION;
! 75: p->hashfraction = HASHFRACTION;
! 76: p->fromssize = p->textsize / HASHFRACTION;
! 77: p->tolimit = p->textsize * ARCDENSITY / 100;
! 78: if (p->tolimit < MINARCS)
! 79: p->tolimit = MINARCS;
! 80: else if (p->tolimit > MAXARCS)
! 81: p->tolimit = MAXARCS;
! 82: p->tossize = p->tolimit * sizeof(struct tostruct);
! 83: size = p->kcountsize + p->fromssize + p->tossize;
! 84: cp = (char *)uvm_km_zalloc(kernel_map, round_page(size));
! 85: if (cp == 0) {
! 86: printf("No memory for profiling.\n");
! 87: return;
! 88: }
! 89: p->tos = (struct tostruct *)cp;
! 90: cp += p->tossize;
! 91: p->kcount = (u_short *)cp;
! 92: cp += p->kcountsize;
! 93: p->froms = (u_short *)cp;
! 94: }
! 95:
! 96: /*
! 97: * Return kernel profiling information.
! 98: */
! 99: int
! 100: sysctl_doprof(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
! 101: size_t newlen)
! 102: {
! 103: struct gmonparam *gp = &_gmonparam;
! 104: int error;
! 105:
! 106: /* all sysctl names at this level are terminal */
! 107: if (namelen != 1)
! 108: return (ENOTDIR); /* overloaded */
! 109:
! 110: switch (name[0]) {
! 111: case GPROF_STATE:
! 112: error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
! 113: if (error)
! 114: return (error);
! 115: if (gp->state == GMON_PROF_OFF)
! 116: stopprofclock(&proc0);
! 117: else
! 118: startprofclock(&proc0);
! 119: return (0);
! 120: case GPROF_COUNT:
! 121: return (sysctl_struct(oldp, oldlenp, newp, newlen,
! 122: gp->kcount, gp->kcountsize));
! 123: case GPROF_FROMS:
! 124: return (sysctl_struct(oldp, oldlenp, newp, newlen,
! 125: gp->froms, gp->fromssize));
! 126: case GPROF_TOS:
! 127: return (sysctl_struct(oldp, oldlenp, newp, newlen,
! 128: gp->tos, gp->tossize));
! 129: case GPROF_GMONPARAM:
! 130: return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
! 131: default:
! 132: return (EOPNOTSUPP);
! 133: }
! 134: /* NOTREACHED */
! 135: }
! 136: #endif /* GPROF */
! 137:
! 138: /*
! 139: * Profiling system call.
! 140: *
! 141: * The scale factor is a fixed point number with 16 bits of fraction, so that
! 142: * 1.0 is represented as 0x10000. A scale factor of 0 turns off profiling.
! 143: */
! 144: /* ARGSUSED */
! 145: int
! 146: sys_profil(struct proc *p, void *v, register_t *retval)
! 147: {
! 148: struct sys_profil_args /* {
! 149: syscallarg(caddr_t) samples;
! 150: syscallarg(size_t) size;
! 151: syscallarg(u_long) offset;
! 152: syscallarg(u_int) scale;
! 153: } */ *uap = v;
! 154: struct uprof *upp;
! 155: int s;
! 156:
! 157: if (SCARG(uap, scale) > (1 << 16))
! 158: return (EINVAL);
! 159: if (SCARG(uap, scale) == 0) {
! 160: stopprofclock(p);
! 161: return (0);
! 162: }
! 163: upp = &p->p_stats->p_prof;
! 164:
! 165: /* Block profile interrupts while changing state. */
! 166: s = splstatclock();
! 167: upp->pr_off = SCARG(uap, offset);
! 168: upp->pr_scale = SCARG(uap, scale);
! 169: upp->pr_base = (caddr_t)SCARG(uap, samples);
! 170: upp->pr_size = SCARG(uap, size);
! 171: startprofclock(p);
! 172: splx(s);
! 173:
! 174: return (0);
! 175: }
! 176:
! 177: /*
! 178: * Scale is a fixed-point number with the binary point 16 bits
! 179: * into the value, and is <= 1.0. pc is at most 32 bits, so the
! 180: * intermediate result is at most 48 bits.
! 181: */
! 182: #define PC_TO_INDEX(pc, prof) \
! 183: ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
! 184: (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
! 185:
! 186: /*
! 187: * Collect user-level profiling statistics; called on a profiling tick,
! 188: * when a process is running in user-mode. This routine may be called
! 189: * from an interrupt context. Schedule an AST that will vector us to
! 190: * trap() with a context in which copyin and copyout will work.
! 191: * Trap will then call addupc_task().
! 192: */
! 193: void
! 194: addupc_intr(struct proc *p, u_long pc)
! 195: {
! 196: struct uprof *prof;
! 197:
! 198: prof = &p->p_stats->p_prof;
! 199: if (pc < prof->pr_off || PC_TO_INDEX(pc, prof) >= prof->pr_size)
! 200: return; /* out of range; ignore */
! 201:
! 202: prof->pr_addr = pc;
! 203: prof->pr_ticks++;
! 204: atomic_setbits_int(&p->p_flag, P_OWEUPC);
! 205: need_proftick(p);
! 206: }
! 207:
! 208:
! 209: /*
! 210: * Much like before, but we can afford to take faults here. If the
! 211: * update fails, we simply turn off profiling.
! 212: */
! 213: void
! 214: addupc_task(struct proc *p, u_long pc, u_int nticks)
! 215: {
! 216: struct uprof *prof;
! 217: caddr_t addr;
! 218: u_int i;
! 219: u_short v;
! 220:
! 221: /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
! 222: if ((p->p_flag & P_PROFIL) == 0 || nticks == 0)
! 223: return;
! 224:
! 225: prof = &p->p_stats->p_prof;
! 226: if (pc < prof->pr_off ||
! 227: (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
! 228: return;
! 229:
! 230: addr = prof->pr_base + i;
! 231: if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
! 232: v += nticks;
! 233: if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
! 234: return;
! 235: }
! 236: stopprofclock(p);
! 237: }
CVSweb