WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

RE: [Xen-devel] [PATCH 0/2] range timer support

To: Keir Fraser <keir.fraser@xxxxxxxxxxxxx>
Subject: RE: [Xen-devel] [PATCH 0/2] range timer support
From: "Yu, Ke" <ke.yu@xxxxxxxxx>
Date: Fri, 31 Oct 2008 16:37:06 +0800
Accept-language: en-US
Acceptlanguage: en-US
Cc: "Liu, Jinsong" <jinsong.liu@xxxxxxxxx>, "Tian, Kevin" <kevin.tian@xxxxxxxxx>, "xen-devel@xxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxx>, "Wei, Gang" <gang.wei@xxxxxxxxx>
Delivery-date: Fri, 31 Oct 2008 01:37:44 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <C5306B7A.1EB53%keir.fraser@xxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <49582C73AC36CC4C8C6C42390304E81C092FD7CE68@xxxxxxxxxxxxxxxxxxxxxxxxxxxx> <C5306B7A.1EB53%keir.fraser@xxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
Thread-index: Ack6jbEldlUAQneTThGFgUljC8f6ygAa6sUwAAup0IcAARZ60AAAks5nAAEnUGA=
Thread-topic: [Xen-devel] [PATCH 0/2] range timer support
Keir Fraser wrote:
> On 31/10/08 07:50, "Yu, Ke" <ke.yu@xxxxxxxxx> wrote:
> 
>> I see. Then I will start to revise the range timer patch as follow:
>> - remove the TIMER_SLOP macro
>> - add "global timer slop" xen option, and make set_timer to use the
>> global slop. 
>> - remove the set_range_timer API, since it is not easy to use
>> currently 
> 
> Sounds reasonable.
> 
>  -- Keir

This is the updated range timer patch. I have done basic test on 50ns and 1ms 
timer slop, both looks fine.

Best Regards
Ke

===========================

Add range timer support

this patch convert the timer into range timer, which can expires at any time 
within the range. A configurable global timer slop is introduced to config the 
timer's default range as [deadline, deadline + timer_slop].

Signed-off-by: Yu Ke <ke.yu@xxxxxxxxx>
               Wei Gang <gang.wei@xxxxxxxxx>

diff -r bec755616e8e xen/arch/x86/hpet.c
--- a/xen/arch/x86/hpet.c
+++ b/xen/arch/x86/hpet.c
@@ -13,8 +13,6 @@
 #include <asm/fixmap.h>
 #include <asm/div64.h>
 #include <asm/hpet.h>
-
-#define STIME_MAX ((s_time_t)((uint64_t)~0ull>>1))
 
 #define MAX_DELTA_NS MILLISECS(10*1000)
 #define MIN_DELTA_NS MICROSECS(20)
diff -r bec755616e8e xen/common/timer.c
--- a/xen/common/timer.c
+++ b/xen/common/timer.c
@@ -25,13 +25,15 @@
  * We pull handlers off the timer list this far in future,
  * rather than reprogramming the time hardware.
  */
-#define TIMER_SLOP (50*1000) /* ns */
+static unsigned int timer_slop __read_mostly = 50000; /* 50 ns */
+integer_param("timer_slop", timer_slop);
 
 struct timers {
     spinlock_t     lock;
     struct timer **heap;
     struct timer  *list;
     struct timer  *running;
+    struct timer  *ready_list; /* ready timers for next fire */
 } __cacheline_aligned;
 
 static DEFINE_PER_CPU(struct timers, timers);
@@ -85,6 +87,33 @@ static void up_heap(struct timer **heap,
     t->heap_offset = pos;
 }
 
+/* Grow heap memory. Return the allocated heap, NULL if failed */
+static struct timer** grow_heap(struct timers *ts)
+{
+    int old_limit, new_limit;
+    struct timer **heap, **newheap;
+
+    heap = ts->heap;
+
+    /* old_limit == (2^n)-1; new_limit == (2^(n+4))-1 */
+    old_limit = GET_HEAP_LIMIT(heap);
+    new_limit = ((old_limit + 1) << 4) - 1;
+
+    newheap = xmalloc_array(struct timer *, new_limit + 1);
+
+    if ( newheap != NULL )
+    {
+        spin_lock_irq(&ts->lock);
+        memcpy(newheap, heap, (old_limit + 1) * sizeof(*heap));
+        SET_HEAP_LIMIT(newheap, new_limit);
+        ts->heap = newheap;
+        spin_unlock_irq(&ts->lock);
+        if ( old_limit != 0 )
+            xfree(heap);
+    }
+
+    return newheap;
+}
 
 /* Delete @t from @heap. Return TRUE if new top of heap. */
 static int remove_from_heap(struct timer **heap, struct timer *t)
