The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/kern/subr_prof.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   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 <kern/cpu_number.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 decl_simple_lock_data(,mcount_lock);
   79 
   80 /*
   81  * Froms is actually a bunch of unsigned shorts indexing tos
   82  */
   83 struct gmonparam _gmonparam = { GMON_PROF_OFF };
   84 
   85 kmstartup()
   86 {
   87         char *cp;
   88         u_long  fromssize, tossize;
   89         struct segment_command          *sgp;
   90         struct gmonparam *p = &_gmonparam;
   91         
   92         sgp = getsegbyname("__TEXT");
   93         p->lowpc = (u_long)sgp->vmaddr;
   94         p->highpc = (u_long)(sgp->vmaddr + sgp->vmsize);
   95         
   96         /*
   97          * Round lowpc and highpc to multiples of the density we're using
   98          * so the rest of the scaling (here and in gprof) stays in ints.
   99          */
  100         p->lowpc = ROUNDDOWN(p->lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
  101         p->highpc = ROUNDUP(p->highpc, HISTFRACTION * sizeof(HISTCOUNTER));
  102         p->textsize = p->highpc - p->lowpc;
  103         printf("Profiling kernel, textsize=%d [0x%08x..0x%08x]\n",
  104                p->textsize, p->lowpc, p->highpc);
  105         p->kcountsize = p->textsize / HISTFRACTION;
  106         p->hashfraction = HASHFRACTION;
  107         p->fromssize = p->textsize / HASHFRACTION;
  108         p->tolimit = p->textsize * ARCDENSITY / 100;
  109         if (p->tolimit < MINARCS)
  110                 p->tolimit = MINARCS;
  111         else if (p->tolimit > MAXARCS)
  112                 p->tolimit = MAXARCS;
  113         p->tossize = p->tolimit * sizeof(struct tostruct);
  114         /* Why not use MALLOC with M_GPROF ? */
  115         cp = (char *)kalloc(p->kcountsize + p->fromssize + p->tossize);
  116         if (cp == 0) {
  117                 printf("No memory for profiling.\n");
  118                 return;
  119         }
  120         bzero(cp, p->kcountsize + p->tossize + p->fromssize);
  121         p->tos = (struct tostruct *)cp;
  122         cp += p->tossize;
  123         p->kcount = (u_short *)cp;
  124         cp += p->kcountsize;
  125         p->froms = (u_short *)cp;
  126         simple_lock_init(&mcount_lock);
  127 }
  128 
  129 /*
  130  * Return kernel profiling information.
  131  */
  132 int
  133 sysctl_doprof(name, namelen, oldp, oldlenp, newp, newlen)
  134         int *name;
  135         u_int namelen;
  136         void *oldp;
  137         size_t *oldlenp;
  138         void *newp;
  139         size_t newlen;
  140 {
  141         struct gmonparam *gp = &_gmonparam;
  142         int error;
  143 
  144         /* all sysctl names at this level are terminal */
  145         if (namelen != 1)
  146                 return (ENOTDIR);               /* overloaded */
  147 
  148         switch (name[0]) {
  149         case GPROF_STATE:
  150                 error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
  151                 if (error)
  152                         return (error);
  153                 if (gp->state == GMON_PROF_OFF)
  154                         stopprofclock(kernproc);
  155                 else
  156                         startprofclock(kernproc);
  157                 return (0);
  158         case GPROF_COUNT:
  159                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
  160                     gp->kcount, gp->kcountsize));
  161         case GPROF_FROMS:
  162                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
  163                     gp->froms, gp->fromssize));
  164         case GPROF_TOS:
  165                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
  166                     gp->tos, gp->tossize));
  167         case GPROF_GMONPARAM:
  168                 return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
  169         default:
  170                 return (EOPNOTSUPP);
  171         }
  172         /* NOTREACHED */
  173 }
  174 
  175 
  176 /*
  177  * mcount() called with interrupts disabled.
  178  */
  179 void
  180 mcount(
  181     register u_long frompc,
  182     register u_long selfpc
  183 )
  184 {
  185     unsigned short *frompcindex;
  186         register struct tostruct *top, *prevtop;
  187         struct gmonparam *p = &_gmonparam;
  188         register long toindex;
  189 
  190     /*
  191      * check that we are profiling
  192      * and that we aren't recursively invoked.
  193      */
  194     if (p->state != GMON_PROF_ON)
  195         return;
  196 
  197         usimple_lock(&mcount_lock);
  198 
  199         /*
  200          *      check that frompcindex is a reasonable pc value.
  201          *      for example:    signal catchers get called from the stack,
  202          *                      not from text space.  too bad.
  203          */
  204         frompc -= p->lowpc;
  205         if (frompc > p->textsize)
  206                 goto done;
  207 
  208         frompcindex = &p->froms[frompc / (p->hashfraction * sizeof(*p->froms))];
  209         toindex = *frompcindex;
  210         if (toindex == 0) {
  211                 /*
  212                  *      first time traversing this arc
  213                  */
  214                 toindex = ++p->tos[0].link;
  215                 if (toindex >= p->tolimit) {
  216             /* halt further profiling */
  217                         goto overflow;
  218                 }
  219                 *frompcindex = toindex;
  220                 top = &p->tos[toindex];
  221                 top->selfpc = selfpc;
  222                 top->count = 1;
  223                 top->link = 0;
  224                 goto done;
  225         }
  226         top = &p->tos[toindex];
  227         if (top->selfpc == selfpc) {
  228                 /*
  229                  *      arc at front of chain; usual case.
  230                  */
  231                 top->count++;
  232                 goto done;
  233         }
  234         /*
  235          *      have to go looking down chain for it.
  236          *      top points to what we are looking at,
  237          *      prevtop points to previous top.
  238          *      we know it is not at the head of the chain.
  239          */
  240         for (; /* goto done */; ) {
  241                 if (top->link == 0) {
  242                         /*
  243                          *      top is end of the chain and none of the chain
  244                          *      had top->selfpc == selfpc.
  245                          *      so we allocate a new tostruct
  246                          *      and link it to the head of the chain.
  247                          */
  248                         toindex = ++p->tos[0].link;
  249                         if (toindex >= p->tolimit) {
  250                                 goto overflow;
  251                         }
  252                         top = &p->tos[toindex];
  253                         top->selfpc = selfpc;
  254                         top->count = 1;
  255                         top->link = *frompcindex;
  256                         *frompcindex = toindex;
  257                         goto done;
  258                 }
  259                 /*
  260                  *      otherwise, check the next arc on the chain.
  261                  */
  262                 prevtop = top;
  263                 top = &p->tos[top->link];
  264                 if (top->selfpc == selfpc) {
  265                         /*
  266                          *      there it is.
  267                          *      increment its count
  268                          *      move it to the head of the chain.
  269                          */
  270                         top->count++;
  271                         toindex = prevtop->link;
  272                         prevtop->link = top->link;
  273                         top->link = *frompcindex;
  274                         *frompcindex = toindex;
  275                         goto done;
  276                 }
  277 
  278         }
  279 done:
  280         usimple_unlock(&mcount_lock);
  281         return;
  282 
  283 overflow:
  284     p->state = GMON_PROF_ERROR;
  285         usimple_unlock(&mcount_lock);
  286         printf("mcount: tos overflow\n");
  287         return;
  288 }
  289 
  290 #endif /* GPROF */
  291 
  292 #define PROFILE_LOCK(x)         simple_lock(x)
  293 #define PROFILE_UNLOCK(x)       simple_unlock(x)
  294 
  295 struct profil_args {
  296         short   *bufbase;
  297         u_int bufsize;
  298         u_int pcoffset;
  299         u_int pcscale;
  300 };
  301 int
  302 profil(p, uap, retval)
  303         struct proc *p;
  304         register struct profil_args *uap;
  305         register_t *retval;
  306 {
  307         register struct uprof *upp = &p->p_stats->p_prof;
  308         struct uprof *upc, *nupc;
  309         int s;
  310 
  311         if (uap->pcscale > (1 << 16))
  312                 return (EINVAL);
  313         if (uap->pcscale == 0) {
  314                 stopprofclock(p);
  315                 return (0);
  316         }
  317 
  318         /* Block profile interrupts while changing state. */
  319         s = ml_set_interrupts_enabled(FALSE);   
  320         PROFILE_LOCK(&upp->pr_lock);
  321         upp->pr_base = (caddr_t)uap->bufbase;
  322         upp->pr_size = uap->bufsize;
  323         upp->pr_off = uap->pcoffset;
  324         upp->pr_scale = uap->pcscale;
  325 
  326         /* remove buffers previously allocated with add_profil() */
  327         for (upc = upp->pr_next; upc; upc = nupc) {
  328                 nupc = upc->pr_next;
  329                 kfree(upc, sizeof (struct uprof));
  330         }
  331 
  332         upp->pr_next = 0;
  333         PROFILE_UNLOCK(&upp->pr_lock);
  334         startprofclock(p);
  335         ml_set_interrupts_enabled(s);
  336         return(0);
  337 }
  338 
  339 struct add_profile_args {
  340         short   *bufbase;
  341         u_int bufsize;
  342         u_int pcoffset;
  343         u_int pcscale;
  344 };
  345 int
  346 add_profil(p, uap, retval)
  347         struct proc *p;
  348         register struct add_profile_args *uap;
  349         register_t *retval;
  350 {
  351         struct uprof *upp = &p->p_stats->p_prof, *upc;
  352         int s;
  353 
  354         if (upp->pr_scale == 0)
  355                 return (0);
  356         s = ml_set_interrupts_enabled(FALSE);           
  357         upc = (struct uprof *) kalloc(sizeof (struct uprof));
  358         upc->pr_base = (caddr_t)uap->bufbase;
  359         upc->pr_size = uap->bufsize;
  360         upc->pr_off = uap->pcoffset;
  361         upc->pr_scale = uap->pcscale;
  362         PROFILE_LOCK(&upp->pr_lock);
  363         upc->pr_next = upp->pr_next;
  364         upp->pr_next = upc;
  365         PROFILE_UNLOCK(&upp->pr_lock);
  366         ml_set_interrupts_enabled(s);           
  367         return(0);
  368 }
  369 
  370 /*
  371  * Scale is a fixed-point number with the binary point 16 bits
  372  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
  373  * intermediate result is at most 48 bits.
  374  */
  375 #define PC_TO_INDEX(pc, prof) \
  376         ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
  377                         (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
  378 
  379 /*
  380  * Collect user-level profiling statistics; called on a profiling tick,
  381  * when a process is running in user-mode. We use
  382  * an AST that will vector us to trap() with a context in which copyin
  383  * and copyout will work.  Trap will then call addupc_task().
  384  *
  385  * Note that we may (rarely) not get around to the AST soon enough, and
  386  * lose profile ticks when the next tick overwrites this one, but in this
  387  * case the system is overloaded and the profile is probably already
  388  * inaccurate.
  389  *
  390  * We can afford to take faults here.  If the
  391  * update fails, we simply turn off profiling.
  392  */
  393 void
  394 addupc_task(p, pc, ticks)
  395         register struct proc *p;
  396         register u_long pc;
  397         u_int ticks;
  398 {
  399         register struct uprof *prof;
  400         register short *cell;
  401         register u_int off;
  402         u_short count;
  403 
  404         /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
  405         if ((p->p_flag & P_PROFIL) == 0 || ticks == 0)
  406                 return;
  407 
  408         for (prof = &p->p_stats->p_prof; prof; prof = prof->pr_next) {
  409                 off = PC_TO_INDEX(pc,prof);
  410                 cell = (short *)(prof->pr_base + off);
  411                 if (cell >= (short *)prof->pr_base &&
  412                         cell < (short*)(prof->pr_size + (int) prof->pr_base)) {
  413                         if (copyin((caddr_t)cell, (caddr_t) &count, sizeof(count)) == 0) {
  414                                 count += ticks;
  415                                 if(copyout((caddr_t) &count, (caddr_t)cell, sizeof(count)) == 0)
  416                                         return;
  417                         }
  418                         p->p_stats->p_prof.pr_scale = 0;
  419                         stopprofclock(p);
  420                         break;
  421                 }
  422         }
  423 }

Cache object: 753570ad3a0e9811a44924c59e1df34c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.