aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrn@wyvis.research.intel-research.net <rn@wyvis.research.intel-research.net>2003-03-19 19:05:13 +0000
committerrn@wyvis.research.intel-research.net <rn@wyvis.research.intel-research.net>2003-03-19 19:05:13 +0000
commit2687309e0987e504e4129251667eb3a67aad365b (patch)
tree0ef1b56c186ae300ed6c3ed899e68884289e9f2d
parent4c98bbe3d8d0e8747755ae8882fbee4dd8e771f9 (diff)
downloadxen-2687309e0987e504e4129251667eb3a67aad365b.tar.gz
xen-2687309e0987e504e4129251667eb3a67aad365b.tar.bz2
xen-2687309e0987e504e4129251667eb3a67aad365b.zip
bitkeeper revision 1.148 (3e78bf69oU3LgkH_AAzL1qYB6OK3GA)
honour context swicth allowance
-rw-r--r--xen/arch/i386/time.c1
-rw-r--r--xen/common/ac_timer.c46
-rw-r--r--xen/common/keyhandler.c4
-rw-r--r--xen/common/schedule.c113
-rw-r--r--xen/include/xeno/sched.h1
5 files changed, 125 insertions, 40 deletions
diff --git a/xen/arch/i386/time.c b/xen/arch/i386/time.c
index 9c217d9e5b..c7986135b2 100644
--- a/xen/arch/i386/time.c
+++ b/xen/arch/i386/time.c
@@ -401,6 +401,7 @@ int __init init_xeno_time()
/* start timer to update time periodically */
init_ac_timer(&update_timer, 0);
+ update_timer.data = 1;
update_timer.function = &update_time;
update_time(0);
diff --git a/xen/common/ac_timer.c b/xen/common/ac_timer.c
index 0c71375297..1e5d3f6bcd 100644
--- a/xen/common/ac_timer.c
+++ b/xen/common/ac_timer.c
@@ -256,30 +256,6 @@ void do_ac_timer(void)
}
-/*****************************************************************************
- * debug dump_queue
- * arguments: queue head, name of queue
- *****************************************************************************/
-static void dump_tqueue(struct list_head *queue, char *name)
-{
- struct list_head *list;
- int loop = 0;
- struct ac_timer *t;
-
- printk ("QUEUE %s %lx n: %lx, p: %lx\n", name, (unsigned long)queue,
- (unsigned long) queue->next, (unsigned long) queue->prev);
- list_for_each (list, queue) {
- t = list_entry(list, struct ac_timer, timer_list);
- printk (" %s %d : %lx ex=0x%08X%08X %lu n: %lx, p: %lx\n",
- name, loop++,
- (unsigned long)list,
- (u32)(t->expires>>32), (u32)t->expires, t->data,
- (unsigned long)list->next, (unsigned long)list->prev);
- }
- return;
-}
-
-
static void ac_timer_softirq_action(struct softirq_action *a)
{
int cpu = smp_processor_id();
@@ -312,6 +288,28 @@ static void ac_timer_softirq_action(struct softirq_action *a)
}
}
+/*****************************************************************************
+ * debug dump_queue
+ * arguments: queue head, name of queue
+ *****************************************************************************/
+static void dump_tqueue(struct list_head *queue, char *name)
+{
+ struct list_head *list;
+ int loop = 0;
+ struct ac_timer *t;
+
+ printk ("QUEUE %s %lx n: %lx, p: %lx\n", name, (unsigned long)queue,
+ (unsigned long) queue->next, (unsigned long) queue->prev);
+ list_for_each (list, queue) {
+ t = list_entry(list, struct ac_timer, timer_list);
+ printk (" %s %d : %lx ex=0x%08X%08X %lu n: %lx, p: %lx\n",
+ name, loop++,
+ (unsigned long)list,
+ (u32)(t->expires>>32), (u32)t->expires, t->data,
+ (unsigned long)list->next, (unsigned long)list->prev);
+ }
+ return;
+}
void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs)
{
diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c
index dde9e0ff10..93b9132a7f 100644
--- a/xen/common/keyhandler.c
+++ b/xen/common/keyhandler.c
@@ -118,6 +118,8 @@ extern void perfc_printall (u_char key, void *dev_id, struct pt_regs *regs);
extern void perfc_reset (u_char key, void *dev_id, struct pt_regs *regs);
extern void dump_timerq(u_char key, void *dev_id, struct pt_regs *regs);
extern void dump_runq(u_char key, void *dev_id, struct pt_regs *regs);
+extern void print_sched_histo(u_char key, void *dev_id, struct pt_regs *regs);
+extern void reset_sched_histo(u_char key, void *dev_id, struct pt_regs *regs);
void initialize_keytable()
@@ -132,6 +134,8 @@ void initialize_keytable()
add_key_handler('a', dump_timerq, "dump ac_timer queues");
add_key_handler('d', dump_registers, "dump registers");
add_key_handler('h', show_handlers, "show this message");
+ add_key_handler('l', print_sched_histo, "print sched latency histogram");
+ add_key_handler('L', reset_sched_histo, "reset sched latency histogram");
add_key_handler('p', perfc_printall, "print performance counters");
add_key_handler('P', perfc_reset, "reset performance counters");
add_key_handler('q', do_task_queues, "dump task queues + guest state");
diff --git a/xen/common/schedule.c b/xen/common/schedule.c
index 678b841e0b..51fd45b428 100644
--- a/xen/common/schedule.c
+++ b/xen/common/schedule.c
@@ -39,9 +39,15 @@
#define TRC(_x)
#endif
+#define SCHED_HISTO
+#ifdef SCHED_HISTO
+#define BUCKETS 31
+#endif
+
-#define MCU (s32)MICROSECS(100) /* Minimum unit */
-static s32 ctx_allow=(s32)MILLISECS(10); /* context switch allowance */
+#define MCU (s32)MICROSECS(100) /* Minimum unit */
+#define TIME_SLOP (s32)MICROSECS(50) /* allow time to slip a bit */
+static s32 ctx_allow=(s32)MILLISECS(5); /* context switch allowance */
/*****************************************************************************
* per CPU data for the scheduler.
@@ -54,6 +60,9 @@ typedef struct schedule_data_st
struct task_struct *idle; /* idle task for this cpu */
u32 svt; /* system virtual time. per CPU??? */
struct ac_timer s_timer; /* scheduling timer */
+#ifdef SCHED_HISTO
+ u32 hist[BUCKETS]; /* for scheduler latency histogram */
+#endif
} __cacheline_aligned schedule_data_t;
schedule_data_t schedule_data[NR_CPUS];
@@ -140,8 +149,11 @@ int wake_up(struct task_struct *p)
p->evt = p->avt; /* RN: XXX BVT deal with warping here */
- ret = 1;
+#ifdef SCHED_HISTO
+ p->wokenup = NOW();
+#endif
+ ret = 1;
out:
spin_unlock_irqrestore(&schedule_data[p->processor].lock, flags);
return ret;
@@ -194,36 +206,46 @@ long sched_adjdom(int dom, unsigned long mcu_adv, unsigned long warp,
* cause a run through the scheduler when appropriate
* Appropriate is:
* - current task is idle task
- * - new processes evt is lower than current one
* - the current task already ran for it's context switch allowance
- * XXX RN: not quite sure about the last two. Strictly, if p->evt < curr->evt
- * should still let curr run for at least ctx_allow. But that gets quite messy.
+ * Otherwise we do a run through the scheduler after the current tasks
+ * context switch allowance is over.
****************************************************************************/
void reschedule(struct task_struct *p)
{
- int cpu = p->processor;
+ int cpu = p->processor;;
struct task_struct *curr;
unsigned long flags;
+ s_time_t now, min_time;
if (p->has_cpu)
return;
spin_lock_irqsave(&schedule_data[cpu].lock, flags);
+
+ now = NOW();
curr = schedule_data[cpu].curr;
+ /* domain should run at least for ctx_allow */
+ min_time = curr->lastschd + ctx_allow;
- if ( is_idle_task(curr) ||
- (p->evt < curr->evt) ||
- (curr->lastschd + ctx_allow >= NOW()) ) {
+ if ( is_idle_task(curr) || (min_time <= now) ) {
/* reschedule */
set_bit(_HYP_EVENT_NEED_RESCHED, &curr->hyp_events);
+
spin_unlock_irqrestore(&schedule_data[cpu].lock, flags);
-#ifdef CONFIG_SMP
+
if (cpu != smp_processor_id())
smp_send_event_check_cpu(cpu);
-#endif
- } else {
- spin_unlock_irqrestore(&schedule_data[cpu].lock, flags);
+ return;
}
+
+ /* current hasn't been running for long enough -> reprogram timer.
+ * but don't bother if timer would go off soon anyway */
+ if (schedule_data[cpu].s_timer.expires > min_time + TIME_SLOP) {
+ mod_ac_timer(&schedule_data[cpu].s_timer, min_time);
+ }
+
+ spin_unlock_irqrestore(&schedule_data[cpu].lock, flags);
+ return;
}
@@ -258,7 +280,8 @@ asmlinkage void schedule(void)
now = NOW();
- /* remove timer */
+ /* remove timer, if till on list */
+ //if (active_ac_timer(&schedule_data[this_cpu].s_timer))
rem_ac_timer(&schedule_data[this_cpu].s_timer);
/* deschedule the current domain */
@@ -369,6 +392,13 @@ asmlinkage void schedule(void)
sched_done:
ASSERT(r_time >= ctx_allow);
+#ifndef NDEBUG
+ if (r_time < ctx_allow) {
+ printk("[%02d]: %lx\n", this_cpu, r_time);
+ dump_rqueue(&schedule_data[this_cpu].runqueue, "foo");
+ }
+#endif
+
prev->has_cpu = 0;
next->has_cpu = 1;
@@ -391,6 +421,19 @@ asmlinkage void schedule(void)
}
perfc_incrc(sched_ctx);
+#ifdef SCHED_HISTO
+ {
+ ulong diff; /* should fit in 32bits */
+ if (!is_idle_task(next) && next->wokenup) {
+ diff = (ulong)(now - next->wokenup);
+ diff /= (ulong)MILLISECS(1);
+ if (diff <= BUCKETS-2) schedule_data[this_cpu].hist[diff]++;
+ else schedule_data[this_cpu].hist[BUCKETS-1]++;
+ }
+ next->wokenup = (s_time_t)0;
+ }
+#endif
+
prepare_to_switch();
switch_to(prev, next);
@@ -450,7 +493,7 @@ static void virt_timer(unsigned long foo)
guest_event_notify(cpu_mask);
now = NOW();
- v_timer.expires = now + MILLISECS(10);
+ v_timer.expires = now + MILLISECS(20);
add_ac_timer(&v_timer);
}
@@ -472,11 +515,13 @@ void __init scheduler_init(void)
/* a timer for each CPU */
init_ac_timer(&schedule_data[i].s_timer, i);
+ schedule_data[i].s_timer.data = 2;
schedule_data[i].s_timer.function = &sched_timer;
}
schedule_data[0].idle = &idle0_task; /* idle on CPU 0 is special */
init_ac_timer(&v_timer, 0);
+ v_timer.data = 3;
v_timer.function = &virt_timer;
}
@@ -603,3 +648,39 @@ void dump_runq(u_char key, void *dev_id, struct pt_regs *regs)
return;
}
+#ifdef SCHED_HISTO
+void print_sched_histo(u_char key, void *dev_id, struct pt_regs *regs)
+{
+ int loop, i, j;
+ for (loop = 0; loop < smp_num_cpus; loop++) {
+ j = 0;
+ printf ("CPU[%02d]: scheduler latency histogram (ms:[count])\n", loop);
+ for (i=0; i<BUCKETS; i++) {
+ if (schedule_data[loop].hist[i]) {
+ if (i < BUCKETS-1)
+ printk("%2d:[%7u] ", i, schedule_data[loop].hist[i]);
+ else
+ printk(" >:[%7u] ", schedule_data[loop].hist[i]);
+ j++;
+ if (!(j % 5)) printk("\n");
+ }
+ }
+ printk("\n");
+ }
+
+}
+void reset_sched_histo(u_char key, void *dev_id, struct pt_regs *regs)
+{
+ int loop, i;
+ for (loop = 0; loop < smp_num_cpus; loop++)
+ for (i=0; i<BUCKETS; i++)
+ schedule_data[loop].hist[i]=0;
+}
+#else
+void print_sched_histo(u_char key, void *dev_id, struct pt_regs *regs)
+{
+}
+void reset_sched_histo(u_char key, void *dev_id, struct pt_regs *regs)
+{
+}
+#endif
diff --git a/xen/include/xeno/sched.h b/xen/include/xeno/sched.h
index 81bbd6e895..555efd9e81 100644
--- a/xen/include/xeno/sched.h
+++ b/xen/include/xeno/sched.h
@@ -94,6 +94,7 @@ struct task_struct {
s_time_t lastschd; /* time this domain was last scheduled */
s_time_t cpu_time; /* total CPU time received till now */
+ s_time_t wokenup; /* time domain got woken up */
unsigned long mcu_advance; /* inverse of weight */
s32 avt; /* actual virtual time */