diff options
author | rn@wyvis.research.intel-research.net <rn@wyvis.research.intel-research.net> | 2003-03-19 19:05:13 +0000 |
---|---|---|
committer | rn@wyvis.research.intel-research.net <rn@wyvis.research.intel-research.net> | 2003-03-19 19:05:13 +0000 |
commit | 2687309e0987e504e4129251667eb3a67aad365b (patch) | |
tree | 0ef1b56c186ae300ed6c3ed899e68884289e9f2d | |
parent | 4c98bbe3d8d0e8747755ae8882fbee4dd8e771f9 (diff) | |
download | xen-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.c | 1 | ||||
-rw-r--r-- | xen/common/ac_timer.c | 46 | ||||
-rw-r--r-- | xen/common/keyhandler.c | 4 | ||||
-rw-r--r-- | xen/common/schedule.c | 113 | ||||
-rw-r--r-- | xen/include/xeno/sched.h | 1 |
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 */ |