This is the patch for deferrable timer
As Xen introduce the C state support, it become important to optimize
the C state residency. The key point of the optimization is reducing the
breaking events. Since timer interrupt is the major part of the breaking
event, this patch is the first step to reduce the timer interrupts.
The basic idea of this patch is that certain ac timer does not stick to
one exact firing point, instead, it is fine with firing period, e.g.
period [a, b]. With the firing period introduced, it is possible to
group multiple ac timers, whose firing periods has non-null period
intersection. for example, suppose ac timer x, y has firing period [a1,
b1], [a2, b2], and [a1,b1]^[a2,b2] = [a3,b3] (where ^ stands for union
intersection). in this case, xen can group ac timer x and y, and fire
them at any time in [a3,b3], this in turn will reduce the timer
interrupt. And this type of ac timer is called deferrable timer.
This patch adds new ac timer API set_timer_deferrable for the deferrable
timer.
Signed-off-by: Yu Ke <ke.yu@xxxxxxxxx>
Wei Gang <gang.wei@xxxxxxxxx>
diff -r 19970181d6a4 xen/arch/x86/hpet.c
--- a/xen/arch/x86/hpet.c Tue Jul 01 14:50:35 2008 +0100
+++ b/xen/arch/x86/hpet.c Wed Jul 09 14:47:13 2008 +0800
@@ -14,8 +14,6 @@
#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 19970181d6a4 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c Tue Jul 01 14:50:35 2008 +0100
+++ b/xen/arch/x86/time.c Thu Jul 10 09:21:47 2008 +0800
@@ -478,7 +478,9 @@ static void plt_overflow(void *unused)
plt_stamp = count;
spin_unlock(&platform_timer_lock);
- set_timer(&plt_overflow_timer, NOW() + plt_overflow_period);
+ set_timer_deferrable( &plt_overflow_timer,
+ NOW() + plt_overflow_period -
plt_overflow_period/8,
+ NOW() + plt_overflow_period );
}
static s_time_t __read_platform_stime(u64 platform_time)
diff -r 19970181d6a4 xen/common/timer.c
--- a/xen/common/timer.c Tue Jul 01 14:50:35 2008 +0100
+++ b/xen/common/timer.c Thu Jul 10 10:28:33 2008 +0800
@@ -27,10 +27,16 @@
*/
#define TIMER_SLOP (50*1000) /* ns */
+#define MAX_READY_TIMERS 16
+
struct timers {
spinlock_t lock;
struct timer **heap;
struct timer *running;
+ /* ready timers for next fire */
+ struct timer *ready[MAX_READY_TIMERS];
+ int ready_nr;
+ s_time_t ready_expires;
} __cacheline_aligned;
static DEFINE_PER_CPU(struct timers, timers);
@@ -113,6 +119,29 @@ static int remove_entry(struct timer **h
return (pos == 1);
}
+/* Delete @t from @ready queue, return TRUE if find timer in queue*/
+static int remove_ready_entry(struct timer *t)
+{
+ int i, j, rc = 0;
+ struct timers *ts;
+
+ ts = &per_cpu(timers, t->cpu);
+
+ for ( i = 0; i < ts->ready_nr; i++ )
+ {
+ if ( ts->ready[i] == t )
+ {
+ t->heap_offset = 0;
+ ts->ready_nr--;
+ for ( j = i; j < ts->ready_nr; j++ )
+ ts->ready[j] = ts->ready[j+1];
+ rc = 1;
+ break;
+ }
+ }
+
+ return rc;
+}
/* Add new entry @t to @heap. Return TRUE if new top of heap. */
static int add_entry(struct timer ***pheap, struct timer *t)
@@ -158,7 +187,10 @@ static inline void __stop_timer(struct t
static inline void __stop_timer(struct timer *timer)
{
int cpu = timer->cpu;
- if ( remove_entry(per_cpu(timers, cpu).heap, timer) )
+
+ if ( remove_ready_entry(timer) )
+ cpu_raise_softirq(cpu, TIMER_SOFTIRQ);
+ else if ( remove_entry(per_cpu(timers, cpu).heap, timer) )
cpu_raise_softirq(cpu, TIMER_SOFTIRQ);
}
@@ -191,8 +223,8 @@ static inline void timer_unlock(struct t
#define timer_unlock_irqrestore(t, flags) \
do { timer_unlock(t); local_irq_restore(flags); } while ( 0 )
-
-void set_timer(struct timer *timer, s_time_t expires)
+/* Set timer that can expire in period [expires_start, expires_end] */
+void set_timer_deferrable(struct timer *timer, s_time_t expires_start,
s_time_t expires_end)
{
unsigned long flags;
@@ -201,7 +233,8 @@ void set_timer(struct timer *timer, s_ti
if ( active_timer(timer) )
__stop_timer(timer);
- timer->expires = expires;
+ timer->expires = expires_start;
+ timer->expires_deferred = expires_end;
if ( likely(!timer->killed) )
__add_timer(timer);
@@ -209,6 +242,10 @@ void set_timer(struct timer *timer, s_ti
timer_unlock_irqrestore(timer, flags);
}
+void set_timer(struct timer *timer, s_time_t expires)
+{
+ set_timer_deferrable(timer, expires, expires);
+}
void stop_timer(struct timer *timer)
{
@@ -295,6 +332,7 @@ static void timer_softirq_action(void)
s_time_t now;
void (*fn)(void *);
void *data;
+ int i;
ts = &this_cpu(timers);
@@ -304,6 +342,23 @@ static void timer_softirq_action(void)
heap = ts->heap;
now = NOW();
+ if ( ts->ready_expires < now + TIMER_SLOP )
+ {
+ for ( i = 0; i < ts->ready_nr; i++ )
+ {
+ fn = ts->ready[i]->function;
+ data = ts->ready[i]->data;
+
+ ts->running = ts->ready[i];
+ ts->ready[i]->heap_offset = 0;
+
+ spin_unlock_irq(&ts->lock);
+ (*fn)(data);
+ spin_lock_irq(&ts->lock);
+ }
+ ts->ready_nr = 0;
+ }
+
while ( (GET_HEAP_SIZE(heap) != 0) &&
((t = heap[1])->expires < (now + TIMER_SLOP)) )
{
@@ -322,9 +377,34 @@ static void timer_softirq_action(void)
heap = ts->heap;
}
+ /* queue ready timers for next fire */
+ if ( ts->ready_nr == 0 )
+ {
+ s_time_t start, end;
+
+ start = 0;
+ end = STIME_MAX;
+
+ while ( (GET_HEAP_SIZE(heap) != 0) &&
+ ((t = heap[1])->expires <= end) &&
+ (ts->ready_nr < MAX_READY_TIMERS) )
+ {
+ remove_entry(heap, t);
+
+ start = t->expires;
+ if ( end > t->expires_deferred )
+ end = t->expires_deferred;
+
+ ts->ready[ts->ready_nr++] = t;
+ t->heap_offset = 1; /* mark it still active */
+ }
+
+ ts->ready_expires = (start + end) / 2;
+ }
+
ts->running = NULL;
- this_cpu(timer_deadline) = GET_HEAP_SIZE(heap) ?
heap[1]->expires : 0;
+ this_cpu(timer_deadline) = ts->ready_nr ? ts->ready_expires :
0;
}
while ( !reprogram_timer(this_cpu(timer_deadline)) );
diff -r 19970181d6a4 xen/include/xen/time.h
--- a/xen/include/xen/time.h Tue Jul 01 14:50:35 2008 +0100
+++ b/xen/include/xen/time.h Wed Jul 09 14:49:15 2008 +0800
@@ -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 19970181d6a4 xen/include/xen/timer.h
--- a/xen/include/xen/timer.h Tue Jul 01 14:50:35 2008 +0100
+++ b/xen/include/xen/timer.h Tue Jul 08 16:44:35 2008 +0800
@@ -15,6 +15,7 @@ struct timer {
struct timer {
/* System time expiry value (nanoseconds since boot). */
s_time_t expires;
+ s_time_t expires_deferred;
/* CPU on which this timer will be installed and executed. */
unsigned int cpu;
/* On expiry, '(*function)(data)' will be executed in softirq
context. */
@@ -63,6 +64,9 @@ static inline void init_timer(
* been initialised by init_timer() (so that callback details are
known).
*/
extern void set_timer(struct timer *timer, s_time_t expires);
+
+/* Set timer that can expire in period [expires-offset, expires+offset]
*/
+extern void set_timer_deferrable(struct timer *timer, s_time_t expires,
s_time_t offset);
/*
* Deactivate a timer This function has no effect if the timer is not
currently
deferable-timer.patch
Description: deferable-timer.patch
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|