LCOV - code coverage report
Current view: top level - kern - subr_prof.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 43 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: subr_prof.c,v 1.30 2016/09/04 09:22:29 mpi 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             : #if !defined(GPROF) && defined(DDBPROF)
      74             :         db_prof_init();
      75             : #endif
      76             : 
      77             :         /*
      78             :          * Round lowpc and highpc to multiples of the density we're using
      79             :          * so the rest of the scaling (here and in gprof) stays in ints.
      80             :          */
      81             :         lowpc = ROUNDDOWN(KERNBASE, HISTFRACTION * sizeof(HISTCOUNTER));
      82             :         highpc = ROUNDUP((u_long)etext, HISTFRACTION * sizeof(HISTCOUNTER));
      83             :         textsize = highpc - lowpc;
      84             : #ifdef GPROF
      85             :         printf("Profiling kernel, textsize=%ld [%lx..%lx]\n",
      86             :             textsize, lowpc, highpc);
      87             : #endif
      88             :         kcountsize = textsize / HISTFRACTION;
      89             :         fromssize = textsize / HASHFRACTION;
      90             :         tolimit = textsize * ARCDENSITY / 100;
      91             :         if (tolimit < MINARCS)
      92             :                 tolimit = MINARCS;
      93             :         else if (tolimit > MAXARCS)
      94             :                 tolimit = MAXARCS;
      95             :         tossize = tolimit * sizeof(struct tostruct);
      96             :         size = sizeof(*p) + kcountsize + fromssize + tossize;
      97             : 
      98             :         /* Allocate and initialize one profiling buffer per CPU. */
      99             :         CPU_INFO_FOREACH(cii, ci) {
     100             :                 cp = km_alloc(round_page(size), &kv_any, &kp_zero, &kd_nowait);
     101             :                 if (cp == NULL) {
     102             :                         printf("No memory for profiling.\n");
     103             :                         return;
     104             :                 }
     105             : 
     106             :                 p = (struct gmonparam *)cp;
     107             :                 cp += sizeof(*p);
     108             :                 p->tos = (struct tostruct *)cp;
     109             :                 cp += tossize;
     110             :                 p->kcount = (u_short *)cp;
     111             :                 cp += kcountsize;
     112             :                 p->froms = (u_short *)cp;
     113             : 
     114             :                 p->state = GMON_PROF_OFF;
     115             :                 p->lowpc = lowpc;
     116             :                 p->highpc = highpc;
     117             :                 p->textsize = textsize;
     118             :                 p->hashfraction = HASHFRACTION;
     119             :                 p->kcountsize = kcountsize;
     120             :                 p->fromssize = fromssize;
     121             :                 p->tolimit = tolimit;
     122             :                 p->tossize = tossize;
     123             : 
     124             :                 ci->ci_gmon = p;
     125             :         }
     126             : }
     127             : 
     128             : int
     129             : prof_state_toggle(struct gmonparam *gp, int oldstate)
     130             : {
     131             :         int error = 0;
     132             : 
     133             :         if (gp->state == oldstate)
     134             :                 return (0);
     135             : 
     136             :         switch (gp->state) {
     137             :         case GMON_PROF_ON:
     138             : #if !defined(GPROF)
     139             :                 /*
     140             :                  * If this is not a profiling kernel, we need to patch
     141             :                  * all symbols that can be instrummented.
     142             :                  */
     143             :                 error = db_prof_enable();
     144             : #endif
     145             :                 if (error == 0)
     146             :                         startprofclock(&process0);
     147             :                 break;
     148             :         default:
     149             :                 error = EINVAL;
     150             :                 gp->state = GMON_PROF_OFF;
     151             :                 /* FALLTHROUGH */
     152             :         case GMON_PROF_OFF:
     153             :                 stopprofclock(&process0);
     154             : #if !defined(GPROF)
     155             :                 db_prof_disable();
     156             : #endif
     157             :                 break;
     158             :         }
     159             : 
     160             :         return (error);
     161             : }
     162             : 
     163             : /*
     164             :  * Return kernel profiling information.
     165             :  */
     166             : int
     167             : sysctl_doprof(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
     168             :     size_t newlen)
     169             : {
     170             :         CPU_INFO_ITERATOR cii;
     171             :         struct cpu_info *ci;
     172             :         struct gmonparam *gp = NULL;
     173             :         int error, cpuid, op, state;
     174             : 
     175             :         /* all sysctl names at this level are name and field */
     176             :         if (namelen != 2)
     177             :                 return (ENOTDIR);               /* overloaded */
     178             : 
     179             :         op = name[0];
     180             :         cpuid = name[1];
     181             : 
     182             :         CPU_INFO_FOREACH(cii, ci) {
     183             :                 if (cpuid == CPU_INFO_UNIT(ci)) {
     184             :                         gp = ci->ci_gmon;
     185             :                         break;
     186             :                 }
     187             :         }
     188             : 
     189             :         if (gp == NULL)
     190             :                 return (EOPNOTSUPP);
     191             : 
     192             :         /* Assume that if we're here it is safe to execute profiling. */
     193             :         gmoninit = 1;
     194             : 
     195             :         switch (op) {
     196             :         case GPROF_STATE:
     197             :                 state = gp->state;
     198             :                 error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state);
     199             :                 if (error)
     200             :                         return (error);
     201             :                 return (prof_state_toggle(gp, state));
     202             :         case GPROF_COUNT:
     203             :                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
     204             :                     gp->kcount, gp->kcountsize));
     205             :         case GPROF_FROMS:
     206             :                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
     207             :                     gp->froms, gp->fromssize));
     208             :         case GPROF_TOS:
     209             :                 return (sysctl_struct(oldp, oldlenp, newp, newlen,
     210             :                     gp->tos, gp->tossize));
     211             :         case GPROF_GMONPARAM:
     212             :                 return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp));
     213             :         default:
     214             :                 return (EOPNOTSUPP);
     215             :         }
     216             :         /* NOTREACHED */
     217             : }
     218             : #endif /* GPROF || DDBPROF */
     219             : 
     220             : /*
     221             :  * Profiling system call.
     222             :  *
     223             :  * The scale factor is a fixed point number with 16 bits of fraction, so that
     224             :  * 1.0 is represented as 0x10000.  A scale factor of 0 turns off profiling.
     225             :  */
     226             : int
     227           0 : sys_profil(struct proc *p, void *v, register_t *retval)
     228             : {
     229             :         struct sys_profil_args /* {
     230             :                 syscallarg(caddr_t) samples;
     231             :                 syscallarg(size_t) size;
     232             :                 syscallarg(u_long) offset;
     233             :                 syscallarg(u_int) scale;
     234           0 :         } */ *uap = v;
     235           0 :         struct process *pr = p->p_p;
     236             :         struct uprof *upp;
     237             :         int s;
     238             : 
     239           0 :         if (SCARG(uap, scale) > (1 << 16))
     240           0 :                 return (EINVAL);
     241           0 :         if (SCARG(uap, scale) == 0) {
     242           0 :                 stopprofclock(pr);
     243           0 :                 return (0);
     244             :         }
     245           0 :         upp = &pr->ps_prof;
     246             : 
     247             :         /* Block profile interrupts while changing state. */
     248           0 :         s = splstatclock();
     249           0 :         upp->pr_off = SCARG(uap, offset);
     250           0 :         upp->pr_scale = SCARG(uap, scale);
     251           0 :         upp->pr_base = (caddr_t)SCARG(uap, samples);
     252           0 :         upp->pr_size = SCARG(uap, size);
     253           0 :         startprofclock(pr);
     254           0 :         splx(s);
     255             : 
     256           0 :         return (0);
     257           0 : }
     258             : 
     259             : /*
     260             :  * Scale is a fixed-point number with the binary point 16 bits
     261             :  * into the value, and is <= 1.0.  pc is at most 32 bits, so the
     262             :  * intermediate result is at most 48 bits.
     263             :  */
     264             : #define PC_TO_INDEX(pc, prof) \
     265             :         ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \
     266             :             (u_quad_t)((prof)->pr_scale)) >> 16) & ~1)
     267             : 
     268             : /*
     269             :  * Collect user-level profiling statistics; called on a profiling tick,
     270             :  * when a process is running in user-mode.  This routine may be called
     271             :  * from an interrupt context. Schedule an AST that will vector us to
     272             :  * trap() with a context in which copyin and copyout will work.
     273             :  * Trap will then call addupc_task().
     274             :  */
     275             : void
     276           0 : addupc_intr(struct proc *p, u_long pc)
     277             : {
     278             :         struct uprof *prof;
     279             : 
     280           0 :         prof = &p->p_p->ps_prof;
     281           0 :         if (pc < prof->pr_off || PC_TO_INDEX(pc, prof) >= prof->pr_size)
     282           0 :                 return;                 /* out of range; ignore */
     283             : 
     284           0 :         p->p_prof_addr = pc;
     285           0 :         p->p_prof_ticks++;
     286           0 :         atomic_setbits_int(&p->p_flag, P_OWEUPC);
     287           0 :         need_proftick(p);
     288           0 : }
     289             : 
     290             : 
     291             : /*
     292             :  * Much like before, but we can afford to take faults here.  If the
     293             :  * update fails, we simply turn off profiling.
     294             :  */
     295             : void
     296           0 : addupc_task(struct proc *p, u_long pc, u_int nticks)
     297             : {
     298           0 :         struct process *pr = p->p_p;
     299             :         struct uprof *prof;
     300             :         caddr_t addr;
     301             :         u_int i;
     302           0 :         u_short v;
     303             : 
     304             :         /* Testing PS_PROFIL may be unnecessary, but is certainly safe. */
     305           0 :         if ((pr->ps_flags & PS_PROFIL) == 0 || nticks == 0)
     306           0 :                 return;
     307             : 
     308           0 :         prof = &pr->ps_prof;
     309           0 :         if (pc < prof->pr_off ||
     310           0 :             (i = PC_TO_INDEX(pc, prof)) >= prof->pr_size)
     311           0 :                 return;
     312             : 
     313           0 :         addr = prof->pr_base + i;
     314           0 :         if (copyin(addr, (caddr_t)&v, sizeof(v)) == 0) {
     315           0 :                 v += nticks;
     316           0 :                 if (copyout((caddr_t)&v, addr, sizeof(v)) == 0)
     317           0 :                         return;
     318             :         }
     319           0 :         stopprofclock(pr);
     320           0 : }

Generated by: LCOV version 1.13