[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

RE: [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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.