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_microtime.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: kern_microtime.c,v 1.16 2006/06/07 22:33:40 kardel Exp $       */
    2 
    3 /*-
    4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the NetBSD
   21  *      Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /******************************************************************************
   40  *                                                                            *
   41  * Copyright (c) David L. Mills 1993, 1994                                    *
   42  *                                                                            *
   43  * Permission to use, copy, modify, and distribute this software and its      *
   44  * documentation for any purpose and without fee is hereby granted, provided  *
   45  * that the above copyright notice appears in all copies and that both the    *
   46  * copyright notice and this permission notice appear in supporting           *
   47  * documentation, and that the name University of Delaware not be used in     *
   48  * advertising or publicity pertaining to distribution of the software        *
   49  * without specific, written prior permission.  The University of Delaware    *
   50  * makes no representations about the suitability this software for any       *
   51  * purpose.  It is provided "as is" without express or implied warranty.      *
   52  *                                                                            *
   53  ******************************************************************************/
   54 
   55 #include <sys/cdefs.h>                  /* RCS ID & Copyright macro defns */
   56 
   57 __KERNEL_RCSID(0, "$NetBSD: kern_microtime.c,v 1.16 2006/06/07 22:33:40 kardel Exp $");
   58 
   59 #include "opt_multiprocessor.h"
   60 
   61 #include <sys/param.h>
   62 #include <sys/systm.h>
   63 #include <sys/kernel.h>
   64 #include <sys/lock.h>
   65 
   66 #include <machine/cpu.h>
   67 #include <machine/cpu_counter.h>
   68 
   69 /* XXX compat definitions */
   70 #define ci_cc_time      ci_cc.cc_time
   71 #define ci_cc_cc        ci_cc.cc_cc
   72 #define ci_cc_ms_delta  ci_cc.cc_ms_delta
   73 #define ci_cc_denom     ci_cc.cc_denom
   74 
   75 struct timeval cc_microset_time;
   76 
   77 /*
   78  * Return the best possible estimate of the time in the timeval to which
   79  * tvp points.  The kernel logical time variable is interpolated between
   80  * ticks by reading the CC to determine the number of cycles since the
   81  * last processor update, then converting the result to microseconds.  In
   82  * the case of multiprocessor systems, the interpolation is specific to
   83  * each processor, since each processor has its own CC.
   84  */
   85 void
   86 cc_microtime(struct timeval *tvp)
   87 {
   88         static struct timeval lasttime;
   89         static struct simplelock microtime_slock = SIMPLELOCK_INITIALIZER;
   90         struct timeval t;
   91         struct cpu_info *ci = curcpu();
   92         int64_t cc, sec, usec;
   93         int s;
   94 
   95 #ifdef MULTIPROCESSOR
   96         s = splipi();           /* also blocks IPIs */
   97 #else
   98         s = splclock();         /* block clock interrupts */
   99 #endif
  100 
  101         if (ci->ci_cc_denom != 0) {
  102                 /*
  103                  * Determine the current clock time as the time at last
  104                  * microset() call, plus the CC accumulation since then.
  105                  * This time should lie in the interval between the current
  106                  * master clock time and the time at the next tick, but
  107                  * this code does not explicitly require that in the interest
  108                  * of speed.  If something ugly occurs, like a settimeofday()
  109                  * call, the processors may disagree among themselves for not
  110                  * more than the interval between microset() calls.  In any
  111                  * case, the following sanity checks will suppress timewarps.
  112                  */
  113                 simple_lock(&microtime_slock);
  114                 t = ci->ci_cc_time;
  115                 cc = cpu_counter32() - ci->ci_cc_cc;
  116                 if (cc < 0)
  117                         cc += 0x100000000LL;
  118                 t.tv_usec += (cc * ci->ci_cc_ms_delta) / ci->ci_cc_denom;
  119                 while (t.tv_usec >= 1000000) {
  120                         t.tv_usec -= 1000000;
  121                         t.tv_sec++;
  122                 }
  123         } else {
  124                 /*
  125                  * Can't use the CC -- just use the system time.
  126                  */
  127                 /* XXXSMP: not atomic */
  128                 simple_lock(&microtime_slock);
  129                 getmicrotime(&t);
  130         }
  131 
  132         /*
  133          * Ordinarily, the current clock time is guaranteed to be later
  134          * by at least one microsecond than the last time the clock was
  135          * read.  However, this rule applies only if the current time is
  136          * within one second of the last time.  Otherwise, the clock will
  137          * (shudder) be set backward.  The clock adjustment daemon or
  138          * human equivalent is presumed to be correctly implemented and
  139          * to set the clock backward only upon unavoidable crisis.
  140          */
  141         sec = lasttime.tv_sec - t.tv_sec;
  142         usec = lasttime.tv_usec - t.tv_usec;
  143         if (usec < 0) {
  144                 usec += 1000000;
  145                 sec--;
  146         }
  147         if (sec == 0 && usec > 0)  {
  148                 t.tv_usec += usec + 1;
  149                 if (t.tv_usec >= 1000000) {
  150                         t.tv_usec -= 1000000;
  151                         t.tv_sec++;
  152                 }
  153         }
  154         lasttime = t;
  155         simple_unlock(&microtime_slock);
  156 
  157         splx(s);
  158 
  159         *tvp = t;
  160 }
  161 
  162 /*
  163  * This routine is called about once per second directly by the master
  164  * processor and via an interprocessor interrupt for other processors.
  165  * It determines the CC frequency of each processor relative to the
  166  * master clock and the time this determination is made.  These values
  167  * are used by microtime() to interpolate the microseconds between
  168  * timer interrupts.  Note that we assume the kernel variables have
  169  * been zeroed early in life.
  170  */
  171 void
  172 cc_microset(struct cpu_info *ci)
  173 {
  174         struct timeval t;
  175         int64_t delta, denom;
  176 
  177         /* Note: Clock interrupts are already blocked. */
  178 
  179         denom = ci->ci_cc_cc;
  180         t = cc_microset_time;           /* XXXSMP: not atomic */
  181         ci->ci_cc_cc = cpu_counter32();
  182 
  183         if (ci->ci_cc_denom == 0) {
  184                 /*
  185                  * This is our first time here on this CPU.  Just
  186                  * start with reasonable initial values.
  187                  */
  188                 ci->ci_cc_time = t;
  189                 ci->ci_cc_ms_delta = 1000000;
  190                 ci->ci_cc_denom = cpu_frequency(ci);
  191                 return;
  192         }
  193 
  194         denom = ci->ci_cc_cc - denom;
  195         if (denom < 0)
  196                 denom += 0x100000000LL;
  197 
  198         delta = (t.tv_sec - ci->ci_cc_time.tv_sec) * 1000000 +
  199             (t.tv_usec - ci->ci_cc_time.tv_usec);
  200 
  201         ci->ci_cc_time = t;
  202         /*
  203          * Make sure it's within .5 to 1.5 seconds -- otherwise,
  204          * the time is probably be frobbed with by the timekeeper
  205          * or the human.
  206          */
  207         if (delta > 500000 && delta < 1500000) {
  208                 ci->ci_cc_ms_delta = delta;
  209                 ci->ci_cc_denom = denom;
  210 #if 0
  211                 printf("cc_microset[%lu]: delta %" PRId64
  212                     ", denom %" PRId64 "\n", ci->ci_cpuid, delta, denom);
  213 #endif
  214         } else {
  215 #if 0
  216                 printf("cc_microset[%lu]: delta %" PRId64 ", resetting state\n",
  217                        (u_long)ci->ci_cpuid, delta);
  218 #endif
  219                 ci->ci_cc_ms_delta = 1000000;
  220                 ci->ci_cc_denom = cpu_frequency(ci);
  221         }
  222 }

Cache object: ff3d4d4bf96bd1e671c18bdb0ea912b8


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