Messages in this thread Patch in this message | | | From | "Ulrich Windl" <> | Date | Mon, 15 Mar 1999 09:47:24 +0100 | Subject | Suppressing Pentium timeoffset jitter in 2.0.36 |
| |
Hi!
I found out that Linux 2.0.36 has 200us and above jitter when reading the time. Interestingly this is not that much caused by system load (Emacs C-U 8 M-x hanoi almost had no effect), but by the schduling of timer events (itimer). At least in xntpd the jitter was present when it ran.
I merged my old "madtime patch" with the code found in 2.2 and made the following patch, possibly a good candidate for 2.0. If anyone cares for a 2.0.37...
Regards, Ulrich P.S. The patch is part of PPSkit-0.3.9 P.P.S. Our mail system is down since Friday 22:00 MET, and they are still "working on the problem". See when the message will leave...
--- linux/arch/i386/kernel/time.c~ Sat Mar 13 21:45:27 1999 +++ linux/arch/i386/kernel/time.c Sun Mar 14 18:14:23 1999 @@ -45,6 +45,9 @@ unsigned long high; } init_timer_cc, last_timer_cc; +/* Number of usecs that the last interrupt was delayed (only for TSC) */ +static int delay_at_last_interrupt; + /* * This is more assembly than C, but it's also rather * timing-critical and we have to use assembler to get @@ -66,7 +69,32 @@ tmp = jiffies; quotient = cached_quotient; low_timer = last_timer_cc.low; - missing_time = 0; + /* Read the time counter */ + __asm__(".byte 0x0f,0x31" + :"=a" (eax), "=d" (edx)); + + /* .. relative to previous jiffy (32 bits is enough) */ + edx = 0; + eax -= low_timer; + + /* + * Time offset = (1000020/HZ * time_low) / quotient. + */ + + __asm__("mull %2" + :"=a" (eax), "=d" (edx) + :"r" (quotient), + "0" (eax), "1" (edx)); + + /* + * Due to rounding errors (and jiffies inconsistencies), + * we need to check the result so that we'll get a timer + * that is monotonic. + */ + if (edx >= 1000020/HZ) + edx = 1000020/HZ-1; + + missing_time = edx + delay_at_last_interrupt; if (last_jiffies != tmp) { last_jiffies = tmp; /* @@ -75,7 +103,7 @@ */ if (test_bit(TIMER_BH, &bh_active) ) { - missing_time = 1000020/HZ; + missing_time += 1000020/HZ; } /* Get last timer tick in absolute kernel time */ @@ -106,36 +134,9 @@ :"r" (tmp), "0" (eax), "1" (edx)); cached_quotient = eax; - quotient = eax; } - /* Read the time counter */ - __asm__(".byte 0x0f,0x31" - :"=a" (eax), "=d" (edx)); - - /* .. relative to previous jiffy (32 bits is enough) */ - edx = 0; - eax -= low_timer; - - /* - * Time offset = (1000020/HZ * time_low) / quotient. - */ - - __asm__("mull %2" - :"=a" (eax), "=d" (edx) - :"r" (quotient), - "0" (eax), "1" (edx)); - - /* - * Due to rounding errors (and jiffies inconsistencies), - * we need to check the result so that we'll get a timer - * that is monotonic. - */ - if (edx >= 1000020/HZ) - edx = 1000020/HZ-1; - - eax = edx + missing_time; - return eax; + return missing_time; } #endif @@ -387,10 +388,22 @@ */ static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { + int count; + /* read Pentium cycle counter */ __asm__(".byte 0x0f,0x31" :"=a" (last_timer_cc.low), "=d" (last_timer_cc.high)); + + /* estimate the delay to avoid jitter when reading the time */ + outb_p(0x00, 0x43); /* latch the count ASAP */ + + count = inb_p(0x40); /* read the latched count */ + count |= inb(0x40) << 8; + + count = ((LATCH-1) - count) * TICK_SIZE; + delay_at_last_interrupt = (count + LATCH/2) / LATCH; + timer_interrupt(irq, NULL, regs); } #endif
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |