All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Dan Magenheimer" <dan.magenheimer@oracle.com>
To: "Xen-Devel (E-mail)" <xen-devel@lists.xensource.com>,
	Keir Fraser <Keir.Fraser@eu.citrix.com>
Cc: Ian Pratt <Ian.Pratt@eu.citrix.com>,
	Dave Winchell <dwinchell@virtualiron.com>
Subject: [PATCH] rendezvous-based local time calibration WOW!
Date: Sun, 3 Aug 2008 10:50:29 -0600	[thread overview]
Message-ID: <20080803105029796.00000008444@djm-pc> (raw)

[-- Attachment #1: Type: text/plain, Size: 1684 bytes --]

The synchronization of local_time_calibration (l_t_c) via
round-to-nearest-epoch provided some improvement, but I was
still seeing skew up to 16usec and higher.  I measured the
temporal distance between the rounded-epoch vs when ltc
was actually running to ensure there wasn't some kind of
bug and found that l_t_c was running up to 150us after the
round-epoch and sometimes up to 50us before.  I guess this
is the granularity of setting a Xen timer.  While it seemed
that +/- 100us shouldn't cause that much skew, I finally
decided to try synchronization-via-rendezvous, as suggested
by Ian here:

http://lists.xensource.com/archives/html/xen-devel/2008-07/msg01074.html
http://lists.xensource.com/archives/html/xen-devel/2008-07/msg01080.html

The result is phenomenal... using this approach (in attached
patch), I have yet to see a skew exceed 1usec!!!  So this is
about a 10-fold increase in accuracy vs the rounded-epoch
method and about 20-fold over the one-epoch-from-NOW() method.

The platform time is now read once for all processors rather
than once per processor.  (Actually, it is read once again
in platform_time_calibration()... by "inlining" that routine
into master_local_time_calibration() that extra read can
be -- and probably should be -- avoided too.)

It may be too late to get this into 3.3.0 but, if so, please
consider it asap for 3.3.1 rather than just xen-unstable/3.4.

Dan

===================================
Thanks... for the memory
I really could use more / My throughput's on the floor
The balloon is flat / My swap disk's fat / I've OOM's in store
Overcommitted so much
(with apologies to the late great Bob Hope)

[-- Attachment #2: rendezcalib.patch --]
[-- Type: application/octet-stream, Size: 5020 bytes --]

diff -r 8951c3b84e2a xen/arch/x86/time.c
--- a/xen/arch/x86/time.c	Fri Aug 01 09:54:54 2008 +0100
+++ b/xen/arch/x86/time.c	Sun Aug 03 10:34:11 2008 -0600
@@ -876,7 +876,8 @@ void do_settime(unsigned long secs, unsi
     rcu_read_unlock(&domlist_read_lock);
 }
 
-static void local_time_calibration(void *unused)
+static void local_time_calibration(s_time_t curr_master_stime,
+    s_time_t curr_local_stime, u64 curr_tsc)
 {
     struct cpu_time *t = &this_cpu(cpu_time);
 
@@ -884,11 +885,11 @@ static void local_time_calibration(void 
      * System timestamps, extrapolated from local and master oscillators,
      * taken during this calibration and the previous calibration.
      */
-    s_time_t prev_local_stime, curr_local_stime;
-    s_time_t prev_master_stime, curr_master_stime;
+    s_time_t prev_local_stime;
+    s_time_t prev_master_stime;
 
     /* TSC timestamps taken during this calibration and prev calibration. */
-    u64 prev_tsc, curr_tsc;
+    u64 prev_tsc;
 
     /*
      * System time and TSC ticks elapsed during the previous calibration
@@ -909,14 +910,6 @@ static void local_time_calibration(void 
     /* The overall calibration scale multiplier. */
     u32 calibration_mul_frac;
 
-    if ( platform_timer_is_tsc() )
-    {
-        make_tsctimer_record(); 
-        update_vcpu_system_time(current);
-        set_timer(&t->calibration_timer, NOW() + MILLISECS(10*1000));
-        return;
-    }
-
     prev_tsc          = t->local_tsc_stamp;
     prev_local_stime  = t->stime_local_stamp;
     prev_master_stime = t->stime_master_stamp;
@@ -925,12 +918,6 @@ static void local_time_calibration(void 
      * Disable IRQs to get 'instantaneous' current timestamps. We read platform
      * time first, as we may be delayed when acquiring platform_timer_lock.
      */
-    local_irq_disable();
-    curr_master_stime = read_platform_stime();
-    curr_local_stime  = get_s_time();
-    rdtscll(curr_tsc);
-    local_irq_enable();
-
 #if 0
     printk("PRE%d: tsc=%"PRIu64" stime=%"PRIu64" master=%"PRIu64"\n",
            smp_processor_id(), prev_tsc, prev_local_stime, prev_master_stime);
@@ -952,7 +939,7 @@ static void local_time_calibration(void 
      * We could be smarter here: resync platform timer with local timer?
      */
     if ( ((s64)stime_elapsed64 < (EPOCH / 2)) )
-        goto out;
+        return;
 
     /*
      * Calculate error-correction factor. This only slows down a fast local
@@ -1020,12 +1007,71 @@ static void local_time_calibration(void 
     local_irq_enable();
 
     update_vcpu_system_time(current);
+}
 
- out:
+static cpumask_t local_time_calibrate_cpumask = CPU_MASK_NONE;
+s_time_t curr_master_stime;
+
+static void slave_local_time_calibration(void *unused)
+{
+    unsigned int cpu = smp_processor_id();
+    u64 curr_tsc;
+    s_time_t curr_local_stime;
+
+    if ( platform_timer_is_tsc() )
+    {
+        make_tsctimer_record(); 
+        update_vcpu_system_time(current);
+        return;
+    }
+
+    local_irq_disable();
+    while ( !cpu_isset(cpu, local_time_calibrate_cpumask) )
+        cpu_relax();
+    curr_local_stime  = get_s_time();
+    rdtscll(curr_tsc);
+    cpu_clear(cpu, local_time_calibrate_cpumask);
+    local_irq_enable();
+
+    local_time_calibration(curr_master_stime, curr_local_stime, curr_tsc);
+}
+
+static void master_local_time_calibration(void *unused)
+{
+    unsigned int cpu = smp_processor_id();
+    static DEFINE_SPINLOCK(lock);
+    u64 curr_tsc;
+    s_time_t curr_local_stime;
+    struct cpu_time *t = &this_cpu(cpu_time);
+
+    if ( platform_timer_is_tsc() )
+    {
+        smp_call_function(slave_local_time_calibration, NULL, 0, 0);
+        make_tsctimer_record(); 
+        update_vcpu_system_time(current);
+        set_timer(&t->calibration_timer, NOW() + MILLISECS(10*1000));
+        return;
+    }
+
+    spin_lock(&lock);
+
+    smp_call_function(slave_local_time_calibration, NULL, 0, 0);
+
+    local_irq_disable();
+    curr_master_stime = read_platform_stime();
+    local_time_calibrate_cpumask = cpu_online_map;
+    curr_local_stime  = get_s_time();
+    rdtscll(curr_tsc);
+    cpu_clear(cpu, local_time_calibrate_cpumask);
+    local_irq_enable();
+
+    local_time_calibration(curr_master_stime, curr_local_stime, curr_tsc);
+
+    spin_unlock(&lock);
+
     set_timer(&t->calibration_timer, NEXT_EPOCH(curr_local_stime));
 
-    if ( smp_processor_id() == 0 )
-        platform_time_calibration();
+    platform_time_calibration();
 }
 
 void init_percpu_time(void)
@@ -1049,9 +1095,12 @@ void init_percpu_time(void)
     t->stime_local_stamp  = now;
 
  out:
-    init_timer(&t->calibration_timer, local_time_calibration,
+    if ( smp_processor_id() == 0 )
+    {
+        init_timer(&t->calibration_timer, master_local_time_calibration,
                NULL, smp_processor_id());
-    set_timer(&t->calibration_timer, NEXT_EPOCH(NOW()));
+        set_timer(&t->calibration_timer, NEXT_EPOCH(NOW()));
+    }
 }
 
 /* Late init function (after all CPUs are booted). */

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

             reply	other threads:[~2008-08-03 16:50 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-03 16:50 Dan Magenheimer [this message]
2008-08-03 17:24 ` [PATCH] rendezvous-based local time calibration WOW! Keir Fraser
2008-08-04 15:24   ` Dan Magenheimer
2008-08-04 15:36     ` Keir Fraser
2008-08-04 17:10     ` Keir Fraser
2008-08-04 17:37       ` Dan Magenheimer
2008-08-04 19:40         ` Dan Magenheimer
2008-08-04 19:47           ` Keir Fraser
2008-08-05 18:56           ` John Levon
2008-08-05 20:49             ` Dan Magenheimer
2008-08-05 21:12               ` John Levon
2008-08-05 21:27                 ` Dan Magenheimer
2008-08-05 21:43                   ` Keir Fraser
2008-08-06 13:25                 ` Dan Magenheimer
2008-08-06 13:38                   ` John Levon
2008-08-06 15:09                     ` Dan Magenheimer
2008-08-06 15:21                       ` John Levon
2008-08-06 15:34                         ` Dan Magenheimer
2008-08-09 14:47                         ` Nils Nieuwejaar
2008-08-09 20:55                           ` Dan Magenheimer
2008-08-11 14:37                             ` John Levon
2008-08-11 14:38                               ` Keir Fraser
2008-08-11 14:43                                 ` John Levon
2008-08-11 14:46                                   ` Keir Fraser
2008-08-11 14:49                                     ` John Levon
2008-08-11 14:50                                       ` Keir Fraser
2008-08-11 18:41                                         ` John Levon

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=20080803105029796.00000008444@djm-pc \
    --to=dan.magenheimer@oracle.com \
    --cc=Ian.Pratt@eu.citrix.com \
    --cc=Keir.Fraser@eu.citrix.com \
    --cc=dwinchell@virtualiron.com \
    --cc=xen-devel@lists.xensource.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.