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

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

unix.superglobalmegacorp.com

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