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/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 /*      $NetBSD: subr_prof.c,v 1.43 2007/12/20 23:03:10 dsl Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 1982, 1986, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  * 3. Neither the name of the University nor the names of its contributors
   16  *    may be used to endorse or promote products derived from this software
   17  *    without specific prior written permission.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   29  * SUCH DAMAGE.
   30  *
   31  *      @(#)subr_prof.c 8.4 (Berkeley) 2/14/95
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: subr_prof.c,v 1.43 2007/12/20 23:03:10 dsl Exp $");
   36 
   37 #include <sys/param.h>
   38 #include <sys/systm.h>
   39 #include <sys/kernel.h>
   40 #include <sys/proc.h>
   41 #include <sys/user.h>
   42 #include <sys/mount.h>
   43 #include <sys/syscallargs.h>
   44 #include <sys/sysctl.h>
   45 
   46 #include <sys/cpu.h>
   47 
   48 #ifdef GPROF
   49 #include <sys/malloc.h>
   50 #include <sys/gmon.h>
   51 
   52 MALLOC_DEFINE(M_GPROF, "gprof", "kernel profiling buffer");
   53 
   54 /*
   55  * Froms is actually a bunch of unsigned shorts indexing tos
   56  */
   57 struct gmonparam _gmonparam = { .state = GMON_PROF_OFF };
   58 
   59 /* Actual start of the kernel text segment. */
   60 extern char kernel_text[];
   61 
   62 extern char etext[];
   63 
   64 
   65 void
   66 kmstartup(void)
   67 {
   68         char *cp;
   69         struct gmonparam *p = &_gmonparam;
   70         /*
   71          * Round lowpc and highpc to multiples of the density we're using
   72          * so the rest of the scaling (here and in gprof) stays in ints.
   73          */
   74         p->lowpc = rounddown(((u_long)kernel_text),
   75                 HISTFRACTION * sizeof(HISTCOUNTER));
   76         p->highpc = roundup((u_long)etext,
   77                 HISTFRACTION * sizeof(HISTCOUNTER));
   78         p->textsize = p->highpc - p->lowpc;
   79         printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
   80                p->textsize, p->lowpc, p->highpc);
   81         p->kcountsize = p->textsize / HISTFRACTION;
   82         p->hashfraction = HASHFRACTION;
   83         p->fromssize = p->textsize / HASHFRACTION;
   84         p->tolimit = p->textsize * ARCDENSITY / 100;
   85         if (p->tolimit < MINARCS)
   86                 p->tolimit = MINARCS;
   87         else if (p->tolimit > MAXARCS)
   88                 p->tolimit = MAXARCS;
   89         p->tossize = p->tolimit * sizeof(struct tostruct);
   90         cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize,
   91             M_GPROF, M_NOWAIT | M_ZERO);
   92         if (cp == 0) {
   93                 printf("No memory for profiling.\n");
   94                 return;
   95         }
   96         p->tos = (struct tostruct *)cp;
   97         cp += p->tossize;
   98         p->kcount = (u_short *)cp;
   99         cp += p->kcountsize;
  100         p->froms = (u_short *)cp;
  101 }
  102 
  103 /*
  104  * Return kernel profiling information.
  105  */
  106 /*
  107  * sysctl helper routine for kern.profiling subtree.  enables/disables
  108  * kernel profiling and gives out copies of the profiling data.
  109  */
  110 static int
  111 sysctl_kern_profiling(SYSCTLFN_ARGS)
  112 {
  113         struct gmonparam *gp = &_gmonparam;
  114         int error;
  115         struct sysctlnode node;
  116 
  117         node = *rnode;
  118 
  119         switch (node.sysctl_num) {
  120         case GPROF_STATE:
  121                 node.sysctl_data = &gp->state;
  122                 break;
  123         case GPROF_COUNT:
  124                 node.sysctl_data = gp->kcount;
  125                 node.sysctl_size = gp->kcountsize;
  126                 break;
  127         case GPROF_FROMS:
  128                 node.sysctl_data = gp->froms;
  129                 node.sysctl_size = gp->fromssize;
  130                 break;
  131         case GPROF_TOS:
  132                 node.sysctl_data = gp->tos;
  133                 node.sysctl_size = gp->tossize;
  134                 break;
  135         case GPROF_GMONPARAM:
  136                 node.sysctl_data = gp;
  137                 node.sysctl_size = sizeof(*gp);
  138                 break;
  139         default:
  140                 return (EOPNOTSUPP);
  141         }
  142 
  143         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  144         if (error || newp == NULL)
  145                 return (error);
  146 
  147         if (node.sysctl_num == GPROF_STATE) {
  148                 mutex_spin_enter(&proc0.p_stmutex);
  149                 if (gp->state == GMON_PROF_OFF)
  150                         stopprofclock(&proc0);
  151                 else
  152                         startprofclock(&proc0);
  153                 mutex_spin_exit(&proc0.p_stmutex);
  154         }
  155 
  156         return (0);
  157 }
  158 
  159 SYSCTL_SETUP(sysctl_kern_gprof_setup, "sysctl kern.profiling subtree setup")
  160 {
  161 
  162         sysctl_createv(clog, 0, NULL, NULL,
  163                        CTLFLAG_PERMANENT,
  164                        CTLTYPE_NODE, "kern", NULL,
  165                        NULL, 0, NULL, 0,
  166                        CTL_KERN, CTL_EOL);
  167         sysctl_createv(clog, 0, NULL, NULL,
  168                        CTLFLAG_PERMANENT,
  169                        CTLTYPE_NODE, "profiling",
  170                        SYSCTL_DESCR("Profiling information (available)"),
  171                        NULL, 0, NULL, 0,
  172                        CTL_KERN, KERN_PROF, CTL_EOL);
  173 
  174         sysctl_createv(clog, 0, NULL, NULL,
  175                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  176                        CTLTYPE_INT, "state",
  177                        SYSCTL_DESCR("Profiling state"),
  178                        sysctl_kern_profiling, 0, NULL, 0,
  179                        CTL_KERN, KERN_PROF, GPROF_STATE, CTL_EOL);
  180         sysctl_createv(clog, 0, NULL, NULL,
  181                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  182                        CTLTYPE_STRUCT, "count",
  183                        SYSCTL_DESCR("Array of statistical program counters"),
  184                        sysctl_kern_profiling, 0, NULL, 0,
  185                        CTL_KERN, KERN_PROF, GPROF_COUNT, CTL_EOL);
  186         sysctl_createv(clog, 0, NULL, NULL,
  187                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  188                        CTLTYPE_STRUCT, "froms",
  189                        SYSCTL_DESCR("Array indexed by program counter of "
  190                                     "call-from points"),
  191                        sysctl_kern_profiling, 0, NULL, 0,
  192                        CTL_KERN, KERN_PROF, GPROF_FROMS, CTL_EOL);
  193         sysctl_createv(clog, 0, NULL, NULL,
  194                        CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
  195                        CTLTYPE_STRUCT, "tos",
  196                        SYSCTL_DESCR("Array of structures describing "
  197                                     "destination of calls and their counts"),
  198                        sysctl_kern_profiling, 0, NULL, 0,
  199                        CTL_KERN, KERN_PROF, GPROF_TOS, CTL_EOL);
  200         sysctl_createv(clog, 0, NULL, NULL,
  201                        CTLFLAG_PERMANENT,
  202                        CTLTYPE_STRUCT, "gmonparam",
  203                        SYSCTL_DESCR("Structure giving the sizes of the above "
  204                                     "arrays"),
  205                        sysctl_kern_profiling, 0, NULL, 0,
  206                        CTL_KERN, KERN_PROF, GPROF_GMONPARAM, CTL_EOL);
  207 }
  208 #endif /* GPROF */
  209 
  210 /*
  211  * Profiling system call.
  212  *
  213  * The scale factor is a fixed point number with 16 bits of fraction, so that
  214  * 1.0 is represented as 0x10000.  A scale factor of 0 turns off profiling.
  215  */
  216 /* ARGSUSED */
  217 int
  218 sys_profil(struct lwp *l, const struct sys_profil_args *uap, register_t *retval)
  219 {
  220         /* {
  221                 syscallarg(char *) samples;
  222                 syscallarg(u_int) size;
  223                 syscallarg(u_int) offset;
  224                 syscallarg(u_int) scale;
  225         } */
  226         struct proc *p = l->l_proc;
  227         struct uprof *upp;
  228 
  229         if (SCARG(uap, scale) > (1 << 16))
  230                 return (EINVAL);
  231         if (SCARG(uap, scale) == 0) {
  232                 mutex_spin_enter(&p->p_stmutex);
  233                 stopprofclock(p);
  234                 mutex_spin_exit(&p->p_stmutex);
  235                 return (0);
  236         }
  237         upp = &p->p_stats->p_prof;
  238 
  239         /* Block profile interrupts while changing state. */
  240         mutex_spin_enter(&p->p_stmutex);
  241         upp->pr_off = SCARG(uap, offset);
  242         upp->pr_scale = SCARG(uap, scale);
  243         upp->pr_base = SCARG(uap, samples);
  244         upp->pr_size = SCARG(uap, size);
  245         startprofclock(p);
  246         mutex_spin_exit(&p->p_stmutex);
  247 
  248         return (0);
  249 }
  250 
  251 /*
  252  * Scale is a fixed-point number with the binary point 16 bits
  253  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
  254  * intermediate result is at most 48 bits.
  255  */
  256 #define PC_TO_INDEX(pc, prof) \
  257         ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
  258             (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
  259 
  260 /*
  261  * Collect user-level profiling statistics; called on a profiling tick,
  262  * when a process is running in user-mode.  This routine may be called
  263  * from an interrupt context.  We try to update the user profiling buffers
  264  * cheaply with fuswintr() and suswintr().  If that fails, we revert to
  265  * an AST that will vector us to trap() with a context in which copyin
  266  * and copyout will work.  Trap will then call addupc_task().
  267  *
  268  * Note that we may (rarely) not get around to the AST soon enough, and
  269  * lose profile ticks when the next tick overwrites this one, but in this
  270  * case the system is overloaded and the profile is probably already
  271  * inaccurate.
  272  */
  273 void
  274 addupc_intr(struct lwp *l, u_long pc)
  275 {
  276         struct uprof *prof;
  277         struct proc *p;
  278         void *addr;
  279         u_int i;
  280         int v;
  281 
  282         p = l->l_proc;
  283 
  284         KASSERT(mutex_owned(&p->p_stmutex));
  285 
  286         prof = &p->p_stats->p_prof;
  287         if (pc < prof->pr_off ||
  288             (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
  289                 return;                 /* out of range; ignore */
  290 
  291         addr = prof->pr_base + i;
  292         mutex_spin_exit(&p->p_stmutex);
  293         if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + 1) == -1) {
  294                 /* XXXSMP */
  295                 prof->pr_addr = pc;
  296                 prof->pr_ticks++;
  297                 cpu_need_proftick(l);
  298         }
  299         mutex_spin_enter(&p->p_stmutex);
  300 }
  301 
  302 /*
  303  * Much like before, but we can afford to take faults here.  If the
  304  * update fails, we simply turn off profiling.
  305  */
  306 void
  307 addupc_task(struct lwp *l, u_long pc, u_int ticks)
  308 {
  309         struct uprof *prof;
  310         struct proc *p;
  311         void *addr;
  312         int error;
  313         u_int i;
  314         u_short v;
  315 
  316         p = l->l_proc;
  317 
  318         if (ticks == 0)
  319                 return;
  320 
  321         mutex_spin_enter(&p->p_stmutex);
  322         prof = &p->p_stats->p_prof;
  323 
  324         /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
  325         if ((p->p_stflag & PST_PROFIL) == 0 || pc < prof->pr_off ||
  326             (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size) {
  327                 mutex_spin_exit(&p->p_stmutex);
  328                 return;
  329         }
  330 
  331         addr = prof->pr_base + i;
  332         mutex_spin_exit(&p->p_stmutex);
  333         if ((error = copyin(addr, (void *)&v, sizeof(v))) == 0) {
  334                 v += ticks;
  335                 error = copyout((void *)&v, addr, sizeof(v));
  336         }
  337         if (error != 0) {
  338                 mutex_spin_enter(&p->p_stmutex);
  339                 stopprofclock(p);
  340                 mutex_spin_exit(&p->p_stmutex);
  341         }
  342 }

Cache object: daefd9785fe4d3b0aebf534faf812805


[ 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.