Annotation of kernel/bsd/kern/subr_prof.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
        !            26: /*-
        !            27:  * Copyright (c) 1982, 1986, 1993
        !            28:  *     The Regents of the University of California.  All rights reserved.
        !            29:  *
        !            30:  * Redistribution and use in source and binary forms, with or without
        !            31:  * modification, are permitted provided that the following conditions
        !            32:  * are met:
        !            33:  * 1. Redistributions of source code must retain the above copyright
        !            34:  *    notice, this list of conditions and the following disclaimer.
        !            35:  * 2. Redistributions in binary form must reproduce the above copyright
        !            36:  *    notice, this list of conditions and the following disclaimer in the
        !            37:  *    documentation and/or other materials provided with the distribution.
        !            38:  * 3. All advertising materials mentioning features or use of this software
        !            39:  *    must display the following acknowledgement:
        !            40:  *     This product includes software developed by the University of
        !            41:  *     California, Berkeley and its contributors.
        !            42:  * 4. Neither the name of the University nor the names of its contributors
        !            43:  *    may be used to endorse or promote products derived from this software
        !            44:  *    without specific prior written permission.
        !            45:  *
        !            46:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            47:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            48:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            49:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            50:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            51:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            52:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            53:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            54:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            55:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            56:  * SUCH DAMAGE.
        !            57:  *
        !            58:  *     @(#)subr_prof.c 8.3 (Berkeley) 9/23/93
        !            59:  */
        !            60: 
        !            61: #include <sys/param.h>
        !            62: #include <sys/systm.h>
        !            63: #include <sys/kernel.h>
        !            64: #include <sys/proc.h>
        !            65: #include <sys/user.h>
        !            66: #include <machine/spl.h>
        !            67: 
        !            68: #include <sys/mount.h>
        !            69: 
        !            70: #include <machine/cpu.h>
        !            71: 
        !            72: #ifdef GPROF
        !            73: #include <sys/malloc.h>
        !            74: #include <sys/gmon.h>
        !            75: #include <kern/mach_header.h>
        !            76: #include <machine/profile.h>
        !            77: 
        !            78: /*
        !            79:  * Froms is actually a bunch of unsigned shorts indexing tos
        !            80:  */
        !            81: struct gmonparam _gmonparam = { GMON_PROF_OFF };
        !            82: 
        !            83: kmstartup()
        !            84: {
        !            85:        char *cp;
        !            86:        u_long  fromssize, tossize;
        !            87:        struct segment_command          *sgp;
        !            88:        struct gmonparam *p = &_gmonparam;
        !            89:        
        !            90:        sgp = getsegbyname("__TEXT");
        !            91:        p->lowpc = (u_long)sgp->vmaddr;
        !            92:        p->highpc = (u_long)(sgp->vmaddr + sgp->vmsize);
        !            93:        
        !            94:        /*
        !            95:         * Round lowpc and highpc to multiples of the density we're using
        !            96:         * so the rest of the scaling (here and in gprof) stays in ints.
        !            97:         */
        !            98:        p->lowpc = ROUNDDOWN(p->lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
        !            99:        p->highpc = ROUNDUP(p->highpc, HISTFRACTION * sizeof(HISTCOUNTER));
        !           100:        p->textsize = p->highpc - p->lowpc;
        !           101:        printf("Profiling kernel, textsize=%d [0x%08x..0x%08x]\n",
        !           102:               p->textsize, p->lowpc, p->highpc);
        !           103:        p->kcountsize = p->textsize / HISTFRACTION;
        !           104:        p->hashfraction = HASHFRACTION;
        !           105:        p->fromssize = p->textsize / HASHFRACTION;
        !           106:        p->tolimit = p->textsize * ARCDENSITY / 100;
        !           107:        if (p->tolimit < MINARCS)
        !           108:                p->tolimit = MINARCS;
        !           109:        else if (p->tolimit > MAXARCS)
        !           110:                p->tolimit = MAXARCS;
        !           111:        p->tossize = p->tolimit * sizeof(struct tostruct);
        !           112:        /* Why not use MALLOC with M_GPROF ? */
        !           113:        cp = (char *)kalloc(p->kcountsize + p->fromssize + p->tossize);
        !           114:        if (cp == 0) {
        !           115:                printf("No memory for profiling.\n");
        !           116:                return;
        !           117:        }
        !           118:        bzero(cp, p->kcountsize + p->tossize + p->fromssize);
        !           119:        p->tos = (struct tostruct *)cp;
        !           120:        cp += p->tossize;
        !           121:        p->kcount = (u_short *)cp;
        !           122:        cp += p->kcountsize;
        !           123:        p->froms = (u_short *)cp;
        !           124: }
        !           125: 
        !           126: /*
        !           127:  * Return kernel profiling information.
        !           128:  */
        !           129: sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen, p)
        !           130:        int *name;
        !           131:        u_int namelen;
        !           132:        void *oldp;
        !           133:        size_t *oldlenp;
        !           134:        void *newp;
        !           135:        size_t newlen;
        !           136: {
        !           137:        struct gmonparam *gp = &_gmonparam;
        !           138:        int error;
        !           139: 
        !           140:        /* all sysctl names at this level are terminal */
        !           141:        if (namelen != 1)
        !           142:                return (ENOTDIR);               /* overloaded */
        !           143: 
        !           144:        switch (name[0]) {
        !           145:        case GPROF_STATE:
        !           146:                error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
        !           147:                if (error)
        !           148:                        return (error);
        !           149:                if (gp->state == GMON_PROF_OFF)
        !           150:                        stopprofclock(kernproc);
        !           151:                else
        !           152:                        startprofclock(kernproc);
        !           153:                return (0);
        !           154:        case GPROF_COUNT:
        !           155:                return (sysctl_struct(oldp, oldlenp, newp, newlen,
        !           156:                    gp->kcount, gp->kcountsize));
        !           157:        case GPROF_FROMS:
        !           158:                return (sysctl_struct(oldp, oldlenp, newp, newlen,
        !           159:                    gp->froms, gp->fromssize));
        !           160:        case GPROF_TOS:
        !           161:                return (sysctl_struct(oldp, oldlenp, newp, newlen,
        !           162:                    gp->tos, gp->tossize));
        !           163:        case GPROF_GMONPARAM:
        !           164:                return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
        !           165:        default:
        !           166:                return (EOPNOTSUPP);
        !           167:        }
        !           168:        /* NOTREACHED */
        !           169: }
        !           170: 
        !           171: 
        !           172: /*
        !           173:  * mcount() called with interrupts disabled.
        !           174:  */
        !           175: void
        !           176: mcount(
        !           177:     register u_long frompc,
        !           178:     register u_long selfpc
        !           179: )
        !           180: {
        !           181:     unsigned short *frompcindex;
        !           182:        register struct tostruct *top, *prevtop;
        !           183:        struct gmonparam *p = &_gmonparam;
        !           184:        register long toindex;
        !           185:        MCOUNT_INIT;
        !           186: 
        !           187:     /*
        !           188:      * check that we are profiling
        !           189:      * and that we aren't recursively invoked.
        !           190:      */
        !           191:     if (p->state != GMON_PROF_ON)
        !           192:         return;
        !           193: 
        !           194:        MCOUNT_ENTER;
        !           195: 
        !           196:        /*
        !           197:         *      check that frompcindex is a reasonable pc value.
        !           198:         *      for example:    signal catchers get called from the stack,
        !           199:         *                      not from text space.  too bad.
        !           200:         */
        !           201:        frompc -= p->lowpc;
        !           202:        if (frompc > p->textsize)
        !           203:                goto done;
        !           204: 
        !           205:        frompcindex = &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))];
        !           206:        toindex = *frompcindex;
        !           207:        if (toindex == 0) {
        !           208:                /*
        !           209:                 *      first time traversing this arc
        !           210:                 */
        !           211:                toindex = ++p->tos[0].link;
        !           212:                if (toindex >= p->tolimit) {
        !           213:             /* halt further profiling */
        !           214:                        goto overflow;
        !           215:                }
        !           216:                *frompcindex = toindex;
        !           217:                top = &p->tos[toindex];
        !           218:                top->selfpc = selfpc;
        !           219:                top->count = 1;
        !           220:                top->link = 0;
        !           221:                goto done;
        !           222:        }
        !           223:        top = &p->tos[toindex];
        !           224:        if (top->selfpc == selfpc) {
        !           225:                /*
        !           226:                 *      arc at front of chain; usual case.
        !           227:                 */
        !           228:                top->count++;
        !           229:                goto done;
        !           230:        }
        !           231:        /*
        !           232:         *      have to go looking down chain for it.
        !           233:         *      top points to what we are looking at,
        !           234:         *      prevtop points to previous top.
        !           235:         *      we know it is not at the head of the chain.
        !           236:         */
        !           237:        for (; /* goto done */; ) {
        !           238:                if (top->link == 0) {
        !           239:                        /*
        !           240:                         *      top is end of the chain and none of the chain
        !           241:                         *      had top->selfpc == selfpc.
        !           242:                         *      so we allocate a new tostruct
        !           243:                         *      and link it to the head of the chain.
        !           244:                         */
        !           245:                        toindex = ++p->tos[0].link;
        !           246:                        if (toindex >= p->tolimit) {
        !           247:                                goto overflow;
        !           248:                        }
        !           249:                        top = &p->tos[toindex];
        !           250:                        top->selfpc = selfpc;
        !           251:                        top->count = 1;
        !           252:                        top->link = *frompcindex;
        !           253:                        *frompcindex = toindex;
        !           254:                        goto done;
        !           255:                }
        !           256:                /*
        !           257:                 *      otherwise, check the next arc on the chain.
        !           258:                 */
        !           259:                prevtop = top;
        !           260:                top = &p->tos[top->link];
        !           261:                if (top->selfpc == selfpc) {
        !           262:                        /*
        !           263:                         *      there it is.
        !           264:                         *      increment its count
        !           265:                         *      move it to the head of the chain.
        !           266:                         */
        !           267:                        top->count++;
        !           268:                        toindex = prevtop->link;
        !           269:                        prevtop->link = top->link;
        !           270:                        top->link = *frompcindex;
        !           271:                        *frompcindex = toindex;
        !           272:                        goto done;
        !           273:                }
        !           274: 
        !           275:        }
        !           276: done:
        !           277:        MCOUNT_EXIT;
        !           278:        return;
        !           279: 
        !           280: overflow:
        !           281:     p->state = GMON_PROF_ERROR;
        !           282:        MCOUNT_EXIT;
        !           283:        printf("mcount: tos overflow\n");
        !           284:        return;
        !           285: }
        !           286: 
        !           287: #endif /* GPROF */
        !           288: 
        !           289: #if NCPUS > 1
        !           290: #define PROFILE_LOCK(x)                simple_lock(x)
        !           291: #define PROFILE_UNLOCK(x)      simple_unlock(x)
        !           292: #else
        !           293: #define PROFILE_LOCK(x)
        !           294: #define PROFILE_UNLOCK(x)
        !           295: #endif
        !           296: 
        !           297: struct profil_args {
        !           298:        short   *bufbase;
        !           299:        u_int bufsize;
        !           300:        u_int pcoffset;
        !           301:        u_int pcscale;
        !           302: };
        !           303: int
        !           304: profil(p, uap, retval)
        !           305:        struct proc *p;
        !           306:        register struct profil_args *uap;
        !           307:        register_t *retval;
        !           308: {
        !           309:        register struct uprof *upp = &p->p_stats->p_prof;
        !           310:        struct uprof *upc, *nupc;
        !           311:        int s;
        !           312: 
        !           313:        if (uap->pcscale > (1 << 16))
        !           314:                return (EINVAL);
        !           315:        if (uap->pcscale == 0) {
        !           316:                stopprofclock(p);
        !           317:                return (0);
        !           318:        }
        !           319: 
        !           320:        /* Block profile interrupts while changing state. */
        !           321:        s = splstatclock();
        !           322:        PROFILE_LOCK(&upp->pr_lock);
        !           323:        upp->pr_base = (caddr_t)uap->bufbase;
        !           324:        upp->pr_size = uap->bufsize;
        !           325:        upp->pr_off = uap->pcoffset;
        !           326:        upp->pr_scale = uap->pcscale;
        !           327: 
        !           328:        /* remove buffers previously allocated with add_profil() */
        !           329:        for (upc = upp->pr_next; upc; upc = nupc) {
        !           330:                nupc = upc->pr_next;
        !           331:                kfree(upc, sizeof (struct uprof));
        !           332:        }
        !           333: 
        !           334:        upp->pr_next = 0;
        !           335:        PROFILE_UNLOCK(&upp->pr_lock);
        !           336:        startprofclock(p);
        !           337:        splx(s);
        !           338:        return(0);
        !           339: }
        !           340: 
        !           341: struct add_profile_args {
        !           342:        short   *bufbase;
        !           343:        u_int bufsize;
        !           344:        u_int pcoffset;
        !           345:        u_int pcscale;
        !           346: };
        !           347: int
        !           348: add_profil(p, uap, retval)
        !           349:        struct proc *p;
        !           350:        register struct add_profile_args *uap;
        !           351:        register_t *retval;
        !           352: {
        !           353:        struct uprof *upp = &p->p_stats->p_prof, *upc;
        !           354:        int s;
        !           355: 
        !           356:        if (upp->pr_scale == 0)
        !           357:                return (0);
        !           358:        s = splstatclock();
        !           359:        upc = (struct uprof *) kalloc(sizeof (struct uprof));
        !           360:        upc->pr_base = (caddr_t)uap->bufbase;
        !           361:        upc->pr_size = uap->bufsize;
        !           362:        upc->pr_off = uap->pcoffset;
        !           363:        upc->pr_scale = uap->pcscale;
        !           364:        PROFILE_LOCK(&upp->pr_lock);
        !           365:        upc->pr_next = upp->pr_next;
        !           366:        upp->pr_next = upc;
        !           367:        PROFILE_UNLOCK(&upp->pr_lock);
        !           368:        splx(s);
        !           369:        return(0);
        !           370: }
        !           371: 
        !           372: /*
        !           373:  * Scale is a fixed-point number with the binary point 16 bits
        !           374:  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
        !           375:  * intermediate result is at most 48 bits.
        !           376:  */
        !           377: #define PC_TO_INDEX(pc, prof) \
        !           378:        ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
        !           379:                        (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
        !           380: 
        !           381: /*
        !           382:  * Collect user-level profiling statistics; called on a profiling tick,
        !           383:  * when a process is running in user-mode. We use
        !           384:  * an AST that will vector us to trap() with a context in which copyin
        !           385:  * and copyout will work.  Trap will then call addupc_task().
        !           386:  *
        !           387:  * Note that we may (rarely) not get around to the AST soon enough, and
        !           388:  * lose profile ticks when the next tick overwrites this one, but in this
        !           389:  * case the system is overloaded and the profile is probably already
        !           390:  * inaccurate.
        !           391:  *
        !           392:  * We can afford to take faults here.  If the
        !           393:  * update fails, we simply turn off profiling.
        !           394:  */
        !           395: void
        !           396: addupc_task(p, pc, ticks)
        !           397:        register struct proc *p;
        !           398:        register u_long pc;
        !           399:        u_int ticks;
        !           400: {
        !           401:        register struct uprof *prof;
        !           402:        register short *cell;
        !           403:        register u_int off;
        !           404:        u_short count;
        !           405: 
        !           406:        /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
        !           407:        if ((p->p_flag & P_PROFIL) == 0 || ticks == 0)
        !           408:                return;
        !           409: 
        !           410:        for (prof = &p->p_stats->p_prof; prof; prof = prof->pr_next) {
        !           411:                off = PC_TO_INDEX(pc,prof);
        !           412:                cell = (short *)(prof->pr_base + off);
        !           413:                if (cell >= (short *)prof->pr_base &&
        !           414:                        cell < (short*)(prof->pr_size + (int) prof->pr_base)) {
        !           415:                        if (copyin((caddr_t)cell, (caddr_t) &count, sizeof(count)) == 0) {
        !           416:                                count += ticks;
        !           417:                                if(copyout((caddr_t) &count, (caddr_t)cell, sizeof(count)) == 0)
        !           418:                                        return;
        !           419:                        }
        !           420:                        p->p_stats->p_prof.pr_scale = 0;
        !           421:                        stopprofclock(p);
        !           422:                        break;
        !           423:                }
        !           424:        }
        !           425: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.