[BACK]Return to subr_prof.c CVS log [TXT][DIR] Up to [local] / sys / kern

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