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;
};
range-timer.patch
Description: range-timer.patch
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|