From: john stultz <johnstul@us.ibm.com>
To: lkml <linux-kernel@vger.kernel.org>
Subject: [RFC] linux-2.5.66_lost-ticks-fix_A0
Date: 25 Mar 2003 12:30:59 -0800 [thread overview]
Message-ID: <1048624259.972.19.camel@w-jstultz2.beaverton.ibm.com> (raw)
[-- Attachment #1.1: Type: text/plain, Size: 1091 bytes --]
All,
I found a broken corner case with my earlier lost-ticks patch, so I'm
planning on submitting this fix to solve the issue.
The problem arises because we're doing two reads from the time source in
the timer_interrupt:
detect_lost_tick();
timer->mark_offset();
The problem with this being that even though we're in the interrupt
handler and properly locking our variables. The time sources keep on
ticking, so the two references to the time source are obviously not
atomic.
For example
time function
-------------------------
@1990 detect_lost_tick()
- calculate # of lost ticks (none, we're < 2000)
@2003 timer->mark_offset()
- overwrite last_tsc_low/last_cyclone_timer
- write 3 into delay_at_last_interrupt
Thus jiffies is only incremented once, but delay_at_last_interrupt is
too small so we get a time inconsistency.
This patch resolves the issue by doing the lost-tick compensation inside
timer->mark_offset(), thus there is only one read of the time-source per
interrupt.
Comments, flames and suggestions welcome.
thanks
-john
[-- Attachment #1.2: linux-2.5.66_lost-tick-fix_A0.patch --]
[-- Type: text/x-patch, Size: 3665 bytes --]
diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c Tue Mar 25 12:08:26 2003
+++ b/arch/i386/kernel/time.c Tue Mar 25 12:08:26 2003
@@ -268,41 +268,6 @@
}
/*
- * Lost tick detection and compensation
- */
-static inline void detect_lost_tick(void)
-{
- /* read time since last interrupt */
- unsigned long delta = timer->get_offset();
- static unsigned long dbg_print;
-
- /* check if delta is greater then two ticks */
- if(delta >= 2*(1000000/HZ)){
-
- /*
- * only print debug info first 5 times
- */
- /*
- * AKPM: disable this for now; it's nice, but irritating.
- */
- if (0 && dbg_print < 5) {
- printk(KERN_WARNING "\nWarning! Detected %lu "
- "micro-second gap between interrupts.\n",
- delta);
- printk(KERN_WARNING " Compensating for %lu lost "
- "ticks.\n",
- delta/(1000000/HZ)-1);
- dump_stack();
- dbg_print++;
- }
- /* calculate number of missed ticks */
- delta = delta/(1000000/HZ)-1;
- jiffies += delta;
- }
-
-}
-
-/*
* This is the same as the above, except we _also_ save the current
* Time Stamp Counter value at the time of the timer interrupt, so that
* we later on can estimate the time of day more exactly.
@@ -318,7 +283,6 @@
*/
write_seqlock(&xtime_lock);
- detect_lost_tick();
timer->mark_offset();
do_timer_interrupt(irq, NULL, regs);
diff -Nru a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c
--- a/arch/i386/kernel/timers/timer_cyclone.c Tue Mar 25 12:08:26 2003
+++ b/arch/i386/kernel/timers/timer_cyclone.c Tue Mar 25 12:08:26 2003
@@ -17,6 +17,7 @@
#include <asm/fixmap.h>
extern spinlock_t i8253_lock;
+extern unsigned long jiffies;
extern unsigned long calibrate_tsc(void);
/* Number of usecs that the last interrupt was delayed */
@@ -35,6 +36,7 @@
static void mark_offset_cyclone(void)
{
+ u32 delta = last_cyclone_timer;
int count;
spin_lock(&i8253_lock);
/* quickly read the cyclone timer */
@@ -47,6 +49,13 @@
count = inb_p(0x40); /* read the latched count */
count |= inb(0x40) << 8;
spin_unlock(&i8253_lock);
+
+ /* lost tick compensation */
+ delta = last_cyclone_timer - delta;
+ delta /=(CYCLONE_TIMER_FREQ/1000000);
+ delta += delay_at_last_interrupt;
+ if(delta >= 2*(1000000/HZ))
+ jiffies += delta/(1000000/HZ)-1;
count = ((LATCH-1) - count) * TICK_SIZE;
delay_at_last_interrupt = (count + LATCH/2) / LATCH;
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
--- a/arch/i386/kernel/timers/timer_tsc.c Tue Mar 25 12:08:26 2003
+++ b/arch/i386/kernel/timers/timer_tsc.c Tue Mar 25 12:08:26 2003
@@ -17,6 +17,7 @@
int tsc_disable __initdata = 0;
extern spinlock_t i8253_lock;
+extern unsigned long jiffies;
static int use_tsc;
/* Number of usecs that the last interrupt was delayed */
@@ -62,6 +63,7 @@
static void mark_offset_tsc(void)
{
+ unsigned long delta = last_tsc_low;
int count;
int countmp;
static int count1=0, count2=LATCH;
@@ -101,6 +103,21 @@
count2 = count1; count1 = count; count = count1;
}
}
+
+ /* lost tick compensation */
+ delta = last_tsc_low - delta;
+ {
+ register unsigned long eax, edx;
+ eax = delta;
+ __asm__("mull %2"
+ :"=a" (eax), "=d" (edx)
+ :"rm" (fast_gettimeoffset_quotient),
+ "0" (eax));
+ delta = edx;
+ }
+ delta += delay_at_last_interrupt;
+ if(delta >= 2*(1000000/HZ))
+ jiffies += delta/(1000000/HZ)-1;
count = ((LATCH-1) - count) * TICK_SIZE;
delay_at_last_interrupt = (count + LATCH/2) / LATCH;
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 232 bytes --]
reply other threads:[~2003-03-25 20:26 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1048624259.972.19.camel@w-jstultz2.beaverton.ibm.com \
--to=johnstul@us.ibm.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®