Re: timer counter chip access mystery]

From: Petri Helenius (pete_at_he.iki.fi)
Date: 07/16/03

  • Next message: Steven Hartland: "Re: timer counter chip access mystery]"
    To: "Jin Guojun [DSD]" <j_guojun@lbl.gov>, <freebsd-performance@freebsd.org>
    Date: Thu, 17 Jul 2003 00:44:32 +0300
    
    

    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@lbl.gov>
    To: <freebsd-performance@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@freebsd.org mailing list
    > http://lists.freebsd.org/mailman/listinfo/freebsd-performance
    > To unsubscribe, send any mail to "freebsd-performance-unsubscribe@freebsd.org"
    >
    _______________________________________________
    freebsd-performance@freebsd.org mailing list
    http://lists.freebsd.org/mailman/listinfo/freebsd-performance
    To unsubscribe, send any mail to "freebsd-performance-unsubscribe@freebsd.org"


  • Next message: Steven Hartland: "Re: timer counter chip access mystery]"