lkml.org 
[lkml]   [1996]   [May]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: the time problem
On Tue, 14 May 1996, Ulrich Windl wrote:

> In 1.99.2 the time still jumps backward from time to time (with or
> without the Pentium CC). Even though H. G. Wells would have been a
> great fan of it, I think the rest of the users won't like it that
> much.

I have patches for time warps, with or without the pentium stuff.
those patches fix all 3 kinds of time warps i found so far. Since i see no
more time warps, i need some feedback.

I suspected some general time warp too, in sched.c, but the tricky thing
is that concurrently there are bugs/problems in both do_fast_gettimeoffset()
and do_slow_gettimoffset().

the best test i found so far is:

dd if=/dev/hda1 of=/dev/null & sleep 1; dd if=/dev/hda2 of=/dev/null

(hda1 and hda2 should be two IDE partitions ...)

-- mingo

ps. i've attached a patch against pre2.0.4, that fixes all problems for
me. Please if ppl with time warps could test it out. They work on my
systems perfectly. I've attached a small testprogram too (posted by the
original bug-reporter), which should be run concurrently with the "dd"-s
(or find /-s, or whatever).

--- time.c.orig.1.99.4 Tue May 14 19:31:23 1996
+++ time.c Tue May 14 19:30:53 1996
@@ -10,6 +10,8 @@
* 1995-03-26 Markus Kuhn
* fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887
* precision CMOS clock update
+ * 1996-05-02 Ingo Molnar
+ * fixed time warps
*/
#include <linux/errno.h>
#include <linux/sched.h>
@@ -37,26 +39,54 @@
static unsigned long do_fast_gettimeoffset(void)
{
unsigned long time_low, time_high;
- unsigned long quotient, remainder;
+ unsigned long quotient,remainder,missing_time=0;

- /* Get last timer tick in absolute kernel time */
- __asm__("subl %2,%0\n\t"
- "sbbl %3,%1"
- :"=r" (time_low), "=r" (time_high)
- :"m" (*(0+(long *)&init_timer_cc)),
- "m" (*(1+(long *)&init_timer_cc)),
- "0" (*(0+(long *)&last_timer_cc)),
- "1" (*(1+(long *)&last_timer_cc)));
- /*
- * Divide the 64-bit time with the 32-bit jiffy counter,
- * getting the quotient in clocks.
- *
- * Giving quotient = "average internal clocks per jiffy"
- */
- __asm__("divl %2"
- :"=a" (quotient), "=d" (remainder)
- :"r" (jiffies),
- "0" (time_low), "1" (time_high));
+ /* Last jiffie when do_fast_gettimeoffset() was called.. */
+ static unsigned long last_jiffies=0;
+
+ /* Cached "clocks per usec" value.. */
+ static unsigned long quotient_c=0, remainder_c=0;
+
+ /* The "clocks per usec" value is calculated once each jiffie */
+ if( last_jiffies != jiffies ) {
+
+ /****
+ * test for hanging bottom handler (this means xtime is not
+ * updated yet)
+ */
+ if( test_bit(TIMER_BH, &bh_active) )
+ missing_time = 997670/HZ;
+
+ last_jiffies = jiffies;
+
+ /* Get last timer tick in absolute kernel time */
+ __asm__("subl %2,%0\n\t"
+ "sbbl %3,%1"
+ :"=r" (time_low), "=r" (time_high)
+ :"m" (*(0+(long *)&init_timer_cc)),
+ "m" (*(1+(long *)&init_timer_cc)),
+ "0" (*(0+(long *)&last_timer_cc)),
+ "1" (*(1+(long *)&last_timer_cc)));
+
+ /*
+ * Divide the 64-bit time with the 32-bit jiffy counter,
+ * getting the quotient in clocks.
+ *
+ * Giving quotient = "average internal clocks per usec"
+ */
+ __asm__("divl %2"
+ :"=a" (quotient), "=d" (remainder)
+ :"r" (last_jiffies),
+ "0" (time_low), "1" (time_high));
+
+ quotient <<= 8;
+
+ __asm__("divl %2"
+ :"=a" (quotient_c), "=d" (remainder_c)
+ :"r" (997670/HZ),
+ "0" (quotient), "1" (0));
+
+ }

/* Read the time counter */
__asm__(".byte 0x0f,0x31"
@@ -65,23 +95,26 @@
/* .. relative to previous jiffy (32 bits is enough) */
time_low -= (unsigned long) last_timer_cc;

+ time_low <<= 8;
+
/*
- * Time offset = (1000000/HZ * remainder) / quotient.
+ * Time offset = (997670/HZ * time_low) / quotient.
*/
- __asm__("mull %1\n\t"
- "divl %2"
+
+ __asm__("divl %2"
:"=a" (quotient), "=d" (remainder)
- :"r" (quotient),
- "0" (time_low), "1" (1000000/HZ));
+ :"r" (quotient_c),
+ "0" (time_low), "1" (0));

/*
- * Due to rounding errors (and jiffies inconsistencies),
+ * Due to rounding errors (and jiffies inconsistencies),
* we need to check the result so that we'll get a timer
* that is monotonous.
*/
- if (quotient >= 1000000/HZ)
- quotient = 1000000/HZ-1;
- return quotient;
+ if (quotient >= 997670/HZ)
+ quotient = 997670/HZ-1;
+
+ return quotient + missing_time;
}
#endif

@@ -122,19 +155,34 @@
static unsigned long do_slow_gettimeoffset(void)
{
int count;
+ static int count_p = 0;
unsigned long offset = 0;
+ static unsigned long jiffies_p = 0;

/* timer count may underflow right here */
outb_p(0x00, 0x43); /* latch the count ASAP */
count = inb_p(0x40); /* read the latched count */
count |= inb(0x40) << 8;
- /* we know probability of underflow is always MUCH less than 1% */
- if (count > (LATCH - LATCH/100)) {
- /* check for pending timer interrupt */
- outb_p(0x0a, 0x20);
- if (inb(0x20) & 1)
- offset = TICK_SIZE;
+
+ if( (jiffies == jiffies_p) && (count > count_p) )
+ {
+ /****
+ * we have detected a counter underflow. Detection
+ * is 100% sure for latencies less than a jiffie
+ */
+ offset = TICK_SIZE;
+
+ /****
+ * make sure that we get into this branch till
+ * the timer interrupt gets handled
+ */
+ count_p = 0;
}
+ else {
+ count_p = count;
+ jiffies_p = jiffies;
+ }
+
count = ((LATCH-1) - count) * TICK_SIZE;
count = (count + LATCH/2) / LATCH;
return offset + count;#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>

void main()
{
struct timeval t, t_old;

timerclear(&t);
timerclear(&t_old);

for(;;)
{
gettimeofday(&t, NULL);

if( ((t.tv_sec*1000000+t.tv_usec) < (t_old.tv_sec*1000000+t_old.tv_usec)) )
{
printf("time warp: old value: %d, new value: %d.\n",
t_old.tv_sec*1000000+t_old.tv_usec,
t.tv_sec*1000000+t.tv_usec);
}
t_old = t;
}
}

\
 
 \ /
  Last update: 2005-03-22 13:37    [W:0.065 / U:0.368 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site