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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: kern_microtime.c,v 1.4.4.2 2004/07/04 12:34:32 he 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.4.4.2 2004/07/04 12:34:32 he 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 struct timeval cc_microset_time;
   70 
   71 /*
   72  * Return the best possible estimate of the time in the timeval to which
   73  * tvp points.  The kernel logical time variable is interpolated between
   74  * ticks by reading the CC to determine the number of cycles since the
   75  * last processor update, then converting the result to microseconds.  In
   76  * the case of multiprocessor systems, the interpolation is specific to
   77  * each processor, since each processor has its own CC.
   78  */
   79 void
   80 cc_microtime(struct timeval *tvp)
   81 {
   82         static struct timeval lasttime;
   83         static struct simplelock microtime_slock = SIMPLELOCK_INITIALIZER;
   84         struct timeval t;
   85         struct cpu_info *ci = curcpu();
   86         int64_t cc, sec, usec;
   87         int s;
   88 
   89 #ifdef MULTIPROCESSOR
   90         s = splipi();           /* also blocks IPIs */
   91 #else
   92         s = splclock();         /* block clock interrupts */
   93 #endif
   94 
   95         if (ci->ci_cc_denom != 0) {
   96                 /*
   97                  * Determine the current clock time as the time at last
   98                  * microset() call, plus the CC accumulation since then.
   99                  * This time should lie in the interval between the current
  100                  * master clock time and the time at the next tick, but
  101                  * this code does not explicitly require that in the interest
  102                  * of speed.  If something ugly occurs, like a settimeofday()
  103                  * call, the processors may disagree among themselves for not
  104                  * more than the interval between microset() calls.  In any
  105                  * case, the following sanity checks will suppress timewarps.
  106                  */
  107                 simple_lock(&microtime_slock);
  108                 t = ci->ci_cc_time;
  109                 cc = cpu_counter32() - ci->ci_cc_cc;
  110                 if (cc < 0)
  111                         cc += 0x100000000LL;
  112                 t.tv_usec += (cc * ci->ci_cc_ms_delta) / ci->ci_cc_denom;
  113                 while (t.tv_usec >= 1000000) {
  114                         t.tv_usec -= 1000000;
  115                         t.tv_sec++;
  116                 }
  117         } else {
  118                 /*
  119                  * Can't use the CC -- just use the system time.
  120                  */
  121                 /* XXXSMP: not atomic */
  122                 simple_lock(&microtime_slock);
  123                 t = time;
  124         }
  125 
  126         /*
  127          * Ordinarily, the current clock time is guaranteed to be later
  128          * by at least one microsecond than the last time the clock was
  129          * read.  However, this rule applies only if the current time is
  130          * within one second of the last time.  Otherwise, the clock will
  131          * (shudder) be set backward.  The clock adjustment daemon or
  132          * human equivalent is presumed to be correctly implemented and
  133          * to set the clock backward only upon unavoidable crisis.
  134          */
  135         sec = lasttime.tv_sec - t.tv_sec;
  136         usec = lasttime.tv_usec - t.tv_usec;
  137         if (usec < 0) {
  138                 usec += 1000000;
  139                 sec--;
  140         }
  141         if (sec == 0 && usec > 0)  {
  142                 t.tv_usec += usec + 1;
  143                 if (t.tv_usec >= 1000000) {
  144                         t.tv_usec -= 1000000;
  145                         t.tv_sec++;
  146                 }
  147         }
  148         lasttime = t;
  149         simple_unlock(&microtime_slock);
  150 
  151         splx(s);
  152 
  153         *tvp = t;
  154 }
  155 
  156 /*
  157  * This routine is called about once per second directly by the master
  158  * processor and via an interprocessor interrupt for other processors.
  159  * It determines the CC frequency of each processor relative to the
  160  * master clock and the time this determination is made.  These values
  161  * are used by microtime() to interpolate the microseconds between
  162  * timer interrupts.  Note that we assume the kernel variables have
  163  * been zeroed early in life.
  164  */
  165 void
  166 cc_microset(struct cpu_info *ci)
  167 {
  168         struct timeval t;
  169         int64_t delta, denom;
  170 
  171         /* Note: Clock interrupts are already blocked. */
  172 
  173         denom = ci->ci_cc_cc;
  174         t = cc_microset_time;           /* XXXSMP: not atomic */
  175         ci->ci_cc_cc = cpu_counter32();
  176 
  177         if (ci->ci_cc_denom == 0) {
  178                 /*
  179                  * This is our first time here on this CPU.  Just
  180                  * start with reasonable initial values.
  181                  */
  182                 ci->ci_cc_time = t;
  183                 ci->ci_cc_ms_delta = 1000000;
  184                 ci->ci_cc_denom = cpu_frequency(ci);
  185                 return;
  186         }
  187 
  188         denom = ci->ci_cc_cc - denom;
  189         if (denom < 0)
  190                 denom += 0x100000000LL;
  191 
  192         delta = (t.tv_sec - ci->ci_cc_time.tv_sec) * 1000000 +
  193             (t.tv_usec - ci->ci_cc_time.tv_usec);
  194 
  195         ci->ci_cc_time = t;
  196         /*
  197          * Make sure it's within .5 to 1.5 seconds -- otherwise,
  198          * the time is probably be frobbed with by the timekeeper
  199          * or the human.
  200          */
  201         if (delta > 500000 && delta < 1500000) {
  202                 ci->ci_cc_ms_delta = delta;
  203                 ci->ci_cc_denom = denom;
  204 #if 0
  205                 printf("cc_microset: delta %" PRId64 ", denom %" PRId64 "\n",
  206                        delta, denom);
  207 #endif
  208         } else {
  209 #if 0
  210                 printf("cc_microset: delta %" PRId64 ", resetting state\n",
  211                        delta);
  212 #endif
  213                 ci->ci_cc_ms_delta = 1000000;
  214                 ci->ci_cc_denom = cpu_frequency(ci);
  215         }
  216 }

Cache object: 297c5b697cbe50ed4d028c04d902bf14


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