Messages in this thread | | | Date | Tue, 2 Nov 1999 18:41:47 -0800 | From | "Charles 'Buck' Krasic" <> | Subject | question about use of x86 tsc in do_fast_gettimeoffset |
| |
Hi.
I've been reading the code in arch/i386/kernel/time.c and I think I see a what should be a bug in do_fast_gettimeoffset(), but I can not trigger it. So I wonder what I'm missing...
The bug I think I see concerns the tsc_low_delta calculation during the period of time when the low 32 bits of the x86 tsc are about to wrap. It appears to me that if a timer_interrupt runs just before the wrap, and then gettimeoffset runs just after the wrap, then the line eax -= last_tsc_low will produce a value close to 2^32. So, all calls to do_gettimeofday will warp forward in time (eg by about 10s on a 400MHz machine) for the duration of the tick.
However, I can not cause this to actually happen...
Why is it safe to compute this tsc_low_delta using only the low 32 bits of the tsc?
-- Buck
static inline unsigned long do_fast_gettimeoffset(void) { register unsigned long eax asm("ax"); register unsigned long edx asm("dx");
/* Read the Time Stamp Counter */
rdtsc(eax,edx);
/* .. relative to previous jiffy (32 bits is enough) */ eax -= last_tsc_low; /* tsc_low delta */
/* * Time offset = (tsc_low delta) * fast_gettimeoffset_quotient * = (tsc_low delta) * (usecs_per_clock) * = (tsc_low delta) * (usecs_per_jiffy / clocks_per_jiffy) * * Using a mull instead of a divl saves up to 31 clock cycles * in the critical path. */
__asm__("mull %2" :"=a" (eax), "=d" (edx) :"g" (fast_gettimeoffset_quotient), "0" (eax));
/* our adjusted time offset in microseconds */ return delay_at_last_interrupt + edx; }
static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int count;
/* * Here we are in the timer irq handler. We just have irqs locally * disabled but we don't know if the timer_bh is running on the other * CPU. We need to avoid to SMP race with it. NOTE: we don' t need * the irq version of write_lock because as just said we have irq * locally disabled. -arca */ write_lock(&xtime_lock);
if (use_tsc) { /* * It is important that these two operations happen almost at * the same time. We do the RDTSC stuff first, since it's * faster. To avoid any inconsistencies, we need interrupts * disabled locally. */
/* * Interrupts are just disabled locally since the timer irq * has the SA_INTERRUPT flag set. -arca */ /* read Pentium cycle counter */
rdtscl(last_tsc_low);
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; } do_timer_interrupt(irq, NULL, regs);
write_unlock(&xtime_lock);
}
- 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/
| |