More time clean up stuff.
PATCH 1/1 More time clean up stuff.
This patch addresses issues of roundoff error in the time keeping and NTP code as follows:
The conversion of "actual jiffies" to TICK_USEC and then to TICK_NSEC introduced large errors if jiffies was not a power of 10 (e.g. 1024 for the ia64). Most of this is avoided by converting directly to TICK_NSEC.
The calculation of MAX_SEC_IN_JIFFIES (the largest timespec or timeval the kernel will attempt) had overflow problems in the 64-bit machines.
We introduce a different equation for those machines.
The NTP frequency update code was allowing a micro second of error to accumulate before applying the correction. We change FINEUSEC to FINENSEC to do the correction as soon as a full nanosecond has accumulated.
The initial calculation of time_freq for NTP had severe roundoff errors for HZ not a power of 10 (i.e. 1024). A new equation fixes this.
clock_nanosleep is changed to round up to the next jiffie to cover starting between jiffies.
(Note, this patch depends on the prior timeclean up patch of this date.)
Signature · 3 lines
George Anzinger [email protected] High-res-timers: http://sourceforge.net/projects/high-res-timers/ Preemption patch: http://www.kernel.org/pub/linux/kernel/people/rml
arch/i386/kernel/time.c +1 -1
@@ -127,7 +127,7 @@* made, and then undo it! */ tv->tv_nsec -= timer->get_offset () *NSEC_PER_USEC ; - tv->tv_nsec -= (jiffies - wall_jiffies) *TICK_NSEC (TICK_USEC ); + tv->tv_nsec -= (jiffies - wall_jiffies) *TICK_NSEC ;while (tv->tv_nsec <0 ) { tv->tv_nsec +=NSEC_PER_SEC ;
include/asm-i386/mach-pc9800/setup_arch_pre.h +1 -1
@@ -26,7 +26,7 @@CLOCK_TICK_RATE =PC9800_8MHz_P () ?1996800 :2457600 ;printk (KERN_DEBUG "CLOCK_TICK_RATE = %d\n" ,CLOCK_TICK_RATE ); tick_usec =TICK_USEC ;/* ACTHZ period (usec) */ - tick_nsec =TICK_NSEC (TICK_USEC );/* USER_HZ period (nsec) */ + tick_nsec =TICK_NSEC ;/* USER_HZ period (nsec) */ pc9800_misc_flags =PC9800_MISC_FLAGS ;#ifdef CONFIG_SMP
include/asm-ia64/timex.h +5 -1
@@ -14,7 +14,11 @@typedef unsigned long cycles_t ; -#define CLOCK_TICK_RATE 100000000 +/* +* Something low processor frequency like 100Mhz but +* yet multiple of HZ to avoid truncation in some formulas. +*/ +#define CLOCK_TICK_RATE (HZ * 100000UL)static inline cycles_t get_cycles (void )
include/linux/time.h +27 -17
84 lines not on this page · raw message
include/linux/timex.h +11 -7
@@ -99,19 +99,19 @@* variable which serves as an extension to the low-order bits of the * system clock variable. The SHIFT_UPDATE define establishes the decimal * point of the time_offset variable which represents the current offset -* with respect to standard time. The FINEUSEC define represents 1 usec in +* with respect to standard time. The FINENSEC define represents 1 nsec in * scaled units. * * SHIFT_USEC defines the scaling (shift) of the time_freq and * time_tolerance variables, which represent the current frequency * offset and maximum frequency tolerance. * -* FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable. +* FINENSEC is 1 ns in SHIFT_UPDATE units of the time_phase variable. */ #define SHIFT_SCALE 22/* phase scale (shift) */ #define SHIFT_UPDATE (SHIFT_KG + MAXTC)/* time offset scale (shift) */ #define SHIFT_USEC 16/* frequency offset scale (shift) */ -#define FINEUSEC (1L << SHIFT_SCALE)/* 1 us in phase units */ +#define FINENSEC (1L << (SHIFT_SCALE - 10))/* ~1 ns in phase units */ #define MAXPHASE 512000L/* max phase error (us) */ #define MAXFREQ (512L << SHIFT_USEC)/* max frequency error (ppm) */
@@ -159,7 +159,7 @@* (NOM << LSH) / DEN * This however means trouble for large NOM, because (NOM << LSH) may no * longer fit in 32 bits. The following way of calculating this gives us -* some slack, under the following onditions: +* some slack, under the following conditions: * - (NOM / DEN) fits in (32 - LSH) bits. * - (NOM % DEN) fits in (32 - LSH) bits. */
@@ -169,12 +169,16 @@/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */ #define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8)) +/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */ +#define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8)) +/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ -#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) +#define TICK_USEC ((TICK_NSEC + 1000UL/2) / 1000UL) -/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ and */ +/* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming real ACTHZ and */ /* a value TUSEC for TICK_USEC (can be set bij adjtimex) */ -#define TICK_NSEC (TUSEC ) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8)) +#define TICK_USEC_TO_NSEC (TUSEC ) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8)) +#include <linux/time.h> /*
kernel/posix-timers.c +3 -3
@@ -33,7 +33,7 @@ result; })#endif -#define CLOCK_REALTIME_RES TICK_NSEC(TICK_USEC) // In nano seconds. +#define CLOCK_REALTIME_RES TICK_NSEC // In nano seconds.static inline u64 mpy_l_X_l_ll (unsigned long mpy1,unsigned long mpy2) {
@@ -1201,7 +1201,7 @@if (abs || !rq_time) {adjust_abs_time (&posix_clocks[which_clock], &t, abs, &rq_time); -// rq_time += (t.tv_sec || t.tv_nsec); + rq_time += (t.tv_sec || t.tv_nsec); } left = rq_time -get_jiffies_64 ();
@@ -1232,7 +1232,7 @@if (abs)return -ERESTARTNOHAND ; - left *=TICK_NSEC (TICK_USEC ); + left *=TICK_NSEC ; tsave->tv_sec =div_long_long_rem (left,NSEC_PER_SEC , &tsave->tv_nsec);
kernel/time.c +1 -1
@@ -339,7 +339,7 @@ }/* txc->modes & ADJ_OFFSET */ if (txc->modes &ADJ_TICK ) { tick_usec = txc->tick; - tick_nsec =TICK_NSEC (tick_usec); + tick_nsec =TICK_USEC_TO_NSEC (tick_usec); } }/* txc->modes */ leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0
kernel/timer.c +4 -4
@@ -439,7 +439,7 @@* Timekeeping variables */ unsigned long tick_usec =TICK_USEC ;/* ACTHZ period (usec) */ -unsigned long tick_nsec =TICK_NSEC (TICK_USEC );/* USER_HZ period (nsec) */ +unsigned long tick_nsec =TICK_NSEC ;/* USER_HZ period (nsec) */ /* * The current time
@@ -469,7 +469,7 @@long time_maxerror =NTP_PHASE_LIMIT ;/* maximum error (us) */ long time_esterror =NTP_PHASE_LIMIT ;/* estimated error (us) */ long time_phase;/* phase offset (scaled us) */ -long time_freq = ((1000000 +HZ /2 ) %HZ -HZ /2 ) <<SHIFT_USEC ; +long time_freq = (((NSEC_PER_SEC +HZ /2 ) %HZ -HZ /2 ) <<SHIFT_USEC ) /NSEC_PER_USEC ;/* frequency offset (scaled ppm)*/ long time_adj;/* tick adjust (scaled 1 / HZ) */ long time_reftime;/* time at last adjustment (s) */
@@ -631,12 +631,12 @@* advance the tick more. */ time_phase += time_adj; -if (time_phase <= -FINEUSEC ) { +if (time_phase <= -FINENSEC ) {long ltemp = -time_phase >> (SHIFT_SCALE -10 ); time_phase += ltemp << (SHIFT_SCALE -10 ); xtime.tv_nsec -= ltemp; } -else if (time_phase >=FINEUSEC ) { +else if (time_phase >=FINENSEC ) {long ltemp = time_phase >> (SHIFT_SCALE -10 ); time_phase -= ltemp << (SHIFT_SCALE -10 ); xtime.tv_nsec += ltemp;