public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Dror Cohen <dror.xiv@gmail.com>
To: linux-kernel@vger.kernel.org
Subject: Time Drift Compensation on Linux Clusters
Date: Thu, 3 Mar 2005 16:50:52 +0200	[thread overview]
Message-ID: <6c58e3190503030650595cbd5@mail.gmail.com> (raw)

Hi all,
While working on a Linux cluster with kernel version 2.4.27 we've
encountered a consistent clock drift problem. We have devised a fix
for this problem which is based on the Pentium's TSC clock. We'd
appreciate any comments on the validity of the proposed solution and
on whether it might cause unexpected (and undesired) problems in other
parts of the kernel.

Following is a detailed description of the problem and the fix,

Thanks everyone,
Dror
XIV ltd.

------------------------------------------------------------------------------------------------------------

Time Drift Compensation on Linux Clusters


1. Background

During the operation of the 2.4.27 kernel under intense IO conditions a clock
drift was detected. The system time, as received by gettimeofday() began lagging
behind the wall clock.

All PCs have a battery driven hardware clock. This clock is used at boot time to
initialize the system time. Linux then uses the Programmable Interval
Timer (PIT)
to keep an internal accounting of the flow of time. The PIT is set to raise an
interrupt every fixed interval. The number of interrupt per second is defined by
the kernel constant HZ, which typically equals 100 (10 on Alpha machines). The
interrupt handler kernel/timer.c:do_timer() increments a kernel wide
variable named
jiffies and invokes the bottom half to take care of timers and scheduling.

2. Analysis

In IO intensive environments a many CPU cycles are spent handling interrupts.
This is done by the device driver code for the different IO devices.
Typically, while
dealing with the hardware, device drivers block other IRQs, including the PIT's
(timer) IRQ.

When debugging drivers it is not uncommon to use printk() inside
driver code while
IRQs are still blocked. This method is by nature blocking and can only
be run once
even on SMP machines. This is because messages printed by printk() must reach
the console before any other operation might cause the kernel to panic or block.

In cluster environments a serial console can be used to access
machines remotely.
One drawback of using such a console is its longer response time which
significantly
lengthens the blocking time of printk().

Putting all this together results in an interrupt rich environments in
which many
interrupt handlers block the IRQs for long periods of time. This
matters when 'long'
becomes longer than 1 second / HZ, which means that the CPU misses timer
interrupts.

Each time a time interrupt is missed the system looses one jiffy.
These lost jiffies
accumulate into a consisting clock drift.

3. Fix

The fix proposed here relies on a quality of the Pentium processor and thus is
irrelevant to other architectures or to older (80386, 80486) CPUs.

The Pentium has an internal cycles counter called the Time Stamp Counter (TSC).
This counter is a 64 bit register which is incremented internally
every CPU cycle and
can be read using a special assembly instruction. On a 1GHz machine
this register
wraps to zero once every 584 years.

The suggested fix adds code to the timer interrupt handler which
tracks the value
of this counter. When an interrupt occurs, the jiffies counter is
increased not just
by one but by the number of 1 second / HZ intervals that actually
passed according
to the TSC value change.

This involves modifying two kernel files:

kernel/timer.c:
	modify the interrupt handler do_timer()

	698a699,703
	> #ifdef X86_TSC_DRIFT_COMPENSATION
	> __u64 xtdc_step;
	> __u64 xtdc_last = 0;
	> #endif
	>
	700a706,712
	> #ifdef X86_TSC_DRIFT_COMPENSATION
	>       __u64 cycles = get_cycles();
	>       while (xtdc_last < cycles) {
	>               (*(unsigned long *)&jiffies)++;
	>               xtdc_last += xtdc_step;
	>       }
	> #else
	701a714,715
	> #endif
	>

arch/i386/kernel/time.c

	modify calibrate_tsc() to get the initial TSC count and to calculate the number
	of TSC cycles per 1 second / HZ interval

	768a769,777
	> #ifdef X86_TSC_DRIFT_COMPENSATION
	>
	> extern __u64 xtdc_step;
	> extern __u64 xtdc_last;
	> #define CALIBRATE_LATCH       (4 * LATCH)
	> #define CALIBRATE_TIME        (4 * 1000020/HZ)
	>
	> #else
	>
	771a781,782
	> #endif
	>
	805a817,820
	> #ifdef X86_TSC_DRIFT_COMPENSATION
	>               xtdc_last = (((__u64) endhigh) << 32) + (__u64) endlow;
	> #endif
	>
	811a827,830
	>
	> #ifdef X86_TSC_DRIFT_COMPENSATION
	>               xtdc_step = ((((__u64) endhigh) << 32) + (__u64) endlow) >> 2;
	> #endif

             reply	other threads:[~2005-03-03 14:51 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-03-03 14:50 Dror Cohen [this message]
2005-03-03 16:23 ` Time Drift Compensation on Linux Clusters Chris Friesen
2005-03-03 16:24 ` Baruch Even
2005-03-03 17:34 ` Andi Kleen

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=6c58e3190503030650595cbd5@mail.gmail.com \
    --to=dror.xiv@gmail.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