timer counter chip access mystery]
Petri Helenius
pete at he.iki.fi
Wed Jul 16 14:44:41 PDT 2003
This access happens over ISA bus and thus happens at the speed the bus
operates at. Use TSC or ACPI for faster gettimeofday.
Pete
----- Original Message -----
From: "Jin Guojun [DSD]" <j_guojun at lbl.gov>
To: <freebsd-performance at freebsd.org>
Sent: Thursday, July 17, 2003 12:37 AM
Subject: [Fwd: timer counter chip access mystery]
> i386/isa/clock.c, line 1207
> i8254_get_timecount(...)
> {
> outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
>
> low = inb(TIMER_CNTR0);
> high = inb(TIMER_CNTR0);
> ...
> inb(IO_ICU1);
> return counter.
> }
>
> This routine takes about 4000 ns. It makes gettimeofday()
> cost over 4000 ns.
>
> measure_i8254_get_timecount: Two_TIMER_CNTR0 2362 ns
> measure_i8254_get_timecount: IO_ICU1 936 ns
> and outb() looks like to take another 700 ns.
>
> The Linux uses the same process to get the time counter (see below).
> It also comments that this is from Steve McCanne's microtime-i386 for BSD.
> However, gettimeofday() under Linux costs 900 ns.
> See attached GIF file for a table of comparison.
>
> Any idea why linux is 4 times faster than FreeBSD in
> reading the same time counter chip?
>
> -Jin
>
> ----------------- Linux source code for the same routine -----------
>
> arch/x86_64/kernel/time.c (line 68)
> void do_gettimeofday(struct timeval *tv)
> {
> unsigned long flags, t;
> unsigned int sec, usec;
>
> read_lock_irqsave(&xtime_lock, flags);
> spin_lock(&time_offset_lock);
>
> sec = xtime.tv_sec;
> usec = xtime.tv_usec;
>
> t = (jiffies - wall_jiffies) * (1000000L / HZ) + do_gettimeoffset();
> if (t > timeoffset) timeoffset = t;
> usec += timeoffset;
>
> spin_unlock(&time_offset_lock);
> read_unlock_irqrestore(&xtime_lock, flags);
>
> tv->tv_sec = sec + usec / 1000000;
> tv->tv_usec = usec % 1000000;
> }
>
> arch/i386/kernel/time.c (line 127)
>
> /* This function must be called with interrupts disabled
> * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
> *
> * However, the pc-audio speaker driver changes the divisor so that
> * it gets interrupted rather more often - it loads 64 into the
> * counter rather than 11932! This has an adverse impact on
> * do_gettimeoffset() -- it stops working! What is also not
> * good is that the interval that our timer function gets called
> * is no longer 10.0002 ms, but 9.9767 ms. To get around this
> * would require using a different timing source. Maybe someone
> * could use the RTC - I know that this can interrupt at frequencies
> * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
> * it so that at startup, the timer code in sched.c would select
> * using either the RTC or the 8253 timer. The decision would be
> * based on whether there was any other device around that needed
> * to trample on the 8253. I'd set up the RTC to interrupt at 1024 Hz,
> * and then do some jiggery to have a version of do_timer that
> * advanced the clock by 1/1024 s. Every time that reached over 1/100
> * of a second, then do all the old code. If the time was kept correct
> * then do_gettimeoffset could just return 0 - there is no low order
> * divider that can be accessed.
> *
> * Ideally, you would be able to use the RTC for the speaker driver,
> * but it appears that the speaker driver really needs interrupt more
> * often than every 120 us or so.
> *
> * Anyway, this needs more thought.... pjsg (1993-08-28)
> *
> * If you are really that interested, you should be reading
> * comp.protocols.time.ntp!
> */
>
> static unsigned long do_slow_gettimeoffset(void)
> {
> int count;
>
> static int count_p = LATCH; /* for the first call after boot */
> static unsigned long jiffies_p = 0;
>
> /*
> * cache volatile jiffies temporarily; we have IRQs turned off.
> */
> unsigned long jiffies_t;
>
> /* gets recalled with irq locally disabled */
> spin_lock(&i8253_lock);
> /* timer count may underflow right here */
> outb_p(0x00, 0x43); /* latch the count ASAP */
>
> count = inb_p(0x40); /* read the latched count */
>
> jiffies_t = jiffies;
>
> count |= inb_p(0x40) << 8;
>
> /* VIA686a test code... reset the latch if count > max + 1 */
> if (count > LATCH) {
> outb_p(0x34, 0x43);
> outb_p(LATCH & 0xff, 0x40);
> outb(LATCH >> 8, 0x40);
> count = LATCH - 1;
> }
>
> spin_unlock(&i8253_lock);
> ...
> return count;
> }
--------------------------------------------------------------------------------
> _______________________________________________
> freebsd-performance at freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-performance
> To unsubscribe, send any mail to "freebsd-performance-unsubscribe at freebsd.org"
>
More information about the freebsd-performance
mailing list