@@ -177,6 +206,9 @@ static int remove_entry(struct timers *t
     case TIMER_STATUS_in_list:
         rc = remove_from_list(&timers->list, t);
         break;
+    case TIMER_STATUS_in_ready_list:
+        rc = remove_from_list(&timers->ready_list, t);
+        break;
     default:
         rc = 0;
         BUG();
@@ -202,6 +234,20 @@ static int add_entry(struct timers *time
     /* Fall back to adding to the slower linked list. */
     t->status = TIMER_STATUS_in_list;
     return add_to_list(&timers->list, t);
+}
+
+static void move_list_to_heap(struct timers *ts, struct timer **list)
+{
+    struct timer  *t, *next;
+
+    next = *list;
+    *list = NULL;
+    while ( (t = next) != NULL )
+    {
+        next = t->list_next;
+        t->status = TIMER_STATUS_inactive;
+        add_entry(ts, t);
+    }
 }
 
 static inline void __add_timer(struct timer *timer)
@@ -247,7 +293,7 @@ static inline void timer_unlock(struct t
 #define timer_unlock_irqrestore(t, flags) \
     do { timer_unlock(t); local_irq_restore(flags); } while ( 0 )
 
-
+/* Set timer that can expire in period [expires, expires + timer_slop] */
 void set_timer(struct timer *timer, s_time_t expires)
 {
     unsigned long flags;
@@ -257,14 +303,14 @@ void set_timer(struct timer *timer, s_ti
     if ( active_timer(timer) )
         __stop_timer(timer);
 
-    timer->expires = expires;
+    timer->expires     = expires;
+    timer->expires_end = expires + timer_slop;
 
     if ( likely(timer->status != TIMER_STATUS_killed) )
         __add_timer(timer);
 
     timer_unlock_irqrestore(timer, flags);
 }
-
 
 void stop_timer(struct timer *timer)
 {
@@ -343,54 +389,92 @@ void kill_timer(struct timer *timer)
             cpu_relax();
 }
 
+static void queue_ready_timer(struct timers* ts)
+{
+    struct timer  *t, **heap;
+    s_time_t start, end;
+
+    if ( unlikely (ts->ready_list != NULL) )
+        move_list_to_heap(ts, &ts->ready_list);
+
+    while ( unlikely (ts->list != NULL) )
+    {
+        spin_unlock_irq(&ts->lock);
+        if ( unlikely (grow_heap(ts) == NULL) )
+        {
+            printk(XENLOG_ERR "timer heap grow failed\n");
+            spin_lock_irq(&ts->lock);
+            break;
+        }
+        spin_lock_irq(&ts->lock);
+
+        move_list_to_heap(ts, &ts->list);
+    }
+
+    heap = ts->heap;
+    start = 0;
+    end   = STIME_MAX;
+
+    while ( (GET_HEAP_SIZE(heap) != 0) &&
+            ((t = heap[1])->expires <= end) )
+    {
+        remove_from_heap(heap, t);
+
+        start = t->expires;
+        if ( end > t->expires_end)
+            end = t->expires_end;
+
+        t->list_next = ts->ready_list;
+        ts->ready_list = t;
+        t->status = TIMER_STATUS_in_ready_list;
+    }
+    this_cpu(timer_deadline) = start;
+}
+
 
 static void timer_softirq_action(void)
 {
-    struct timer  *t, **heap, *next;
+    struct timer  *t, **heap;
     struct timers *ts;
-    s_time_t       now, deadline;
+    s_time_t       now;
     void         (*fn)(void *);
     void          *data;
 
     ts = &this_cpu(timers);
-    heap = ts->heap;
 
     /* If we are using overflow linked list, try to allocate a larger heap. */
     if ( unlikely(ts->list != NULL) )
-    {
-        /* old_limit == (2^n)-1; new_limit == (2^(n+4))-1 */
-        int old_limit = GET_HEAP_LIMIT(heap);
-        int new_limit = ((old_limit + 1) << 4) - 1;
-        struct timer **newheap = xmalloc_array(struct timer *, new_limit + 1);
-        if ( newheap != NULL )
-        {
-            spin_lock_irq(&ts->lock);
-            memcpy(newheap, heap, (old_limit + 1) * sizeof(*heap));
-            SET_HEAP_LIMIT(newheap, new_limit);
-            ts->heap = newheap;
-            spin_unlock_irq(&ts->lock);
-            if ( old_limit != 0 )
-                xfree(heap);
-            heap = newheap;
-        }
-    }
+        grow_heap(ts);
+    heap = ts->heap;
 
     spin_lock_irq(&ts->lock);
 
     /* Try to move timers from overflow linked list to more efficient heap. */
-    next = ts->list;
-    ts->list = NULL;
-    while ( unlikely((t = next) != NULL) )
-    {
-        next = t->list_next;
-        t->status = TIMER_STATUS_inactive;
-        add_entry(ts, t);
-    }
+    move_list_to_heap (ts, &ts->list);
 
     now = NOW();
 
+    /* Execute ready timer first */
+    if ( this_cpu(timer_deadline) < now )
+    {
+        while ( likely((t = ts->ready_list)!= NULL) )
+        {
+            fn   = t->function;
+            data = t->data;
+
+            ts->ready_list = t->list_next;
+            t->status = TIMER_STATUS_inactive;
+
+            ts->running = t;
+
+            spin_unlock_irq(&ts->lock);
+            (*fn)(data);
+            spin_lock_irq(&ts->lock);
+        }
+    }
+
     while ( (GET_HEAP_SIZE(heap) != 0) &&
-            ((t = heap[1])->expires < (now + TIMER_SLOP)) )
+            ((t = heap[1])->expires < now ) )
     {
         remove_entry(ts, t);
 
@@ -404,16 +488,10 @@ static void timer_softirq_action(void)
         spin_lock_irq(&ts->lock);
     }
 
-    deadline = GET_HEAP_SIZE(heap) ? heap[1]->expires : 0;
-
     while ( unlikely((t = ts->list) != NULL) )
     {
-        if ( t->expires >= (now + TIMER_SLOP) )
-        {
-            if ( (deadline == 0) || (deadline > t->expires) )
-                deadline = t->expires;
+        if ( t->expires >= now )
             break;
-        }
 
         ts->list = t->list_next;
         t->status = TIMER_STATUS_inactive;
@@ -430,8 +508,8 @@ static void timer_softirq_action(void)
 
     ts->running = NULL;
 
-    this_cpu(timer_deadline) = deadline;
-    if ( !reprogram_timer(deadline) )
+    queue_ready_timer(ts);
+    if ( !reprogram_timer(this_cpu(timer_deadline)) )
         raise_softirq(TIMER_SOFTIRQ);
 
     spin_unlock_irq(&ts->lock);
diff -r bec755616e8e xen/include/xen/time.h
--- a/xen/include/xen/time.h
+++ b/xen/include/xen/time.h
@@ -52,6 +52,7 @@ struct tm gmtime(unsigned long t);
 #define SECONDS(_s)     ((s_time_t)((_s)  * 1000000000ULL))
 #define MILLISECS(_ms)  ((s_time_t)((_ms) * 1000000ULL))
 #define MICROSECS(_us)  ((s_time_t)((_us) * 1000ULL))
+#define STIME_MAX ((s_time_t)((uint64_t)~0ull>>1))
 
 extern void update_vcpu_system_time(struct vcpu *v);
 extern void update_domain_wallclock_time(struct domain *d);
diff -r bec755616e8e xen/include/xen/timer.h
--- a/xen/include/xen/timer.h
+++ b/xen/include/xen/timer.h
@@ -15,6 +15,7 @@ struct timer {
 struct timer {
     /* System time expiry value (nanoseconds since boot). */
     s_time_t expires;
+    s_time_t expires_end;
 
     /* Position in active-timer data structure. */
     union {
@@ -36,6 +37,7 @@ struct timer {
 #define TIMER_STATUS_killed   1 /* Not in use; canot be activated.  */
 #define TIMER_STATUS_in_heap  2 /* In use; on timer heap.           */
 #define TIMER_STATUS_in_list  3 /* In use; on overflow linked list. */
+#define TIMER_STATUS_in_ready_list  4 /* In use; on ready linked list. */
     uint8_t status;
 };
 

Attachment: range-timer.patch
Description: range-timer.patch

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