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/kern_clock.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: kern_clock.c,v 1.105 2022/08/14 01:58:27 jsg Exp $    */
    2 /*      $NetBSD: kern_clock.c,v 1.34 1996/06/09 04:51:03 briggs Exp $   */
    3 
    4 /*-
    5  * Copyright (c) 1982, 1986, 1991, 1993
    6  *      The Regents of the University of California.  All rights reserved.
    7  * (c) UNIX System Laboratories, Inc.
    8  * All or some portions of this file are derived from material licensed
    9  * to the University of California by American Telephone and Telegraph
   10  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
   11  * the permission of UNIX System Laboratories, Inc.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  *
   37  *      @(#)kern_clock.c        8.5 (Berkeley) 1/21/94
   38  */
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/timeout.h>
   43 #include <sys/kernel.h>
   44 #include <sys/limits.h>
   45 #include <sys/proc.h>
   46 #include <sys/user.h>
   47 #include <sys/resourcevar.h>
   48 #include <sys/sysctl.h>
   49 #include <sys/sched.h>
   50 #include <sys/timetc.h>
   51 
   52 #if defined(GPROF) || defined(DDBPROF)
   53 #include <sys/gmon.h>
   54 #endif
   55 
   56 #include "dt.h"
   57 #if NDT > 0
   58 #include <dev/dt/dtvar.h>
   59 #endif
   60 
   61 /*
   62  * Clock handling routines.
   63  *
   64  * This code is written to operate with two timers that run independently of
   65  * each other.  The main clock, running hz times per second, is used to keep
   66  * track of real time.  The second timer handles kernel and user profiling,
   67  * and does resource use estimation.  If the second timer is programmable,
   68  * it is randomized to avoid aliasing between the two clocks.  For example,
   69  * the randomization prevents an adversary from always giving up the cpu
   70  * just before its quantum expires.  Otherwise, it would never accumulate
   71  * cpu ticks.  The mean frequency of the second timer is stathz.
   72  *
   73  * If no second timer exists, stathz will be zero; in this case we drive
   74  * profiling and statistics off the main clock.  This WILL NOT be accurate;
   75  * do not do it unless absolutely necessary.
   76  *
   77  * The statistics clock may (or may not) be run at a higher rate while
   78  * profiling.  This profile clock runs at profhz.  We require that profhz
   79  * be an integral multiple of stathz.
   80  *
   81  * If the statistics clock is running fast, it must be divided by the ratio
   82  * profhz/stathz for statistics.  (For profiling, every tick counts.)
   83  */
   84 
   85 int     stathz;
   86 int     schedhz;
   87 int     profhz;
   88 int     profprocs;
   89 int     ticks;
   90 static int psdiv, pscnt;                /* prof => stat divider */
   91 int     psratio;                        /* ratio: prof / stat */
   92 
   93 volatile unsigned long jiffies;         /* XXX Linux API for drm(4) */
   94 
   95 /*
   96  * Initialize clock frequencies and start both clocks running.
   97  */
   98 void
   99 initclocks(void)
  100 {
  101         int i;
  102 
  103         ticks = INT_MAX - (15 * 60 * hz);
  104         jiffies = ULONG_MAX - (10 * 60 * hz);
  105 
  106         /*
  107          * Set divisors to 1 (normal case) and let the machine-specific
  108          * code do its bit.
  109          */
  110         psdiv = pscnt = 1;
  111         cpu_initclocks();
  112 
  113         /*
  114          * Compute profhz/stathz, and fix profhz if needed.
  115          */
  116         i = stathz ? stathz : hz;
  117         if (profhz == 0)
  118                 profhz = i;
  119         psratio = profhz / i;
  120 
  121         inittimecounter();
  122 }
  123 
  124 /*
  125  * hardclock does the accounting needed for ITIMER_PROF and ITIMER_VIRTUAL.
  126  * We don't want to send signals with psignal from hardclock because it makes
  127  * MULTIPROCESSOR locking very complicated. Instead, to use an idea from
  128  * FreeBSD, we set a flag on the thread and when it goes to return to
  129  * userspace it signals itself.
  130  */
  131 
  132 /*
  133  * The real-time timer, interrupting hz times per second.
  134  */
  135 void
  136 hardclock(struct clockframe *frame)
  137 {
  138         struct proc *p;
  139         struct cpu_info *ci = curcpu();
  140 
  141         p = curproc;
  142         if (p && ((p->p_flag & (P_SYSTEM | P_WEXIT)) == 0)) {
  143                 struct process *pr = p->p_p;
  144 
  145                 /*
  146                  * Run current process's virtual and profile time, as needed.
  147                  */
  148                 if (CLKF_USERMODE(frame) &&
  149                     timespecisset(&pr->ps_timer[ITIMER_VIRTUAL].it_value) &&
  150                     itimerdecr(&pr->ps_timer[ITIMER_VIRTUAL], tick_nsec) == 0) {
  151                         atomic_setbits_int(&p->p_flag, P_ALRMPEND);
  152                         need_proftick(p);
  153                 }
  154                 if (timespecisset(&pr->ps_timer[ITIMER_PROF].it_value) &&
  155                     itimerdecr(&pr->ps_timer[ITIMER_PROF], tick_nsec) == 0) {
  156                         atomic_setbits_int(&p->p_flag, P_PROFPEND);
  157                         need_proftick(p);
  158                 }
  159         }
  160 
  161         /*
  162          * If no separate statistics clock is available, run it from here.
  163          */
  164         if (stathz == 0)
  165                 statclock(frame);
  166 
  167         if (--ci->ci_schedstate.spc_rrticks <= 0)
  168                 roundrobin(ci);
  169 
  170 #if NDT > 0
  171         DT_ENTER(profile, NULL);
  172         if (CPU_IS_PRIMARY(ci))
  173                 DT_ENTER(interval, NULL);
  174 #endif
  175 
  176         /*
  177          * If we are not the primary CPU, we're not allowed to do
  178          * any more work.
  179          */
  180         if (CPU_IS_PRIMARY(ci) == 0)
  181                 return;
  182 
  183         tc_ticktock();
  184         ticks++;
  185         jiffies++;
  186 
  187         /*
  188          * Update the timeout wheel.
  189          */
  190         timeout_hardclock_update();
  191 }
  192 
  193 /*
  194  * Compute number of hz in the specified amount of time.
  195  */
  196 int
  197 tvtohz(const struct timeval *tv)
  198 {
  199         unsigned long nticks;
  200         time_t sec;
  201         long usec;
  202 
  203         /*
  204          * If the number of usecs in the whole seconds part of the time
  205          * fits in a long, then the total number of usecs will
  206          * fit in an unsigned long.  Compute the total and convert it to
  207          * ticks, rounding up and adding 1 to allow for the current tick
  208          * to expire.  Rounding also depends on unsigned long arithmetic
  209          * to avoid overflow.
  210          *
  211          * Otherwise, if the number of ticks in the whole seconds part of
  212          * the time fits in a long, then convert the parts to
  213          * ticks separately and add, using similar rounding methods and
  214          * overflow avoidance.  This method would work in the previous
  215          * case but it is slightly slower and assumes that hz is integral.
  216          *
  217          * Otherwise, round the time down to the maximum
  218          * representable value.
  219          *
  220          * If ints have 32 bits, then the maximum value for any timeout in
  221          * 10ms ticks is 248 days.
  222          */
  223         sec = tv->tv_sec;
  224         usec = tv->tv_usec;
  225         if (sec < 0 || (sec == 0 && usec <= 0))
  226                 nticks = 0;
  227         else if (sec <= LONG_MAX / 1000000)
  228                 nticks = (sec * 1000000 + (unsigned long)usec + (tick - 1))
  229                     / tick + 1;
  230         else if (sec <= LONG_MAX / hz)
  231                 nticks = sec * hz
  232                     + ((unsigned long)usec + (tick - 1)) / tick + 1;
  233         else
  234                 nticks = LONG_MAX;
  235         if (nticks > INT_MAX)
  236                 nticks = INT_MAX;
  237         return ((int)nticks);
  238 }
  239 
  240 int
  241 tstohz(const struct timespec *ts)
  242 {
  243         struct timeval tv;
  244         TIMESPEC_TO_TIMEVAL(&tv, ts);
  245 
  246         /* Round up. */
  247         if ((ts->tv_nsec % 1000) != 0) {
  248                 tv.tv_usec += 1;
  249                 if (tv.tv_usec >= 1000000) {
  250                         tv.tv_usec -= 1000000;
  251                         tv.tv_sec += 1;
  252                 }
  253         }
  254 
  255         return (tvtohz(&tv));
  256 }
  257 
  258 /*
  259  * Start profiling on a process.
  260  *
  261  * Kernel profiling passes proc0 which never exits and hence
  262  * keeps the profile clock running constantly.
  263  */
  264 void
  265 startprofclock(struct process *pr)
  266 {
  267         int s;
  268 
  269         if ((pr->ps_flags & PS_PROFIL) == 0) {
  270                 atomic_setbits_int(&pr->ps_flags, PS_PROFIL);
  271                 if (++profprocs == 1 && stathz != 0) {
  272                         s = splstatclock();
  273                         psdiv = pscnt = psratio;
  274                         setstatclockrate(profhz);
  275                         splx(s);
  276                 }
  277         }
  278 }
  279 
  280 /*
  281  * Stop profiling on a process.
  282  */
  283 void
  284 stopprofclock(struct process *pr)
  285 {
  286         int s;
  287 
  288         if (pr->ps_flags & PS_PROFIL) {
  289                 atomic_clearbits_int(&pr->ps_flags, PS_PROFIL);
  290                 if (--profprocs == 0 && stathz != 0) {
  291                         s = splstatclock();
  292                         psdiv = pscnt = 1;
  293                         setstatclockrate(stathz);
  294                         splx(s);
  295                 }
  296         }
  297 }
  298 
  299 /*
  300  * Statistics clock.  Grab profile sample, and if divider reaches 0,
  301  * do process and kernel statistics.
  302  */
  303 void
  304 statclock(struct clockframe *frame)
  305 {
  306 #if defined(GPROF) || defined(DDBPROF)
  307         struct gmonparam *g;
  308         u_long i;
  309 #endif
  310         struct cpu_info *ci = curcpu();
  311         struct schedstate_percpu *spc = &ci->ci_schedstate;
  312         struct proc *p = curproc;
  313         struct process *pr;
  314 
  315         /*
  316          * Notice changes in divisor frequency, and adjust clock
  317          * frequency accordingly.
  318          */
  319         if (spc->spc_psdiv != psdiv) {
  320                 spc->spc_psdiv = psdiv;
  321                 spc->spc_pscnt = psdiv;
  322                 if (psdiv == 1) {
  323                         setstatclockrate(stathz);
  324                 } else {
  325                         setstatclockrate(profhz);
  326                 }
  327         }
  328 
  329         if (CLKF_USERMODE(frame)) {
  330                 pr = p->p_p;
  331                 if (pr->ps_flags & PS_PROFIL)
  332                         addupc_intr(p, CLKF_PC(frame));
  333                 if (--spc->spc_pscnt > 0)
  334                         return;
  335                 /*
  336                  * Came from user mode; CPU was in user state.
  337                  * If this process is being profiled record the tick.
  338                  */
  339                 p->p_uticks++;
  340                 if (pr->ps_nice > NZERO)
  341                         spc->spc_cp_time[CP_NICE]++;
  342                 else
  343                         spc->spc_cp_time[CP_USER]++;
  344         } else {
  345 #if defined(GPROF) || defined(DDBPROF)
  346                 /*
  347                  * Kernel statistics are just like addupc_intr, only easier.
  348                  */
  349                 g = ci->ci_gmon;
  350                 if (g != NULL && g->state == GMON_PROF_ON) {
  351                         i = CLKF_PC(frame) - g->lowpc;
  352                         if (i < g->textsize) {
  353                                 i /= HISTFRACTION * sizeof(*g->kcount);
  354                                 g->kcount[i]++;
  355                         }
  356                 }
  357 #endif
  358                 if (p != NULL && p->p_p->ps_flags & PS_PROFIL)
  359                         addupc_intr(p, PROC_PC(p));
  360                 if (--spc->spc_pscnt > 0)
  361                         return;
  362                 /*
  363                  * Came from kernel mode, so we were:
  364                  * - spinning on a lock
  365                  * - handling an interrupt,
  366                  * - doing syscall or trap work on behalf of the current
  367                  *   user process, or
  368                  * - spinning in the idle loop.
  369                  * Whichever it is, charge the time as appropriate.
  370                  * Note that we charge interrupts to the current process,
  371                  * regardless of whether they are ``for'' that process,
  372                  * so that we know how much of its real time was spent
  373                  * in ``non-process'' (i.e., interrupt) work.
  374                  */
  375                 if (CLKF_INTR(frame)) {
  376                         if (p != NULL)
  377                                 p->p_iticks++;
  378                         spc->spc_cp_time[spc->spc_spinning ?
  379                             CP_SPIN : CP_INTR]++;
  380                 } else if (p != NULL && p != spc->spc_idleproc) {
  381                         p->p_sticks++;
  382                         spc->spc_cp_time[spc->spc_spinning ?
  383                             CP_SPIN : CP_SYS]++;
  384                 } else
  385                         spc->spc_cp_time[spc->spc_spinning ?
  386                             CP_SPIN : CP_IDLE]++;
  387         }
  388         spc->spc_pscnt = psdiv;
  389 
  390         if (p != NULL) {
  391                 p->p_cpticks++;
  392                 /*
  393                  * If no schedclock is provided, call it here at ~~12-25 Hz;
  394                  * ~~16 Hz is best
  395                  */
  396                 if (schedhz == 0) {
  397                         if ((++spc->spc_schedticks & 3) == 0)
  398                                 schedclock(p);
  399                 }
  400         }
  401 }
  402 
  403 /*
  404  * Return information about system clocks.
  405  */
  406 int
  407 sysctl_clockrate(char *where, size_t *sizep, void *newp)
  408 {
  409         struct clockinfo clkinfo;
  410 
  411         /*
  412          * Construct clockinfo structure.
  413          */
  414         memset(&clkinfo, 0, sizeof clkinfo);
  415         clkinfo.tick = tick;
  416         clkinfo.hz = hz;
  417         clkinfo.profhz = profhz;
  418         clkinfo.stathz = stathz ? stathz : hz;
  419         return (sysctl_rdstruct(where, sizep, newp, &clkinfo, sizeof(clkinfo)));
  420 }

Cache object: 9a1093a902a8cb913ddb918276852764


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