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.36.2.1 2006/12/29 02:04:14 riz 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.36.2.1 2006/12/29 02:04:14 riz 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/sa.h>
   44 #include <sys/syscallargs.h>
   45 #include <sys/sysctl.h>
   46 
   47 #include <machine/cpu.h>
   48 
   49 #ifdef GPROF
   50 #include <sys/malloc.h>
   51 #include <sys/gmon.h>
   52 
   53 MALLOC_DEFINE(M_GPROF, "gprof", "kernel profiling buffer");
   54 
   55 /*
   56  * Froms is actually a bunch of unsigned shorts indexing tos
   57  */
   58 struct gmonparam _gmonparam = { .state = GMON_PROF_OFF };
   59 
   60 /* Actual start of the kernel text segment. */
   61 extern char kernel_text[];
   62 
   63 extern char etext[];
   64 
   65 
   66 void
   67 kmstartup(void)
   68 {
   69         char *cp;
   70         struct gmonparam *p = &_gmonparam;
   71         /*
   72          * Round lowpc and highpc to multiples of the density we're using
   73          * so the rest of the scaling (here and in gprof) stays in ints.
   74          */
   75         p->lowpc = rounddown(((u_long)kernel_text),
   76                 HISTFRACTION * sizeof(HISTCOUNTER));
   77         p->highpc = roundup((u_long)etext,
   78                 HISTFRACTION * sizeof(HISTCOUNTER));
   79         p->textsize = p->highpc - p->lowpc;
   80         printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
   81                p->textsize, p->lowpc, p->highpc);
   82         p->kcountsize = p->textsize / HISTFRACTION;
   83         p->hashfraction = HASHFRACTION;
   84         p->fromssize = p->textsize / HASHFRACTION;
   85         p->tolimit = p->textsize * ARCDENSITY / 100;
   86         if (p->tolimit < MINARCS)
   87                 p->tolimit = MINARCS;
   88         else if (p->tolimit > MAXARCS)
   89                 p->tolimit = MAXARCS;
   90         p->tossize = p->tolimit * sizeof(struct tostruct);
   91         cp = (char *)malloc(p->kcountsize + p->fromssize + p->tossize,
   92             M_GPROF, M_NOWAIT);
   93         if (cp == 0) {
   94                 printf("No memory for profiling.\n");
   95                 return;
   96         }
   97         memset(cp, 0, p->kcountsize + p->tossize + p->fromssize);
   98         p->tos = (struct tostruct *)cp;
   99         cp += p->tossize;
  100         p->kcount = (u_short *)cp;
  101         cp += p->kcountsize;
  102         p->froms = (u_short *)cp;
  103 }
  104 
  105 /*
  106  * Return kernel profiling information.
  107  */
  108 /*
  109  * sysctl helper routine for kern.profiling subtree.  enables/disables
  110  * kernel profiling and gives out copies of the profiling data.
  111  */
  112 static int
  113 sysctl_kern_profiling(SYSCTLFN_ARGS)
  114 {
  115         struct gmonparam *gp = &_gmonparam;
  116         int error;
  117         struct sysctlnode node;
  118 
  119         node = *rnode;
  120 
  121         switch (node.sysctl_num) {
  122         case GPROF_STATE:
  123                 node.sysctl_data = &gp->state;
  124                 break;
  125         case GPROF_COUNT:
  126                 node.sysctl_data = gp->kcount;
  127                 node.sysctl_size = gp->kcountsize;
  128                 break;
  129         case GPROF_FROMS:
  130                 node.sysctl_data = gp->froms;
  131                 node.sysctl_size = gp->fromssize;
  132                 break;
  133         case GPROF_TOS:
  134                 node.sysctl_data = gp->tos;
  135                 node.sysctl_size = gp->tossize;
  136                 break;
  137         case GPROF_GMONPARAM:
  138                 node.sysctl_data = gp;
  139                 node.sysctl_size = sizeof(*gp);
  140                 break;
  141         default:
  142                 return (EOPNOTSUPP);
  143         }
  144 
  145         error = sysctl_lookup(SYSCTLFN_CALL(&node));
  146         if (error || newp == NULL)
  147                 return (error);
  148 
  149         if (node.sysctl_num == GPROF_STATE) {
  150                 if (gp->state == GMON_PROF_OFF)
  151                         stopprofclock(&proc0);
  152                 else
  153                         startprofclock(&proc0);
  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, void *v, register_t *retval)
  219 {
  220         struct sys_profil_args /* {
  221                 syscallarg(caddr_t) samples;
  222                 syscallarg(u_int) size;
  223                 syscallarg(u_int) offset;
  224                 syscallarg(u_int) scale;
  225         } */ *uap = v;
  226         struct proc *p = l->l_proc;
  227         struct uprof *upp;
  228         int s;
  229 
  230         if (SCARG(uap, scale) > (1 << 16))
  231                 return (EINVAL);
  232         if (SCARG(uap, scale) == 0) {
  233                 stopprofclock(p);
  234                 return (0);
  235         }
  236         upp = &p->p_stats->p_prof;
  237 
  238         /* Block profile interrupts while changing state. */
  239         s = splstatclock();
  240         upp->pr_off = SCARG(uap, offset);
  241         upp->pr_scale = SCARG(uap, scale);
  242         upp->pr_base = SCARG(uap, samples);
  243         upp->pr_size = SCARG(uap, size);
  244         startprofclock(p);
  245         splx(s);
  246 
  247         return (0);
  248 }
  249 
  250 /*
  251  * Scale is a fixed-point number with the binary point 16 bits
  252  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
  253  * intermediate result is at most 48 bits.
  254  */
  255 #define PC_TO_INDEX(pc, prof) \
  256         ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
  257             (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
  258 
  259 /*
  260  * Collect user-level profiling statistics; called on a profiling tick,
  261  * when a process is running in user-mode.  This routine may be called
  262  * from an interrupt context.  We try to update the user profiling buffers
  263  * cheaply with fuswintr() and suswintr().  If that fails, we revert to
  264  * an AST that will vector us to trap() with a context in which copyin
  265  * and copyout will work.  Trap will then call addupc_task().
  266  *
  267  * Note that we may (rarely) not get around to the AST soon enough, and
  268  * lose profile ticks when the next tick overwrites this one, but in this
  269  * case the system is overloaded and the profile is probably already
  270  * inaccurate.
  271  */
  272 void
  273 addupc_intr(struct proc *p, u_long pc)
  274 {
  275         struct uprof *prof;
  276         caddr_t addr;
  277         u_int i;
  278         int v;
  279 
  280         prof = &p->p_stats->p_prof;
  281         if (pc < prof->pr_off ||
  282             (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
  283                 return;                 /* out of range; ignore */
  284 
  285         addr = prof->pr_base + i;
  286         if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + 1) == -1) {
  287                 prof->pr_addr = pc;
  288                 prof->pr_ticks++;
  289                 need_proftick(p);
  290         }
  291 }
  292 
  293 /*
  294  * Much like before, but we can afford to take faults here.  If the
  295  * update fails, we simply turn off profiling.
  296  */
  297 void
  298 addupc_task(struct proc *p, u_long pc, u_int ticks)
  299 {
  300         struct uprof *prof;
  301         caddr_t addr;
  302         u_int i;
  303         u_short v;
  304 
  305         /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
  306         if ((p->p_flag & P_PROFIL) == 0 || ticks == 0)
  307                 return;
  308 
  309         prof = &p->p_stats->p_prof;
  310         if (pc < prof->pr_off ||
  311             (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
  312                 return;
  313 
  314         addr = prof->pr_base + i;
  315         if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
  316                 v += ticks;
  317                 if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
  318                         return;
  319         }
  320         stopprofclock(p);
  321 }

Cache object: 40c8c481513f8419b4fafb408294d977


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