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.30.2.1 2004/04/21 04:27:34 jmc 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.30.2.1 2004/04/21 04:27:34 jmc 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 = { 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()
   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(l, v, retval)
  219         struct lwp *l;
  220         void *v;
  221         register_t *retval;
  222 {
  223         struct sys_profil_args /* {
  224                 syscallarg(caddr_t) samples;
  225                 syscallarg(u_int) size;
  226                 syscallarg(u_int) offset;
  227                 syscallarg(u_int) scale;
  228         } */ *uap = v;
  229         struct proc *p = l->l_proc;
  230         struct uprof *upp;
  231         int s;
  232 
  233         if (SCARG(uap, scale) > (1 << 16))
  234                 return (EINVAL);
  235         if (SCARG(uap, scale) == 0) {
  236                 stopprofclock(p);
  237                 return (0);
  238         }
  239         upp = &p->p_stats->p_prof;
  240 
  241         /* Block profile interrupts while changing state. */
  242         s = splstatclock();
  243         upp->pr_off = SCARG(uap, offset);
  244         upp->pr_scale = SCARG(uap, scale);
  245         upp->pr_base = SCARG(uap, samples);
  246         upp->pr_size = SCARG(uap, size);
  247         startprofclock(p);
  248         splx(s);
  249 
  250         return (0);
  251 }
  252 
  253 /*
  254  * Scale is a fixed-point number with the binary point 16 bits
  255  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
  256  * intermediate result is at most 48 bits.
  257  */
  258 #define PC_TO_INDEX(pc, prof) \
  259         ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
  260             (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
  261 
  262 /*
  263  * Collect user-level profiling statistics; called on a profiling tick,
  264  * when a process is running in user-mode.  This routine may be called
  265  * from an interrupt context.  We try to update the user profiling buffers
  266  * cheaply with fuswintr() and suswintr().  If that fails, we revert to
  267  * an AST that will vector us to trap() with a context in which copyin
  268  * and copyout will work.  Trap will then call addupc_task().
  269  *
  270  * Note that we may (rarely) not get around to the AST soon enough, and
  271  * lose profile ticks when the next tick overwrites this one, but in this
  272  * case the system is overloaded and the profile is probably already
  273  * inaccurate.
  274  */
  275 void
  276 addupc_intr(p, pc)
  277         struct proc *p;
  278         u_long pc;
  279 {
  280         struct uprof *prof;
  281         caddr_t addr;
  282         u_int i;
  283         int v;
  284 
  285         prof = &p->p_stats->p_prof;
  286         if (pc < prof->pr_off ||
  287             (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
  288                 return;                 /* out of range; ignore */
  289 
  290         addr = prof->pr_base + i;
  291         if ((v = fuswintr(addr)) == -1 || suswintr(addr, v + 1) == -1) {
  292                 prof->pr_addr = pc;
  293                 prof->pr_ticks++;
  294                 need_proftick(p);
  295         }
  296 }
  297 
  298 /*
  299  * Much like before, but we can afford to take faults here.  If the
  300  * update fails, we simply turn off profiling.
  301  */
  302 void
  303 addupc_task(p, pc, ticks)
  304         struct proc *p;
  305         u_long pc;
  306         u_int ticks;
  307 {
  308         struct uprof *prof;
  309         caddr_t addr;
  310         u_int i;
  311         u_short v;
  312 
  313         /* Testing P_PROFIL may be unnecessary, but is certainly safe. */
  314         if ((p->p_flag & P_PROFIL) == 0 || ticks == 0)
  315                 return;
  316 
  317         prof = &p->p_stats->p_prof;
  318         if (pc < prof->pr_off ||
  319             (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
  320                 return;
  321 
  322         addr = prof->pr_base + i;
  323         if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
  324                 v += ticks;
  325                 if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
  326                         return;
  327         }
  328         stopprofclock(p);
  329 }

Cache object: e068fd555473904037b6aca140b97d5b


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