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 + -
显示快捷键?