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 /*      $OpenBSD: subr_prof.c,v 1.31 2021/09/03 16:45:45 jasper Exp $   */
    2 /*      $NetBSD: subr_prof.c,v 1.12 1996/04/22 01:38:50 christos Exp $  */
    3 
    4 /*-
    5  * Copyright (c) 1982, 1986, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. Neither the name of the University nor the names of its contributors
   17  *    may be used to endorse or promote products derived from this software
   18  *    without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   30  * SUCH DAMAGE.
   31  *
   32  *      @(#)subr_prof.c 8.3 (Berkeley) 9/23/93
   33  */
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/proc.h>
   38 #include <sys/resourcevar.h>
   39 #include <sys/mount.h>
   40 #include <sys/sysctl.h>
   41 #include <sys/syscallargs.h>
   42 
   43 
   44 #if defined(GPROF) || defined(DDBPROF)
   45 #include <sys/malloc.h>
   46 #include <sys/gmon.h>
   47 
   48 #include <uvm/uvm_extern.h>
   49 
   50 #include <machine/db_machdep.h>
   51 #include <ddb/db_extern.h>
   52 
   53 /*
   54  * Flag to prevent CPUs from executing the mcount() monitor function
   55  * until we're sure they are in a sane state.
   56  */
   57 int gmoninit = 0;
   58 
   59 extern char etext[];
   60 
   61 void
   62 prof_init(void)
   63 {
   64         CPU_INFO_ITERATOR cii;
   65         struct cpu_info *ci;
   66         struct gmonparam *p;
   67         u_long lowpc, highpc, textsize;
   68         u_long kcountsize, fromssize, tossize;
   69         long tolimit;
   70         char *cp;
   71         int size;
   72 
   73         /*
   74          * Round lowpc and highpc to multiples of the density we're using
   75          * so the rest of the scaling (here and in gprof) stays in ints.
   76          */
   77         lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
   78         highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
   79         textsize = highpc - lowpc;
   80 #ifdef GPROF
   81         printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
   82             textsize, lowpc, highpc);
   83 #endif
   84         kcountsize = textsize / HISTFRACTION;
   85         fromssize = textsize / HASHFRACTION;
   86         tolimit = textsize * ARCDENSITY / 100;
   87         if (tolimit < MINARCS)
   88                 tolimit = MINARCS;
   89         else if (tolimit > MAXARCS)
   90                 tolimit = MAXARCS;
   91         tossize = tolimit * sizeof(struct tostruct);
   92         size = sizeof(*p) + kcountsize + fromssize + tossize;
   93 
   94         /* Allocate and initialize one profiling buffer per CPU. */
   95         CPU_INFO_FOREACH(cii, ci) {
   96                 cp = km_alloc(round_page(size), &kv_any, &kp_zero, &kd_nowait);
   97                 if (cp == NULL) {
   98                         printf("No memory for profiling.\n");
   99                         return;
  100                 }
  101 
  102                 p = (struct gmonparam *)cp;
  103                 cp += sizeof(*p);
  104                 p->tos = (struct tostruct *)cp;
  105                 cp += tossize;
  106                 p->kcount = (u_short *)cp;
  107                 cp += kcountsize;
  108                 p->froms = (u_short *)cp;
  109 
  110                 p->state = GMON_PROF_OFF;
  111                 p->lowpc = lowpc;
  112                 p->highpc = highpc;
  113                 p->textsize = textsize;
  114                 p->hashfraction = HASHFRACTION;
  115                 p->kcountsize = kcountsize;
  116                 p->fromssize = fromssize;
  117                 p->tolimit = tolimit;
  118                 p->tossize = tossize;
  119 
  120                 ci->ci_gmon = p;
  121         }
  122 }
  123 
  124 int
  125 prof_state_toggle(struct gmonparam *gp, int oldstate)
  126 {
  127         int error = 0;
  128 
  129         if (gp->state == oldstate)
  130                 return (0);
  131 
  132         switch (gp->state) {
  133         case GMON_PROF_ON:
  134 #if !defined(GPROF)
  135                 /*
  136                  * If this is not a profiling kernel, we need to patch
  137                  * all symbols that can be instrummented.
  138                  */
  139                 error = db_prof_enable();
  140 #endif
  141                 if (error == 0)
  142                         startprofclock(&process0);
  143                 break;
  144         default:
  145                 error = EINVAL;
  146                 gp->state = GMON_PROF_OFF;
  147                 /* FALLTHROUGH */
  148         case GMON_PROF_OFF:
  149                 stopprofclock(&process0);
  150 #if !defined(GPROF)
  151                 db_prof_disable();
  152 #endif
  153                 break;
  154         }
  155 
  156         return (error);
  157 }
  158 
  159 /*
  160  * Return kernel profiling information.
  161  */
  162 int
  163 sysctl_doprof(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
  164     size_t newlen)
  165 {
  166         CPU_INFO_ITERATOR cii;
  167         struct cpu_info *ci;
  168         struct gmonparam *gp = NULL;
  169         int error, cpuid, op, state;
  170 
  171         /* all sysctl names at this level are name and field */
  172         if (namelen != 2)
  173                 return (ENOTDIR);               /* overloaded */
  174 
  175         op = name[0];
  176         cpuid = name[1];
  177 
  178         CPU_INFO_FOREACH(cii, ci) {
  179                 if (cpuid == CPU_INFO_UNIT(ci)) {
  180                         gp = ci->ci_gmon;
  181                         break;
  182                 }
  183         }
  184 
  185         if (gp == NULL)
  186                 return (EOPNOTSUPP);
  187 
  188         /* Assume that if we're here it is safe to execute profiling. */
  189         gmoninit = 1;
  190 
  191         switch (op) {
  192         case GPROF_STATE:
  193                 state = gp->state;
  194                 error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
  195                 if (error)
  196                         return (error);
  197                 return (prof_state_toggle(gp, state));
  198         case GPROF_COUNT:
  199                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
  200                     gp->kcount, gp->kcountsize));
  201         case GPROF_FROMS:
  202                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
  203                     gp->froms, gp->fromssize));
  204         case GPROF_TOS:
  205                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
  206                     gp->tos, gp->tossize));
  207         case GPROF_GMONPARAM:
  208                 return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
  209         default:
  210                 return (EOPNOTSUPP);
  211         }
  212         /* NOTREACHED */
  213 }
  214 #endif /* GPROF || DDBPROF */
  215 
  216 /*
  217  * Profiling system call.
  218  *
  219  * The scale factor is a fixed point number with 16 bits of fraction, so that
  220  * 1.0 is represented as 0x10000.  A scale factor of 0 turns off profiling.
  221  */
  222 int
  223 sys_profil(struct proc *p, void *v, register_t *retval)
  224 {
  225         struct sys_profil_args /* {
  226                 syscallarg(caddr_t) samples;
  227                 syscallarg(size_t) size;
  228                 syscallarg(u_long) offset;
  229                 syscallarg(u_int) scale;
  230         } */ *uap = v;
  231         struct process *pr = p->p_p;
  232         struct uprof *upp;
  233         int s;
  234 
  235         if (SCARG(uap, scale) > (1 << 16))
  236                 return (EINVAL);
  237         if (SCARG(uap, scale) == 0) {
  238                 stopprofclock(pr);
  239                 return (0);
  240         }
  241         upp = &pr->ps_prof;
  242 
  243         /* Block profile interrupts while changing state. */
  244         s = splstatclock();
  245         upp->pr_off = SCARG(uap, offset);
  246         upp->pr_scale = SCARG(uap, scale);
  247         upp->pr_base = (caddr_t)SCARG(uap, samples);
  248         upp->pr_size = SCARG(uap, size);
  249         startprofclock(pr);
  250         splx(s);
  251 
  252         return (0);
  253 }
  254 
  255 /*
  256  * Scale is a fixed-point number with the binary point 16 bits
  257  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
  258  * intermediate result is at most 48 bits.
  259  */
  260 #define PC_TO_INDEX(pc, prof) \
  261         ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
  262             (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
  263 
  264 /*
  265  * Collect user-level profiling statistics; called on a profiling tick,
  266  * when a process is running in user-mode.  This routine may be called
  267  * from an interrupt context. Schedule an AST that will vector us to
  268  * trap() with a context in which copyin and copyout will work.
  269  * Trap will then call addupc_task().
  270  */
  271 void
  272 addupc_intr(struct proc *p, u_long pc)
  273 {
  274         struct uprof *prof;
  275 
  276         prof = &p->p_p->ps_prof;
  277         if (pc < prof->pr_off || PC_TO_INDEX(pc, prof) >= prof->pr_size)
  278                 return;                 /* out of range; ignore */
  279 
  280         p->p_prof_addr = pc;
  281         p->p_prof_ticks++;
  282         atomic_setbits_int(&p->p_flag, P_OWEUPC);
  283         need_proftick(p);
  284 }
  285 
  286 
  287 /*
  288  * Much like before, but we can afford to take faults here.  If the
  289  * update fails, we simply turn off profiling.
  290  */
  291 void
  292 addupc_task(struct proc *p, u_long pc, u_int nticks)
  293 {
  294         struct process *pr = p->p_p;
  295         struct uprof *prof;
  296         caddr_t addr;
  297         u_int i;
  298         u_short v;
  299 
  300         /* Testing PS_PROFIL may be unnecessary, but is certainly safe. */
  301         if ((pr->ps_flags & PS_PROFIL) == 0 || nticks == 0)
  302                 return;
  303 
  304         prof = &pr->ps_prof;
  305         if (pc < prof->pr_off ||
  306             (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
  307                 return;
  308 
  309         addr = prof->pr_base + i;
  310         if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
  311                 v += nticks;
  312                 if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
  313                         return;
  314         }
  315         stopprofclock(pr);
  316 }

Cache object: e7cef23dc1f7dd67835a39d0ef5ad815


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