rfc1589.txt

来自「著名的RFC文档,其中有一些文档是已经翻译成中文的的.」· 文本 代码 · 共 1,332 行 · 第 1/5 页

TXT
1,332
字号
      It is a design feature of the NTP architecture that the system      clocks in a synchronization subnet are to read the same or nearly      the same values before during and after a leap-second event, as      declared by national standards bodies. The new model is designed      to implement the leap event upon command by an ntp_adjtime()      argument. The intricate and sometimes arcane details of the model      and implementation are discussed in [3] and [5]. Further details      are given in the technical summary later in this memorandum.3. Technical Summary   In order to more fully understand the workings of the model, a stand-   alone simulator kern.c and header file timex.h are included in the   kernel.tar.Z distribution mentioned previously. In addition, a   complete C program kern_ntptime.c which implements the ntp_gettime()   and ntp_adjtime() functions is provided, but with the vendor-specific   argument-passing code deleted. Since the distribution is somewhat   large, due to copious comments and ornamentation, it is impractical   to include a listing of these programs in this memorandum. In any   case, implementors may choose to snip portions of the simulator for   use in new kernel designs, but, due to formatting conventions, this   would be difficult if included in this memorandum.Mills                                                          [Page 10]RFC 1589         Kernel Model for Precision Timekeeping       March 1994   The kern.c program is an implementation of an adaptive-parameter,   first-order, type-II phase-lock loop. The system clock is implemented   using a set of variables and algorithms defined in the simulator and   driven by explicit offsets generated by a driver program also   included in the program. The algorithms include code fragments almost   identical to those in the machine-specific kernel implementations and   operate in the same way, but the operations can be understood   separately from any licensed source code into which these fragments   may be integrated. The code fragments themselves are not derived from   any licensed code. The following discussion assumes that the   simulator code is available for inspection.   3.1. PLL Simulation      The simulator operates in conformance with the analytical model      described in [3]. The main() program operates as a driver for the      fragments hardupdate(), hardclock(), second_overflow(), hardpps()      and microtime(), although not all functions implemented in these      fragments are simulated. The program simulates the PLL at each      timer interrupt and prints a summary of critical program variables      at each time update.      There are three defined options in the kernel configuration file      specific to each implementation. The PPS_SYNC option provides      support for a pulse-per-second (PPS) signal, which is used to      discipline the frequency of the CPU clock oscillator. The      EXT_CLOCK option provides support for an external kernel-readable      clock, such as the KSI/Odetics TPRO IRIG interface or HIGHBALL      precision oscillator, both for the SBus. The TPRO option provides      support for the former, while the HIGHBALL option provides support      for the latter. External clocks are implemented as the microtime()      clock driver, with the specific source code selected by the kernel      configuration file.      3.1.1. The hardupdate() Fragment         The hardupdate() fragment is called by ntp_adjtime() as each         update is computed to adjust the system clock phase and         frequency. Note that the time constant is in units of powers of         two, so that multiplies can be done by simple shifts. The phase         variable is computed as the offset divided by the time         constant. Then, the time since the last update is computed and         clamped to a maximum (for robustness) and to zero if         initializing. The offset is multiplied (sorry about the ugly         multiply) by the result and divided by the square of the time         constant and then added to the frequency variable. Note that         all shifts are assumed to be positive and that a shift of a         signed quantity to the right requires a little dance.Mills                                                          [Page 11]RFC 1589         Kernel Model for Precision Timekeeping       March 1994         With the defines given, the maximum time offset is determined         by the size in bits of the long type (32 or 64) less the         SHIFT_UPDATE scale factor (12) or at least 20 bits (signed).         The scale factor is chosen so that there is no loss of         significance in later steps, which may involve a right shift up         to SHIFT_UPDATE bits. This results in a time adjustment range         over +-512 ms. Since time_constant must be greater than or         equal to zero, the maximum frequency offset is determined by         the SHIFT_USEC scale factor (16) or at least 16 bits (signed).         This results in a frequency adjustment range over +-31,500 ppm.         In the addition step, the value of offset * mtemp is not         greater than MAXPHASE * MAXSEC = 31 bits (signed), which will         not overflow a long add on a 32-bit machine. There could be a         loss of precision due to the right shift of up to 12 bits,         since time_constant is bounded at 6. This results in a net         worst-case frequency resolution of about .063 ppm, which is not         significant for most quartz oscillators. The worst case could         be realized only if the NTP peer misbehaves according to the         protocol specification.         The time_offset value is clamped upon entry. The time_phase         variable is an accumulator, so is clamped to the tolerance on         every call. This helps to damp transients before the oscillator         frequency has been determined, as well as to satisfy the         correctness assertions if the time synchronization protocol or         implementation misbehaves.      3.1.2. The hardclock() Fragment         The hardclock() fragment is inserted in the hardware timer         interrupt routine at the point the system clock is to be         incremented. Previous to this fragment the time_update variable         has been initialized to the value computed by the adjtime()         system call in the stock Unix kernel, normally plus/minus the         tickadj value, which is usually in the order of 5 us. The         time_phase variable, which represents the instantaneous phase         of the system clock, is advanced by time_adj, which is         calculated in the second_overflow() fragment described below.         If the value of time_phase exceeds 1 us in scaled units,         time_update is increased by the (signed) excess and time_phase         retains the residue.         Except in the case of an external oscillator such as the         HIGHBALL interface, the hardclock() fragment advances the         system clock by the value of tick plus time_update. However, in         the case of an external oscillator, the system clock is         obtained directly from the interface and time_update used toMills                                                          [Page 12]RFC 1589         Kernel Model for Precision Timekeeping       March 1994         discipline that interface instead. However, the system clock         must still be disciplined as explained previously, so the value         of clock_cpu computed by the second_overflow() fragment is used         instead.      3.1.3. The second_overflow() Fragment         The second_overflow() fragment is inserted at the point where         the microseconds field of the system time variable is being         checked for overflow. Upon overflow the maximum error         time_maxerror is increased by time_tolerance to reflect the         maximum time offset due to oscillator frequency error. Then,         the increment time_adj to advance the kernel time variable is         calculated from the (scaled) time_offset and time_freq         variables updated at the last call to the hardclock() fragment.         The phase adjustment is calculated as a (signed) fraction of         the time_offset remaining, where the fraction is added to         time_adj, then subtracted from time_offset. This technique         provides a rapid convergence when offsets are high, together         with good resolution when offsets are low. The frequency         adjustment is the sum of the (scaled) time_freq variable, an         adjustment necessary when the tick interval does not evenly         divide one second fixtick and PPS frequency adjustment pps_ybar         (if configured).         The scheme of approximating exact multiply/divide operations         with shifts produces good results, except when an exact         calculation is required, such as when the PPS signal is being         used to discipling the CPU clock oscillator frequency, as         described below. As long as the actual oscillator frequency is         a power of two in seconds, no correction is required. However,         in the SunOS kernel the clock frequency is 100 Hz, which         results in an error factor of 0.78. In this case the code         increases time_adj by a factor of 1.25, which results in an         overall error less than three percent.         On rollover of the day, the leap-second state machine described         below  determines whether a second is to be inserted or deleted         in the timescale. The microtime() routine insures that the         reported time is always monotonically increasing.      3.1.4. The hardpps() Fragment         The hardpps() fragment is operative only if the PPS_SYNC option         is specified in the kernel configuration file. It is called         from the serial port driver or equivalent interface at the on-         time transition of the PPS signal. The fragment operates as aMills                                                          [Page 13]RFC 1589         Kernel Model for Precision Timekeeping       March 1994         first-order, type-I frequency-lock loop (FLL) controlled by the         difference between the frequency represented by the pps_ybar         variable and the frequency of the hardware clock oscillator.         In order to avoid calling the microtime() routine more than         once for each PPS transition, the interface requires the         calling program to capture the system time and hardware counter         contents at the on-time transition of the PPS signal and         provide a pointer to the timestamp (Unix timeval) and counter         contents as arguments to the hardpps() call. The hardware         counter contents can be determined by saving the microseconds         field of the system time, calling the microtime() routine, and         subtracting the saved value. If a counter overflow has occured         during the process, the resulting microseconds value will be         negative, in which case the caller adds 1000000 to normalize         the microseconds field.         The frequency of the hardware oscillator can be determined from         the difference in hardware counter readings at the beginning         and end of the calibration interval divided by the duration of         the interval. However, the oscillator frequency tolerance, as         much as 100 ppm, may cause the difference to exceed the tick         value, creating an ambiguity. In order to avoid this ambiguity,         the hardware counter value at the beginning of the interval is         increased by the current pps_ybar value once each second, but         computed modulo the tick value. At the end of the interval, the         difference between this value and the value computed from the         hardware counter is used as a control signal sample for the         FLL.         Control signal samples which exceed the frequency tolerance are         discarded, as well as samples resulting from excessive interval         duration jitter. Surviving samples are then processed by a         three-stage median filter. The signal which drives the FLL is         derived from the median sample, while the average of         differences between the other two samples is used as a measure         of dispersion. If the dispersion is below the threshold         pps_dispmax, the median is used to correct the pps_ybar value         with a weight expressed as a shift PPS_AVG (2). In addition to         the averaging function, pps_disp is increased by the amount         pps_dispinc once each second. The result is that, should the         dispersion be exceptionally high, or if the PPS signal fails         for some reason, the pps_disp will eventually exceed         pps_dispmax and raise an alarm.         Initially, an approximate value for pps_ybar is not known, so         the duration of the calibration interval must be kept small to         avoid overflowing the tick. The time difference at the end ofMills                                                          [Page 14]RFC 1589         Kernel Model for Precision Timekeeping       March 1994         the calibration interval is measured. If greater than a         fraction tick/4, the interval is reduced by half. If less than         this fraction for four successive calibration intervals, the         interval is doubled. This design automatically adapts to         nominal jitter in the PPS signal, as well as the value of tick.         The duration of the calibration interval is set by the         pps_shift variable as a shift in powers of two. The minimum         value PPS_SHIFT (2) is chosen so that with the highest CPU         oscillator frequency 1024 Hz and frequency tolerance 100 ppm         the tick will not overflow. The maximum value PPS_SHIFTMAX (8)         is chosen such that the maximum averaging time is about 1000 s

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?