Hi, Considering the recent attention on CPU schedulers, so here is an updated version of my scheduler against 2.6.21-rc4. I often run it on my own desktop here here and it works well for me, no guarantees! I would be happy if anyone was interested in testing it :)
Thanks, Nick -- SUSE Labs, Novell Inc.
Forward port of nicksched to 2.6.21-rc4. Can't find my old design/description document for it, but it is yet another scheduler. Focus is on simplicity and fairness. This one tends to require X to be reniced to -10 or so for best results (renice -10 `pidof X`). Timeslices get scaled by /proc/sys/kernel/base_timeslice. If you have bad interactivity you could try lowering this and see if it helps. fs/proc/array.c | 12 include/linux/init_task.h | 7 include/linux/sched.h | 34 - include/linux/sysctl.h | 1 kernel/sched.c | 1122 +++++++++++++++++----------------------------- kernel/sysctl.c | 16 mm/oom_kill.c | 7 7 files changed, 476 insertions(+), 723 deletions(-) Index: linux-2.6/fs/proc/array.c =================================================================== --- linux-2.6.orig/fs/proc/array.c 2007-03-22 20:44:00.000000000 +1100 +++ linux-2.6/fs/proc/array.c 2007-03-22 20:44:20.000000000 +1100 @@ -165,7 +165,13 @@ static inline char * task_state(struct t rcu_read_lock(); buffer += sprintf(buffer, "State:\t%s\n" - "SleepAVG:\t%lu%%\n" + "timeslice:\t%d\n" + "usedslice:\t%d\n" + "arrayseq:\t%lu\n" + "staticprio:\t%u\n" + "prio:\t%u\n" + "sleep_time:\t%lu\n" + "total_time:\t%lu\n" "Tgid:\t%d\n" "Pid:\t%d\n" "PPid:\t%d\n" @@ -173,7 +179,9 @@ static inline char * task_state(struct t "Uid:\t%d\t%d\t%d\t%d\n" "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), - (p->sleep_avg/1024)*100/(1020000000/1024), + get_task_timeslice(p), p->used_slice, p->array_sequence, + p->static_prio, p->prio, + p->sleep_time, p->total_time, p->tgid, p->pid, pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0, pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0, Index: linux-2.6/include/linux/sched.h =================================================================== --- linux-2.6.orig/include/linux/sched.h 2007-03-22 20:44:00.000000000 +1100 +++ linux-2.6/include/linux/sched.h 2007-03-22 20:45:18.000000000 +1100 @@ -523,7 +523,7 @@ struct signal_struct { #define MAX_USER_RT_PRIO 100 #define MAX_RT_PRIO MAX_USER_RT_PRIO -#define MAX_PRIO (MAX_RT_PRIO + 40) +#define MAX_PRIO (MAX_RT_PRIO + 59) #define rt_prio(prio) unlikely((prio) < MAX_RT_PRIO) #define rt_task(p) rt_prio((p)->prio) @@ -788,24 +788,16 @@ struct mempolicy; struct pipe_inode_info; struct uts_namespace; -enum sleep_type { - SLEEP_NORMAL, - SLEEP_NONINTERACTIVE, - SLEEP_INTERACTIVE, - SLEEP_INTERRUPTED, -}; - struct prio_array; struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ struct thread_info *thread_info; atomic_t usage; + int lock_depth; /* BKL lock depth */ unsigned long flags; /* per process flags, defined below */ unsigned long ptrace; - int lock_depth; /* BKL lock depth */ - #ifdef CONFIG_SMP #ifdef __ARCH_WANT_UNLOCKED_CTXSW int oncpu; @@ -813,27 +805,29 @@ struct task_struct { #endif int load_weight; /* for niceness load balancing purposes */ int prio, static_prio, normal_prio; + int used_slice, over_slice; struct list_head run_list; struct prio_array *array; + unsigned long array_sequence; - unsigned short ioprio; -#ifdef CONFIG_BLK_DEV_IO_TRACE - unsigned int btrace_seq; -#endif - unsigned long sleep_avg; unsigned long long timestamp, last_ran; unsigned long long sched_time; /* sched_clock time spent running */ - enum sleep_type sleep_type; + unsigned long total_time, sleep_time; + + struct list_head tasks; + struct mm_struct *mm, *active_mm; unsigned long policy; cpumask_t cpus_allowed; - unsigned int time_slice, first_time_slice; #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) struct sched_info sched_info; #endif - struct list_head tasks; + unsigned short ioprio; +#ifdef CONFIG_BLK_DEV_IO_TRACE + unsigned int btrace_seq; +#endif /* * ptrace_list/ptrace_children forms the list of my children * that were stolen by a ptracer. @@ -841,8 +835,6 @@ struct task_struct { struct list_head ptrace_children; struct list_head ptrace_list; - struct mm_struct *mm, *active_mm; - /* task state */ struct linux_binfmt *binfmt; long exit_state; @@ -1199,6 +1191,8 @@ extern unsigned long long sched_clock(vo extern unsigned long long current_sched_time(const struct task_struct *current_task); +extern int get_task_timeslice(struct task_struct *t); + /* sched_exec is called by processes performing an exec */ #ifdef CONFIG_SMP extern void sched_exec(void); Index: linux-2.6/kernel/sched.c =================================================================== --- linux-2.6.orig/kernel/sched.c 2007-03-22 20:44:00.000000000 +1100 +++ linux-2.6/kernel/sched.c 2007-03-22 20:48:52.000000000 +1100 @@ -71,129 +71,68 @@ unsigned long long __attribute__((weak)) * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], * and back. */ -#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20) -#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20) #define TASK_NICE(p) PRIO_TO_NICE((p)->static_prio) +#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 30) +#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 30) /* * 'User priority' is the nice value converted to something we * can work with better when scaling various scheduler parameters, - * it's a [ 0 ... 39 ] range. + * it's a [ 0 ... 58 ] range. */ #define USER_PRIO(p) ((p)-MAX_RT_PRIO) -#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio) #define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) +#define US_TO_JIFFIES(x) ((x) * HZ / 1000000) +#define JIFFIES_TO_US(x) ((x) * 1000000 / HZ) + /* - * Some helpers for converting nanosecond timing to jiffy resolution + * MIN_TIMESLICE is the timeslice that a minimum priority process gets if there + * is a maximum priority process runnable. MAX_TIMESLICE is derived from the + * formula in task_timeslice. It cannot be changed here. It is the timesilce + * that the maximum priority process will get. Larger timeslices are attainable + * by low priority processes however. */ -#define NS_TO_JIFFIES(TIME) ((TIME) / (1000000000 / HZ)) -#define JIFFIES_TO_NS(TIME) ((TIME) * (1000000000 / HZ)) +int sched_base_timeslice = 300; +int sched_min_base = 10; +int sched_max_base = 10000; + +#define MIN_TIMESLICE 1 +#define RT_TIMESLICE (50 * 1000 / HZ) /* 50ms */ +#define BASE_TIMESLICE (sched_base_timeslice) + +/* Maximum amount of history that will be used to calculate priority */ +#define MAX_SLEEP_SHIFT 18 +#define MAX_SLEEP (1UL << MAX_SLEEP_SHIFT) /* ~0.25s */ /* - * These are the 'tuning knobs' of the scheduler: + * Maximum effect that 1 block of activity (run/sleep/etc) can have. This is + * will moderate dicard freak events (eg. SIGSTOP) * - * Minimum timeslice is 5 msecs (or 1 jiffy, whichever is larger), - * default timeslice is 100 msecs, maximum timeslice is 800 msecs. - * Timeslices get refilled after they expire. */ -#define MIN_TIMESLICE max(5 * HZ / 1000, 1) -#define DEF_TIMESLICE (100 * HZ / 1000) -#define ON_RUNQUEUE_WEIGHT 30 -#define CHILD_PENALTY 95 -#define PARENT_PENALTY 100 -#define EXIT_WEIGHT 3 -#define PRIO_BONUS_RATIO 25 -#define MAX_BONUS (MAX_USER_PRIO * PRIO_BONUS_RATIO / 100) -#define INTERACTIVE_DELTA 2 -#define MAX_SLEEP_AVG (DEF_TIMESLICE * MAX_BONUS) -#define STARVATION_LIMIT (MAX_SLEEP_AVG) -#define NS_MAX_SLEEP_AVG (JIFFIES_TO_NS(MAX_SLEEP_AVG)) +#define MAX_SLEEP_AFFECT (MAX_SLEEP/4) /* - * If a task is 'interactive' then we reinsert it in the active - * array after it has expired its current timeslice. (it will not - * continue to run immediately, it will still roundrobin with - * other interactive tasks.) - * - * This part scales the interactivity limit depending on niceness. - * - * We scale it linearly, offset by the INTERACTIVE_DELTA delta. - * Here are a few examples of different nice levels: - * - * TASK_INTERACTIVE(-20): [1,1,1,1,1,1,1,1,1,0,0] - * TASK_INTERACTIVE(-10): [1,1,1,1,1,1,1,0,0,0,0] - * TASK_INTERACTIVE( 0): [1,1,1,1,0,0,0,0,0,0,0] - * TASK_INTERACTIVE( 10): [1,1,0,0,0,0,0,0,0,0,0] - * TASK_INTERACTIVE( 19): [0,0,0,0,0,0,0,0,0,0,0] - * - * (the X axis represents the possible -5 ... 0 ... +5 dynamic - * priority range a task can explore, a value of '1' means the - * task is rated interactive.) - * - * Ie. nice +19 tasks can never get 'interactive' enough to be - * reinserted into the active array. And only heavily CPU-hog nice -20 - * tasks will be expired. Default nice 0 tasks are somewhere between, - * it takes some effort for them to get interactive, but it's not - * too hard. + * The amount of history can be decreased (on fork for example). This puts a + * lower bound on it. */ +#define MIN_HISTORY (MAX_SLEEP/8) +#define FORKED_TS_MAX (US_TO_JIFFIES(10000) ?: 1) -#define CURRENT_BONUS(p) \ - (NS_TO_JIFFIES((p)->sleep_avg) * MAX_BONUS / \ - MAX_SLEEP_AVG) - -#define GRANULARITY (10 * HZ / 1000 ? : 1) - -#ifdef CONFIG_SMP -#define TIMESLICE_GRANULARITY(p) (GRANULARITY * \ - (1 << (((MAX_BONUS - CURRENT_BONUS(p)) ? : 1) - 1)) * \ - num_online_cpus()) -#else -#define TIMESLICE_GRANULARITY(p) (GRANULARITY * \ - (1 << (((MAX_BONUS - CURRENT_BONUS(p)) ? : 1) - 1))) -#endif - -#define SCALE(v1,v1_max,v2_max) \ - (v1) * (v2_max) / (v1_max) - -#define DELTA(p) \ - (SCALE(TASK_NICE(p) + 20, 40, MAX_BONUS) - 20 * MAX_BONUS / 40 + \ - INTERACTIVE_DELTA) - -#define TASK_INTERACTIVE(p) \ - ((p)->prio <= (p)->static_prio - DELTA(p)) - -#define INTERACTIVE_SLEEP(p) \ - (JIFFIES_TO_NS(MAX_SLEEP_AVG * \ - (MAX_BONUS / 2 + DELTA((p)) + 1) / MAX_BONUS - 1)) - -#define TASK_PREEMPTS_CURR(p, rq) \ - ((p)->prio < (rq)->curr->prio) - -#define SCALE_PRIO(x, prio) \ - max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE) - -static unsigned int static_prio_timeslice(int static_prio) -{ - if (static_prio < NICE_TO_PRIO(0)) - return SCALE_PRIO(DEF_TIMESLICE * 4, static_prio); - else - return SCALE_PRIO(DEF_TIMESLICE, static_prio); -} +/* + * SLEEP_FACTOR is a fixed point factor used to scale history tracking things. + * In particular: total_time, sleep_time, sleep_avg. + */ +#define SLEEP_FACTOR 1024 /* - * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ] - * to time slice values: [800ms ... 100ms ... 5ms] - * - * The higher a thread's priority, the bigger timeslices - * it gets during one round of execution. But even the lowest - * priority thread gets MIN_TIMESLICE worth of execution time. + * The scheduler classifies a process as performing one of the following + * activities */ +#define STIME_SLEEP 1 /* Sleeping */ +#define STIME_RUN 2 /* Using CPU */ -static inline unsigned int task_timeslice(struct task_struct *p) -{ - return static_prio_timeslice(p->static_prio); -} +#define TASK_PREEMPTS_CURR(p, rq) ((p)->prio < (rq)->curr->prio) /* * These are the runqueue data structures: @@ -224,6 +163,7 @@ struct rq { #ifdef CONFIG_SMP unsigned long cpu_load[3]; #endif + unsigned long array_sequence; unsigned long long nr_switches; /* @@ -234,15 +174,13 @@ struct rq { */ unsigned long nr_uninterruptible; - unsigned long expired_timestamp; - /* Cached timestamp set by update_cpu_clock() */ - unsigned long long most_recent_timestamp; struct task_struct *curr, *idle; unsigned long next_balance; struct mm_struct *prev_mm; - struct prio_array *active, *expired, arrays[2]; - int best_expired_prio; atomic_t nr_iowait; + int min_expired_prio; + struct prio_array *active, *expired, arrays[2]; +// struct list_head quotient_queue[10]; #ifdef CONFIG_SMP struct sched_domain *sd; @@ -261,9 +199,6 @@ struct rq { struct sched_info rq_sched_info; /* sys_sched_yield() stats */ - unsigned long yld_exp_empty; - unsigned long yld_act_empty; - unsigned long yld_both_empty; unsigned long yld_cnt; /* schedule() stats */ @@ -411,9 +346,8 @@ static struct rq *task_rq_lock(struct ta struct rq *rq; repeat_lock_task: - local_irq_save(*flags); rq = task_rq(p); - spin_lock(&rq->lock); + spin_lock_irqsave(&rq->lock, *flags); if (unlikely(rq != task_rq(p))) { spin_unlock_irqrestore(&rq->lock, *flags); goto repeat_lock_task; @@ -456,8 +390,8 @@ static int show_schedstat(struct seq_fil /* runqueue-specific stats */ seq_printf(seq, "cpu%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", - cpu, rq->yld_both_empty, - rq->yld_act_empty, rq->yld_exp_empty, rq->yld_cnt, + cpu, + 0UL, 0UL, 0UL, rq->yld_cnt, rq->sched_switch, rq->sched_cnt, rq->sched_goidle, rq->ttwu_cnt, rq->ttwu_local, rq->rq_sched_info.cpu_time, @@ -561,21 +495,6 @@ rq_sched_info_depart(struct rq *rq, unsi # define schedstat_add(rq, field, amt) do { } while (0) #endif -/* - * this_rq_lock - lock this runqueue and disable interrupts. - */ -static inline struct rq *this_rq_lock(void) - __acquires(rq->lock) -{ - struct rq *rq; - - local_irq_disable(); - rq = this_rq(); - spin_lock(&rq->lock); - - return rq; -} - #if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT) /* * Called when a process is dequeued from the active array and given @@ -682,6 +601,12 @@ sched_info_switch(struct task_struct *pr #define sched_info_switch(t, next) do { } while (0) #endif /* CONFIG_SCHEDSTATS || CONFIG_TASK_DELAY_ACCT */ +static inline void update_min_expired_prio(struct task_struct *p, struct rq *rq) +{ + if (!rt_task(p) && p->static_prio < rq->min_expired_prio) + rq->min_expired_prio = p->static_prio; +} + /* * Adding/removing a task to/from a priority array: */ @@ -695,22 +620,15 @@ static void dequeue_task(struct task_str static void enqueue_task(struct task_struct *p, struct prio_array *array) { + struct list_head *entry = array->queue + p->prio; + sched_info_queued(p); - list_add_tail(&p->run_list, array->queue + p->prio); + list_add_tail(&p->run_list, entry); __set_bit(p->prio, array->bitmap); array->nr_active++; p->array = array; } -/* - * Put task to the end of the run list without the overhead of dequeue - * followed by enqueue. - */ -static void requeue_task(struct task_struct *p, struct prio_array *array) -{ - list_move_tail(&p->run_list, array->queue + p->prio); -} - static inline void enqueue_task_head(struct task_struct *p, struct prio_array *array) { @@ -721,35 +639,6 @@ enqueue_task_head(struct task_struct *p, } /* - * __normal_prio - return the priority that is based on the static - * priority but is modified by bonuses/penalties. - * - * We scale the actual sleep average [0 .... MAX_SLEEP_AVG] - * into the -5 ... 0 ... +5 bonus/penalty range. - * - * We use 25% of the full 0...39 priority range so that: - * - * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs. - * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks. - * - * Both properties are important to certain workloads. - */ - -static inline int __normal_prio(struct task_struct *p) -{ - int bonus, prio; - - bonus = CURRENT_BONUS(p) - MAX_BONUS / 2; - - prio = p->static_prio - bonus; - if (prio < MAX_RT_PRIO) - prio = MAX_RT_PRIO; - if (prio > MAX_PRIO-1) - prio = MAX_PRIO-1; - return prio; -} - -/* * To aid in avoiding the subversion of "niceness" due to uneven distribution * of tasks with abnormal "nice" values across CPUs the contribution that * each task makes to its run queue's load is weighted according to its @@ -758,12 +647,17 @@ static inline int __normal_prio(struct t * slice expiry etc. */ +static int static_prio_timeslice(unsigned int prio) +{ + return BASE_TIMESLICE; /* XXX: fixme for smpnice */ +} + /* - * Assume: static_prio_timeslice(NICE_TO_PRIO(0)) == DEF_TIMESLICE + * Assume: static_prio_timeslice(NICE_TO_PRIO(0)) == BASE_TIMESLICE * If static_prio_timeslice() is ever changed to break this assumption then * this code will need modification */ -#define TIME_SLICE_NICE_ZERO DEF_TIMESLICE +#define TIME_SLICE_NICE_ZERO BASE_TIMESLICE #define LOAD_WEIGHT(lp) \ (((lp) * SCHED_LOAD_SCALE) / TIME_SLICE_NICE_ZERO) #define PRIO_TO_LOAD_WEIGHT(prio) \ @@ -813,134 +707,153 @@ static inline void dec_nr_running(struct dec_raw_weighted_load(rq, p); } + +static inline long long sched_clock_us(void) +{ + return ((unsigned long long)jiffies) << (20 - SHIFT_HZ); +} + /* - * Calculate the expected normal priority: i.e. priority - * without taking RT-inheritance into account. Might be - * boosted by interactivity modifiers. Changes upon fork, - * setprio syscalls, and whenever the interactivity - * estimator recalculates. + * add_task_time updates a task p after time of doing the specified @type + * of activity. See STIME_*. This is used for priority calculation. */ -static inline int normal_prio(struct task_struct *p) +static void add_task_time(struct task_struct *p, + unsigned long long time, unsigned long type) { - int prio; + unsigned long ratio; + unsigned long long tmp; + unsigned long t; - if (has_rt_policy(p)) - prio = MAX_RT_PRIO-1 - p->rt_priority; - else - prio = __normal_prio(p); - return prio; + if (!time) + return; + + t = time; + if (type == STIME_SLEEP) { + unsigned long fac; + fac = USER_PRIO(p->static_prio); /* 0..39 */ + fac = fac + 12; /* 12..41 */ + if (time > MAX_SLEEP_AFFECT*8) + t = MAX_SLEEP_AFFECT*8; + t = (t * fac) / 32; + t = (t + 7) / 8; + } else { + if (time > MAX_SLEEP) + t = MAX_SLEEP; + } + + ratio = MAX_SLEEP - t; + tmp = (unsigned long long)ratio*p->total_time + MAX_SLEEP/2; + tmp >>= MAX_SLEEP_SHIFT; + p->total_time = (unsigned long)tmp; + + tmp = (unsigned long long)ratio*p->sleep_time + MAX_SLEEP/2; + tmp >>= MAX_SLEEP_SHIFT; + p->sleep_time = (unsigned long)tmp; + + p->total_time += t; + if (type == STIME_SLEEP) + p->sleep_time += t; } -/* - * Calculate the current priority, i.e. the priority - * taken into account by the scheduler. This value might - * be boosted by RT tasks, or might be boosted by - * interactivity modifiers. Will be RT if the task got - * RT-boosted. If not then it returns p->normal_prio. - */ -static int effective_prio(struct task_struct *p) -{ - p->normal_prio = normal_prio(p); - /* - * If we are RT tasks or we were boosted to RT priority, - * keep the priority unchanged. Otherwise, update priority - * to the normal priority: - */ - if (!rt_prio(p->prio)) - return p->normal_prio; - return p->prio; +static inline unsigned long task_sleep_avg(struct task_struct *p) +{ + return (SLEEP_FACTOR * p->sleep_time) / (p->total_time + 1); } /* - * __activate_task - move a task to the runqueue. + * The higher a thread's priority, the bigger timeslices + * it gets during one round of execution. But even the lowest + * priority thread gets MIN_TIMESLICE worth of execution time. + * + * Timeslices are scaled, so if only low priority processes are running, + * they will all get long timeslices. */ -static void __activate_task(struct task_struct *p, struct rq *rq) +static int task_timeslice(struct task_struct *p, struct rq *rq) { - struct prio_array *target = rq->active; + unsigned int prio, delta, scale, ts; - if (batch_task(p)) - target = rq->expired; - enqueue_task(p, target); - inc_nr_running(p, rq); + if (rt_task(p)) + return RT_TIMESLICE; + + /* prio is 10..49 */ + prio = USER_PRIO(p->static_prio) - 10 + 9; + + ts = prio * 1024; /* 10240..50176 */ + + /* delta is 3..42 (delta-3 <= prio-9) */ + delta = p->static_prio - min(rq->min_expired_prio, p->static_prio) + 3; + + scale = delta*delta; /* 9..1764 */ + + ts = ts / scale; /* 1137..(28..5575) */ + + /* a nice 0 task has ts (29*29/9) here. scale to BASE_TIMESLICE */ + ts = ts * BASE_TIMESLICE / (29*1024/9); + + ts = msecs_to_jiffies(ts); + if (unlikely(ts == 0)) + ts = 1; + + return ts; } -/* - * __activate_idle_task - move idle task to the _front_ of runqueue. - */ -static inline void __activate_idle_task(struct task_struct *p, struct rq *rq) +int get_task_timeslice(struct task_struct *p) { - enqueue_task_head(p, rq->active); - inc_nr_running(p, rq); + int ts; + struct rq *rq; + unsigned long flags; + rq = task_rq_lock(p, &flags); + ts = task_timeslice(p, rq); + task_rq_unlock(rq, &flags); + + return ts; } /* - * Recalculate p->normal_prio and p->prio after having slept, - * updating the sleep-average too: + * task_priority: calculates a task's priority based on previous running + * history (see add_task_time). The priority is just a simple linear function + * based on sleep_avg and static_prio. */ -static int recalc_task_prio(struct task_struct *p, unsigned long long now) +static int task_priority(struct task_struct *p) { - /* Caller must always ensure 'now >= p->timestamp' */ - unsigned long sleep_time = now - p->timestamp; + unsigned long sleep_avg; + int bonus, prio; - if (batch_task(p)) - sleep_time = 0; + if (rt_prio(p->prio)) + return p->prio; - if (likely(sleep_time > 0)) { - /* - * This ceiling is set to the lowest priority that would allow - * a task to be reinserted into the active array on timeslice - * completion. - */ - unsigned long ceiling = INTERACTIVE_SLEEP(p); + sleep_avg = task_sleep_avg(p); - if (p->mm && sleep_time > ceiling && p->sleep_avg < ceiling) { - /* - * Prevents user tasks from achieving best priority - * with one single large enough sleep. - */ - p->sleep_avg = ceiling; - /* - * Using INTERACTIVE_SLEEP() as a ceiling places a - * nice(0) task 1ms sleep away from promotion, and - * gives it 700ms to round-robin with no chance of - * being demoted. This is more than generous, so - * mark this sleep as non-interactive to prevent the - * on-runqueue bonus logic from intervening should - * this task not receive cpu immediately. - */ - p->sleep_type = SLEEP_NONINTERACTIVE; - } else { - /* - * Tasks waking from uninterruptible sleep are - * limited in their sleep_avg rise as they - * are likely to be waiting on I/O - */ - if (p->sleep_type == SLEEP_NONINTERACTIVE && p->mm) { - if (p->sleep_avg >= ceiling) - sleep_time = 0; - else if (p->sleep_avg + sleep_time >= - ceiling) { - p->sleep_avg = ceiling; - sleep_time = 0; - } - } + prio = USER_PRIO(p->static_prio) + 10; + bonus = (((MAX_USER_PRIO + 1) / 3) * sleep_avg + (SLEEP_FACTOR / 2)) + / SLEEP_FACTOR; + prio = MAX_RT_PRIO + prio - bonus; - /* - * This code gives a bonus to interactive tasks. - * - * The boost works by updating the 'average sleep time' - * value here, based on ->timestamp. The more time a - * task spends sleeping, the higher the average gets - - * and the higher the priority boost gets as well. - */ - p->sleep_avg += sleep_time; + if (prio < MAX_RT_PRIO) + return MAX_RT_PRIO; + if (prio > MAX_PRIO-1) + return MAX_PRIO-1; - } - if (p->sleep_avg > NS_MAX_SLEEP_AVG) - p->sleep_avg = NS_MAX_SLEEP_AVG; - } + return prio; +} - return effective_prio(p); +/* + * __activate_task - move a task to the runqueue. + */ +static inline void __activate_task(struct task_struct *p, struct rq *rq, + struct prio_array *array) +{ + enqueue_task(p, array); + rq->nr_running++; +} + +/* + * __activate_idle_task - move idle task to the _front_ of runqueue. + */ +static inline void __activate_idle_task(struct task_struct *p, struct rq *rq) +{ + enqueue_task_head(p, rq->active); + inc_nr_running(p, rq); } /* @@ -951,20 +864,14 @@ static int recalc_task_prio(struct task_ */ static void activate_task(struct task_struct *p, struct rq *rq, int local) { - unsigned long long now; + unsigned long long now, sleep; + struct prio_array *array; + array = rq->active; if (rt_task(p)) goto out; - now = sched_clock(); -#ifdef CONFIG_SMP - if (!local) { - /* Compensate for drifting sched_clock */ - struct rq *this_rq = this_rq(); - now = (now - this_rq->most_recent_timestamp) - + rq->most_recent_timestamp; - } -#endif + now = sched_clock_us(); /* * Sleep time is in units of nanosecs, so shift by 20 to get a @@ -976,41 +883,34 @@ static void activate_task(struct task_st profile_hits(SLEEP_PROFILING, (void *)get_wchan(p), (now - p->timestamp) >> 20); } - - p->prio = recalc_task_prio(p, now); - /* - * This checks to make sure it's not an uninterruptible task - * that is now waking up. + * If we have slept through an active/expired array switch, restart + * our timeslice too. */ - if (p->sleep_type == SLEEP_NORMAL) { - /* - * Tasks which were woken up by interrupts (ie. hw events) - * are most likely of interactive nature. So we give them - * the credit of extending their sleep time to the period - * of time they spend on the runqueue, waiting for execution - * on a CPU, first time around: - */ - if (in_interrupt()) - p->sleep_type = SLEEP_INTERRUPTED; - else { - /* - * Normal first-time wakeups get a credit too for - * on-runqueue time, but it will be weighted down: - */ - p->sleep_type = SLEEP_INTERACTIVE; - } - } + sleep = now - p->timestamp; p->timestamp = now; + add_task_time(p, sleep, STIME_SLEEP); + p->prio = task_priority(p); + + if (rq->array_sequence != p->array_sequence) { + p->used_slice = 0; + p->over_slice = 0; + } else if (unlikely(p->used_slice == -1)) { + array = rq->expired; + p->used_slice = 0; + update_min_expired_prio(p, rq); + } + out: - __activate_task(p, rq); + __activate_task(p, rq, array); } /* * deactivate_task - remove a task from the runqueue. */ -static void deactivate_task(struct task_struct *p, struct rq *rq) +static inline void deactivate_task(struct task_struct *p, struct rq *rq) { + p->array_sequence = rq->array_sequence; dec_nr_running(p, rq); dequeue_task(p, p->array); p->array = NULL; @@ -1508,10 +1408,12 @@ static int try_to_wake_up(struct task_st out_set_cpu: new_cpu = wake_idle(new_cpu, p); if (new_cpu != cpu) { + int seq_delta = p->array_sequence - rq->array_sequence; set_task_cpu(p, new_cpu); task_rq_unlock(rq, &flags); /* might preempt at this point */ rq = task_rq_lock(p, &flags); + p->array_sequence = rq->array_sequence + seq_delta; old_state = p->state; if (!(old_state & state)) goto out; @@ -1524,33 +1426,9 @@ out_set_cpu: out_activate: #endif /* CONFIG_SMP */ - if (old_state == TASK_UNINTERRUPTIBLE) { + if (old_state == TASK_UNINTERRUPTIBLE) rq->nr_uninterruptible--; - /* - * Tasks on involuntary sleep don't earn - * sleep_avg beyond just interactive state. - */ - p->sleep_type = SLEEP_NONINTERACTIVE; - } else - - /* - * Tasks that have marked their sleep as noninteractive get - * woken up with their sleep average not weighted in an - * interactive way. - */ - if (old_state & TASK_NONINTERACTIVE) - p->sleep_type = SLEEP_NONINTERACTIVE; - - activate_task(p, rq, cpu == this_cpu); - /* - * Sync wakeups (i.e. those types of wakeups where the waker - * has indicated that it will leave the CPU in short order) - * don't trigger a preemption, if the woken up task will run on - * this cpu. (in this case the 'I will reschedule' promise of - * the waker guarantees that the freshly woken up task is going - * to be considered on this CPU.) - */ if (!sync || cpu != this_cpu) { if (TASK_PREEMPTS_CURR(p, rq)) resched_task(rq->curr); @@ -1584,6 +1462,9 @@ static void task_running_tick(struct rq */ void fastcall sched_fork(struct task_struct *p, int clone_flags) { + unsigned long sleep_avg; + struct rq *rq; + struct task_struct *cur; int cpu = get_cpu(); #ifdef CONFIG_SMP @@ -1617,31 +1498,47 @@ void fastcall sched_fork(struct task_str /* Want to start with kernel preemption disabled. */ task_thread_info(p)->preempt_count = 1; #endif - /* - * Share the timeslice between parent and child, thus the - * total amount of pending timeslices in the system doesn't change, - * resulting in more scheduling fairness. - */ + p->timestamp = sched_clock_us(); + p->used_slice = 0; + p->over_slice = 0; + if (rt_task(p)) + goto out; + + rq = this_rq(); + cur = current; + + /* Get MIN_HISTORY of history with a bit less sleep_avg than parent. */ + sleep_avg = task_sleep_avg(cur); + sleep_avg -= sleep_avg >> 2; + p->total_time = MIN_HISTORY; + p->sleep_time = MIN_HISTORY * sleep_avg / SLEEP_FACTOR; + + p->prio = p->normal_prio = task_priority(p); + + /* Parent loses sleep time the child took */ + cur->sleep_time -= min(cur->sleep_time/4, p->sleep_time); + local_irq_disable(); - p->time_slice = (current->time_slice + 1) >> 1; - /* - * The remainder of the first timeslice might be recovered by - * the parent if the child exits early enough. - */ - p->first_time_slice = 1; - current->time_slice >>= 1; - p->timestamp = sched_clock(); - if (unlikely(!current->time_slice)) { - /* - * This case is rare, it happens when the parent has only - * a single jiffy left from its timeslice. Taking the - * runqueue lock is not a problem. - */ - current->time_slice = 1; - task_running_tick(cpu_rq(cpu), current); + if (unlikely(cur->used_slice == -1 || cur == rq->idle)) + p->used_slice = -1; + else { + int ts = task_timeslice(p, rq); + int child_ts = min_t(int, ts/4, FORKED_TS_MAX); + + if (child_ts == 0) { + p->used_slice = -1; + } else { + p->used_slice = ts - child_ts; + cur->used_slice += child_ts; + if (cur->used_slice >= task_timeslice(p, rq)) { + cur->used_slice = -1; + set_need_resched(); + } + } } local_irq_enable(); - put_cpu(); +out: + put_cpu(); } /* @@ -1653,108 +1550,55 @@ void fastcall sched_fork(struct task_str */ void fastcall wake_up_new_task(struct task_struct *p, unsigned long clone_flags) { - struct rq *rq, *this_rq; unsigned long flags; int this_cpu, cpu; + struct rq *rq; + struct prio_array *array; + struct task_struct *cur; + + cpu = task_cpu(p); rq = task_rq_lock(p, &flags); BUG_ON(p->state != TASK_RUNNING); this_cpu = smp_processor_id(); - cpu = task_cpu(p); - - /* - * We decrease the sleep average of forking parents - * and children as well, to keep max-interactive tasks - * from forking tasks that are max-interactive. The parent - * (current) is done further down, under its lock. - */ - p->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(p) * - CHILD_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS); - p->prio = effective_prio(p); + array = rq->active; + if (unlikely(p->used_slice == -1)) { + array = rq->expired; + p->used_slice = 0; + update_min_expired_prio(p, rq); + } + cur = current; if (likely(cpu == this_cpu)) { - if (!(clone_flags & CLONE_VM)) { + if (!rt_task(p) && !rt_task(cur) && + !(clone_flags & CLONE_VM) && (array == rq->active)) { /* * The VM isn't cloned, so we're in a good position to * do child-runs-first in anticipation of an exec. This * usually avoids a lot of COW overhead. */ - if (unlikely(!current->array)) - __activate_task(p, rq); - else { - p->prio = current->prio; - p->normal_prio = current->normal_prio; - list_add_tail(&p->run_list, ¤t->run_list); - p->array = current->array; - p->array->nr_active++; - inc_nr_running(p, rq); - } set_need_resched(); - } else - /* Run child last */ - __activate_task(p, rq); - /* - * We skip the following code due to cpu == this_cpu - * - * task_rq_unlock(rq, &flags); - * this_rq = task_rq_lock(current, &flags); - */ - this_rq = rq; - } else { - this_rq = cpu_rq(this_cpu); + p->prio = cur->prio; + list_add_tail(&p->run_list, &cur->run_list); + p->array = cur->array; + p->array->nr_active++; + rq->nr_running++; + goto child_queued; + } + } + __activate_task(p, rq, array); - /* - * Not the local CPU - must adjust timestamp. This should - * get optimised away in the !CONFIG_SMP case. - */ - p->timestamp = (p->timestamp - this_rq->most_recent_timestamp) - + rq->most_recent_timestamp; - __activate_task(p, rq); - if (TASK_PREEMPTS_CURR(p, rq)) - resched_task(rq->curr); + /* This catches RT tasks and remote SMP tasks */ + if (TASK_PREEMPTS_CURR(p, rq)) + resched_task(rq->curr); - /* - * Parent and child are on different CPUs, now get the - * parent runqueue to update the parent's ->sleep_avg: - */ - task_rq_unlock(rq, &flags); - this_rq = task_rq_lock(current, &flags); - } - current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) * - PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS); - task_rq_unlock(this_rq, &flags); +child_queued: + task_rq_unlock(rq, &flags); } -/* - * Potentially available exiting-child timeslices are - * retrieved here - this way the parent does not get - * penalized for creating too many threads. - * - * (this cannot be used to 'generate' timeslices - * artificially, because any timeslice recovered here - * was given away by the parent in the first place.) - */ void fastcall sched_exit(struct task_struct *p) { - unsigned long flags; - struct rq *rq; - - /* - * If the child was a (relative-) CPU hog then decrease - * the sleep_avg of the parent as well. - */ - rq = task_rq_lock(p->parent, &flags); - if (p->first_time_slice && task_cpu(p) == task_cpu(p->parent)) { - p->parent->time_slice += p->time_slice; - if (unlikely(p->parent->time_slice > task_timeslice(p))) - p->parent->time_slice = task_timeslice(p); - } - if (p->sleep_avg < p->parent->sleep_avg) - p->parent->sleep_avg = p->parent->sleep_avg / - (EXIT_WEIGHT + 1) * EXIT_WEIGHT + p->sleep_avg / - (EXIT_WEIGHT + 1); - task_rq_unlock(rq, &flags); } /** @@ -1831,6 +1675,7 @@ static inline void finish_task_switch(st asmlinkage void schedule_tail(struct task_struct *prev) __releases(rq->lock) { + struct task_struct *cur; struct rq *rq = this_rq(); finish_task_switch(rq, prev); @@ -1838,8 +1683,9 @@ asmlinkage void schedule_tail(struct tas /* In this case, finish_task_switch does not reenable preemption */ preempt_enable(); #endif - if (current->set_child_tid) - put_user(current->pid, current->set_child_tid); + cur = current; + if (cur->set_child_tid) + put_user(cur->pid, cur->set_child_tid); } /* @@ -1979,19 +1825,19 @@ static void double_rq_lock(struct rq *rq __acquires(rq1->lock) __acquires(rq2->lock) { + spinlock_t *l1, *l2; + BUG_ON(!irqs_disabled()); - if (rq1 == rq2) { - spin_lock(&rq1->lock); - __acquire(rq2->lock); /* Fake it out ;) */ - } else { - if (rq1 < rq2) { - spin_lock(&rq1->lock); - spin_lock(&rq2->lock); - } else { - spin_lock(&rq2->lock); - spin_lock(&rq1->lock); - } + + l1 = &rq1->lock; + l2 = &rq2->lock; + if (rq1 > rq2) { + l1 = l2; + l2 = &rq1->lock; } + + spin_lock(l1); + spin_lock(l2); } /* @@ -2005,10 +1851,7 @@ static void double_rq_unlock(struct rq * __releases(rq2->lock) { spin_unlock(&rq1->lock); - if (rq1 != rq2) - spin_unlock(&rq2->lock); - else - __release(rq2->lock); + spin_unlock(&rq2->lock); } /* @@ -2045,9 +1888,12 @@ static void sched_migrate_task(struct ta struct migration_req req; unsigned long flags; struct rq *rq; + int cpu; rq = task_rq_lock(p, &flags); + cpu = task_cpu(p); if (!cpu_isset(dest_cpu, p->cpus_allowed) + || cpu == dest_cpu || unlikely(cpu_is_offline(dest_cpu))) goto out; @@ -2094,8 +1940,10 @@ static void pull_task(struct rq *src_rq, set_task_cpu(p, this_cpu); inc_nr_running(p, this_rq); enqueue_task(p, this_array); - p->timestamp = (p->timestamp - src_rq->most_recent_timestamp) - + this_rq->most_recent_timestamp; + + if (this_array == this_rq->expired) + update_min_expired_prio(p, this_rq); + /* * Note that idle threads have a prio of MAX_PRIO, for this test * to be always true for them. @@ -2110,7 +1958,7 @@ static void pull_task(struct rq *src_rq, static int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu, struct sched_domain *sd, enum idle_type idle, - int *all_pinned) + int *all_pinned, unsigned long long now) { /* * We do not migrate tasks that are: @@ -2133,18 +1981,18 @@ int can_migrate_task(struct task_struct if (sd->nr_balance_failed > sd->cache_nice_tries) { #ifdef CONFIG_SCHEDSTATS - if (task_hot(p, rq->most_recent_timestamp, sd)) + if (task_hot(p, now, sd)) schedstat_inc(sd, lb_hot_gained[idle]); #endif return 1; } - if (task_hot(p, rq->most_recent_timestamp, sd)) + if (task_hot(p, now, sd)) return 0; return 1; } -#define rq_best_prio(rq) min((rq)->curr->prio, (rq)->best_expired_prio) +#define rq_best_prio(rq) min((rq)->curr->prio, (rq)->min_expired_prio) /* * move_tasks tries to move up to max_nr_move tasks and max_load_move weighted @@ -2164,12 +2012,14 @@ static int move_tasks(struct rq *this_rq struct list_head *head, *curr; struct task_struct *tmp; long rem_load_move; + unsigned long long now; if (max_nr_move == 0 || max_load_move == 0) goto out; rem_load_move = max_load_move; pinned = 1; + now = sched_clock_us(); this_best_prio = rq_best_prio(this_rq); best_prio = rq_best_prio(busiest); /* @@ -2228,7 +2078,7 @@ skip_queue: if (skip_for_load && idx < this_best_prio) skip_for_load = !best_prio_seen && idx == best_prio; if (skip_for_load || - !can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) { + !can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned, now)) { best_prio_seen |= idx == best_prio; if (curr != head) @@ -2289,6 +2139,8 @@ find_busiest_group(struct sched_domain * struct sched_group *group_min = NULL, *group_leader = NULL; #endif + prefetch(group); + max_load = this_load = total_load = total_pwr = 0; busiest_load_per_task = busiest_nr_running = 0; this_load_per_task = this_nr_running = 0; @@ -2306,6 +2158,8 @@ find_busiest_group(struct sched_domain * unsigned int balance_cpu = -1, first_idle_cpu = 0; unsigned long sum_nr_running, sum_weighted_load; + prefetch(group->next); + local_group = cpu_isset(this_cpu, group->cpumask); if (local_group) @@ -3018,7 +2872,7 @@ static inline void update_cpu_clock(struct task_struct *p, struct rq *rq, unsigned long long now) { p->sched_time += now - p->last_ran; - p->last_ran = rq->most_recent_timestamp = now; + p->last_ran = now; } /* @@ -3031,34 +2885,13 @@ unsigned long long current_sched_time(co unsigned long flags; local_irq_save(flags); - ns = p->sched_time + sched_clock() - p->last_ran; + ns = p->sched_time + sched_clock_us() - p->last_ran; local_irq_restore(flags); return ns; } /* - * We place interactive tasks back into the active array, if possible. - * - * To guarantee that this does not starve expired tasks we ignore the - * interactivity of a task if the first expired task had to wait more - * than a 'reasonable' amount of time. This deadline timeout is - * load-dependent, as the frequency of array switched decreases with - * increasing number of running tasks. We also ignore the interactivity - * if a better static_prio task has expired: - */ -static inline int expired_starving(struct rq *rq) -{ - if (rq->curr->static_prio > rq->best_expired_prio) - return 1; - if (!STARVATION_LIMIT || !rq->expired_timestamp) - return 0; - if (jiffies - rq->expired_timestamp > STARVATION_LIMIT * rq->nr_running) - return 1; - return 0; -} - -/* * Account user cpu time to a process. * @p: the process that the cpu time gets accounted to * @hardirq_offset: the offset to subtract from hardirq_count() @@ -3133,77 +2966,26 @@ void account_steal_time(struct task_stru static void task_running_tick(struct rq *rq, struct task_struct *p) { - if (p->array != rq->active) { - /* Task has expired but was not scheduled yet */ - set_tsk_need_resched(p); + int allowed; + int ts; + + /* Task might have expired already, but not scheduled off yet */ + if (unlikely(p->used_slice == -1)) return; - } - spin_lock(&rq->lock); - /* - * The task was running during this tick - update the - * time slice counter. Note: we do not update a thread's - * priority until it either goes to sleep or uses up its - * timeslice. This makes it possible for interactive tasks - * to use up their timeslices at their highest priority levels. - */ - if (rt_task(p)) { - /* - * RR tasks need a special form of timeslice management. - * FIFO tasks have no timeslices. - */ - if ((p->policy == SCHED_RR) && !--p->time_slice) { - p->time_slice = task_timeslice(p); - p->first_time_slice = 0; - set_tsk_need_resched(p); - /* put it at the end of the queue: */ - requeue_task(p, rq->active); - } - goto out_unlock; - } - if (!--p->time_slice) { - dequeue_task(p, rq->active); - set_tsk_need_resched(p); - p->prio = effective_prio(p); - p->time_slice = task_timeslice(p); - p->first_time_slice = 0; - - if (!rq->expired_timestamp) - rq->expired_timestamp = jiffies; - if (!TASK_INTERACTIVE(p) || expired_starving(rq)) { - enqueue_task(p, rq->expired); - if (p->static_prio < rq->best_expired_prio) - rq->best_expired_prio = p->static_prio; - } else - enqueue_task(p, rq->active); - } else { - /* - * Prevent a too long timeslice allowing a task to monopolize - * the CPU. We do this by splitting up the timeslice into - * smaller pieces. - * - * Note: this does not mean the task's timeslices expire or - * get lost in any way, they just might be preempted by - * another task of equal priority. (one with higher - * priority would have preempted this task already.) We - * requeue this task to the end of the list on this priority - * level, which is in essence a round-robin of tasks with - * equal priority. - * - * This only applies to tasks in the interactive - * delta range with at least TIMESLICE_GRANULARITY to requeue. - */ - if (TASK_INTERACTIVE(p) && !((task_timeslice(p) - - p->time_slice) % TIMESLICE_GRANULARITY(p)) && - (p->time_slice >= TIMESLICE_GRANULARITY(p)) && - (p->array == rq->active)) { + /* SCHED_FIFO tasks have no timeslice */ + if (unlikely(p->policy == SCHED_FIFO)) + return; - requeue_task(p, rq->active); - set_tsk_need_resched(p); - } + /* p was running during this tick. Update its time slice counter. */ + p->used_slice++; + ts = task_timeslice(p, rq); + allowed = ts - min(p->over_slice, ts >> 1); + if (unlikely(p->used_slice >= allowed)) { + p->over_slice = allowed - p->used_slice; + p->used_slice = -1; + set_tsk_need_resched(p); } -out_unlock: - spin_unlock(&rq->lock); } /* @@ -3215,7 +2997,7 @@ out_unlock: */ void scheduler_tick(void) { - unsigned long long now = sched_clock(); + unsigned long long now = sched_clock_us(); struct task_struct *p = current; int cpu = smp_processor_id(); struct rq *rq = cpu_rq(cpu); @@ -3269,12 +3051,6 @@ EXPORT_SYMBOL(sub_preempt_count); #endif -static inline int interactive_sleep(enum sleep_type sleep_type) -{ - return (sleep_type == SLEEP_INTERACTIVE || - sleep_type == SLEEP_INTERRUPTED); -} - /* * schedule() is the main scheduler function. */ @@ -3285,56 +3061,46 @@ asmlinkage void __sched schedule(void) struct list_head *queue; unsigned long long now; unsigned long run_time; - int cpu, idx, new_prio; + int cpu, idx; long *switch_count; struct rq *rq; + prev = current; + prefetch(prev); + + profile_hit(SCHED_PROFILING, __builtin_return_address(0)); + /* * Test if we are atomic. Since do_exit() needs to call into * schedule() atomically, we ignore that path for now. * Otherwise, whine if we are scheduling when we should not be. */ - if (unlikely(in_atomic() && !current->exit_state)) { - printk(KERN_ERR "BUG: scheduling while atomic: " - "%s/0x%08x/%d\n", - current->comm, preempt_count(), current->pid); - debug_show_held_locks(current); - if (irqs_disabled()) - print_irqtrace_events(current); - dump_stack(); + if (unlikely(in_atomic())) { + if (unlikely(!current->exit_state)) { + printk(KERN_ERR "BUG: scheduling while atomic: " + "%s/0x%08x/%d\n", + current->comm, preempt_count(), current->pid); + debug_show_held_locks(current); + if (irqs_disabled()) + print_irqtrace_events(current); + dump_stack(); + } } profile_hit(SCHED_PROFILING, __builtin_return_address(0)); -need_resched: preempt_disable(); - prev = current; - release_kernel_lock(prev); -need_resched_nonpreemptible: rq = this_rq(); + prefetchw(rq); +need_resched: + cpu = smp_processor_id(); + release_kernel_lock(prev); - /* - * The idle thread is not allowed to schedule! - * Remove this check after it has been exercised a bit. - */ - if (unlikely(prev == rq->idle) && prev->state != TASK_RUNNING) { - printk(KERN_ERR "bad: scheduling from the idle thread!\n"); - dump_stack(); - } - +need_resched_nobkl: schedstat_inc(rq, sched_cnt); - now = sched_clock(); - if (likely((long long)(now - prev->timestamp) < NS_MAX_SLEEP_AVG)) { - run_time = now - prev->timestamp; - if (unlikely((long long)(now - prev->timestamp) < 0)) - run_time = 0; - } else - run_time = NS_MAX_SLEEP_AVG; - - /* - * Tasks charged proportionately less run_time at high sleep_avg to - * delay them losing their interactive status - */ - run_time /= (CURRENT_BONUS(prev) ? : 1); + now = sched_clock_us(); + run_time = now - prev->timestamp; + prev->timestamp = prev->last_ran = now; + add_task_time(prev, run_time, STIME_RUN); spin_lock_irq(&rq->lock); @@ -3342,24 +3108,42 @@ need_resched_nonpreemptible: if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) { switch_count = &prev->nvcsw; if (unlikely((prev->state & TASK_INTERRUPTIBLE) && - unlikely(signal_pending(prev)))) + unlikely(signal_pending(prev)))) { prev->state = TASK_RUNNING; - else { + } else { if (prev->state == TASK_UNINTERRUPTIBLE) rq->nr_uninterruptible++; deactivate_task(prev, rq); + goto no_check_expired; } } - cpu = smp_processor_id(); - if (unlikely(!rq->nr_running)) { + if (unlikely(prev->used_slice == -1)) { + dequeue_task(prev, prev->array); + /* SCHED_FIFO can come in here too, from sched_yield */ + array = rq->active; + if (!rt_task(prev)) { + array = rq->expired; + prev->prio = task_priority(prev); + update_min_expired_prio(prev, rq); + } + enqueue_task(prev, array); + prev->used_slice = 0; + goto no_check_idle; + } +no_check_expired: + + if (!rq->nr_running) { + rq->min_expired_prio = MAX_PRIO; + rq->array_sequence++; idle_balance(cpu, rq); if (!rq->nr_running) { + schedstat_inc(rq, sched_goidle); next = rq->idle; - rq->expired_timestamp = 0; goto switch_tasks; } } +no_check_idle: array = rq->active; if (unlikely(!array->nr_active)) { @@ -3370,72 +3154,55 @@ need_resched_nonpreemptible: rq->active = rq->expired; rq->expired = array; array = rq->active; - rq->expired_timestamp = 0; - rq->best_expired_prio = MAX_PRIO; + rq->array_sequence++; + rq->min_expired_prio = MAX_PRIO; } idx = sched_find_first_bit(array->bitmap); queue = array->queue + idx; next = list_entry(queue->next, struct task_struct, run_list); - if (!rt_task(next) && interactive_sleep(next->sleep_type)) { - unsigned long long delta = now - next->timestamp; - if (unlikely((long long)(now - next->timestamp) < 0)) - delta = 0; - - if (next->sleep_type == SLEEP_INTERACTIVE) - delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128; - - array = next->array; - new_prio = recalc_task_prio(next, next->timestamp + delta); - - if (unlikely(next->prio != new_prio)) { - dequeue_task(next, array); - next->prio = new_prio; - enqueue_task(next, array); - } - } - next->sleep_type = SLEEP_NORMAL; switch_tasks: - if (next == rq->idle) - schedstat_inc(rq, sched_goidle); + prefetch(&next->mm); prefetch(next); prefetch_stack(next); clear_tsk_need_resched(prev); - rcu_qsctr_inc(task_cpu(prev)); + rcu_qsctr_inc(cpu); update_cpu_clock(prev, rq, now); - prev->sleep_avg -= run_time; - if ((long)prev->sleep_avg <= 0) - prev->sleep_avg = 0; - prev->timestamp = prev->last_ran = now; - sched_info_switch(prev, next); if (likely(prev != next)) { + struct task_struct *from; + + prefetch(next->mm); + prefetch(next->thread_info); + next->timestamp = next->last_ran = now; rq->nr_switches++; rq->curr = next; ++*switch_count; prepare_task_switch(rq, next); - prev = context_switch(rq, prev, next); - barrier(); + from = context_switch(rq, prev, next); /* * this_rq must be evaluated again because prev may have moved * CPUs since it called schedule(), thus the 'rq' on its stack * frame will be invalid. */ - finish_task_switch(this_rq(), prev); + rq = this_rq(); + finish_task_switch(rq, from); } else spin_unlock_irq(&rq->lock); - prev = current; if (unlikely(reacquire_kernel_lock(prev) < 0)) - goto need_resched_nonpreemptible; + goto need_resched_nobkl; preempt_enable_no_resched(); - if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) { + preempt_disable(); + rq = this_rq(); goto need_resched; + } } EXPORT_SYMBOL(schedule); @@ -3916,7 +3683,7 @@ void set_user_nice(struct task_struct *p p->static_prio = NICE_TO_PRIO(nice); set_load_weight(p); old_prio = p->prio; - p->prio = effective_prio(p); + p->prio = task_priority(p); delta = p->prio - old_prio; if (array) { @@ -4047,14 +3814,9 @@ static void __setscheduler(struct task_s p->policy = policy; p->rt_priority = prio; - p->normal_prio = normal_prio(p); + p->normal_prio = task_priority(p); /* we are holding p->pi_lock already */ p->prio = rt_mutex_getprio(p); - /* - * SCHED_BATCH tasks are treated as perpetual CPU hogs: - */ - if (policy == SCHED_BATCH) - p->sleep_avg = 0; set_load_weight(p); } @@ -4149,8 +3911,11 @@ recheck: deactivate_task(p, rq); oldprio = p->prio; __setscheduler(p, policy, param->sched_priority); + if (policy == SCHED_FIFO || policy == SCHED_RR) + p->used_slice = 0; + if (array) { - __activate_task(p, rq); + __activate_task(p, rq, rq->active); /* * Reschedule if we are currently running on this runqueue and * our priority decreased, or if we are not currently running on @@ -4438,46 +4203,13 @@ asmlinkage long sys_sched_getaffinity(pi */ asmlinkage long sys_sched_yield(void) { - struct rq *rq = this_rq_lock(); - struct prio_array *array = current->array, *target = rq->expired; - - schedstat_inc(rq, yld_cnt); - /* - * We implement yielding by moving the task into the expired - * queue. - * - * (special rule: RT tasks will just roundrobin in the active - * array.) - */ - if (rt_task(current)) - target = rq->active; - - if (array->nr_active == 1) { - schedstat_inc(rq, yld_act_empty); - if (!rq->expired->nr_active) - schedstat_inc(rq, yld_both_empty); - } else if (!rq->expired->nr_active) - schedstat_inc(rq, yld_exp_empty); - - if (array != target) { - dequeue_task(current, array); - enqueue_task(current, target); - } else - /* - * requeue_task is cheaper so perform that if possible. - */ - requeue_task(current, array); - - /* - * Since we are going to call schedule() anyway, there's - * no need to preempt or enable interrupts: - */ - __release(rq->lock); - spin_release(&rq->lock.dep_map, 1, _THIS_IP_); - _raw_spin_unlock(&rq->lock); - preempt_enable_no_resched(); - - schedule(); + local_irq_disable(); +#ifdef CONFIG_SCHEDSTATS + schedstat_inc(this_rq(), yld_cnt); +#endif + current->used_slice = -1; + set_need_resched(); + local_irq_enable(); return 0; } @@ -4566,6 +4298,15 @@ void __sched yield(void) { set_current_state(TASK_RUNNING); sys_sched_yield(); + /* + * Kernel-space yield won't follow the schedule upon + * return from syscall path. Unless preempt is enabled, + * however in that case, preempt_schedule doesn't drop + * the bkl, which is needed in some paths. + * + * Must call schedule() here. + */ + schedule(); } EXPORT_SYMBOL(yield); @@ -4662,6 +4403,8 @@ long sys_sched_rr_get_interval(pid_t pid struct task_struct *p; int retval = -EINVAL; struct timespec t; + unsigned long flags; + struct rq *rq; if (pid < 0) goto out_nounlock; @@ -4676,8 +4419,10 @@ long sys_sched_rr_get_interval(pid_t pid if (retval) goto out_unlock; + rq = task_rq_lock(p, &flags); jiffies_to_timespec(p->policy == SCHED_FIFO ? - 0 : task_timeslice(p), &t); + 0 : task_timeslice(p, rq), &t); + task_rq_unlock(rq, &flags); read_unlock(&tasklist_lock); retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; out_nounlock: @@ -4805,11 +4550,12 @@ void __cpuinit init_idle(struct task_str struct rq *rq = cpu_rq(cpu); unsigned long flags; - idle->timestamp = sched_clock(); - idle->sleep_avg = 0; + idle->timestamp = sched_clock_us(); idle->array = NULL; idle->prio = idle->normal_prio = MAX_PRIO; idle->state = TASK_RUNNING; + idle->used_slice = 0; + idle->over_slice = 0; idle->cpus_allowed = cpumask_of_cpu(cpu); set_task_cpu(idle, cpu); @@ -4928,16 +4674,8 @@ static int __migrate_task(struct task_st set_task_cpu(p, dest_cpu); if (p->array) { - /* - * Sync timestamp with rq_dest's before activating. - * The same thing could be achieved by doing this step - * afterwards, and pretending it was a local activate. - * This way is cleaner and logically correct. - */ - p->timestamp = p->timestamp - rq_src->most_recent_timestamp - + rq_dest->most_recent_timestamp; deactivate_task(p, rq_src); - __activate_task(p, rq_dest); + activate_task(p, rq_dest, 0); if (TASK_PREEMPTS_CURR(p, rq_dest)) resched_task(rq_dest->curr); } @@ -6771,7 +6509,7 @@ void __init sched_init(void) rq->nr_running = 0; rq->active = rq->arrays; rq->expired = rq->arrays + 1; - rq->best_expired_prio = MAX_PRIO; + rq->min_expired_prio = MAX_PRIO; #ifdef CONFIG_SMP rq->sd = NULL; @@ -6791,7 +6529,7 @@ void __init sched_init(void) INIT_LIST_HEAD(array->queue + k); __clear_bit(k, array->bitmap); } - // delimiter for bitsearch + /* delimiter for bitsearch */ __set_bit(MAX_PRIO, array->bitmap); } } @@ -6864,10 +6602,10 @@ void normalize_rt_tasks(void) array = p->array; if (array) - deactivate_task(p, task_rq(p)); + deactivate_task(p, rq); __setscheduler(p, SCHED_NORMAL, 0); if (array) { - __activate_task(p, task_rq(p)); + __activate_task(p, rq, array); resched_task(rq->curr); } Index: linux-2.6/mm/oom_kill.c =================================================================== --- linux-2.6.orig/mm/oom_kill.c 2007-03-22 20:44:00.000000000 +1100 +++ linux-2.6/mm/oom_kill.c 2007-03-22 20:44:17.000000000 +1100 @@ -287,11 +287,10 @@ static void __oom_kill_task(struct task_ printk(KERN_ERR "Killed process %d (%s)\n", p->pid, p->comm); /* - * We give our sacrificial lamb high priority and access to - * all the memory it needs. That way it should be able to - * exit() and clear out its resources quickly... + * We give our sacrificial lamb access to all the memory it needs. + * That way it should be able to exit() and clear out its resources + * quickly... */ - p->time_slice = HZ; set_tsk_thread_flag(p, TIF_MEMDIE); force_sig(SIGKILL, p); Index: linux-2.6/kernel/sysctl.c =================================================================== --- linux-2.6.orig/kernel/sysctl.c 2007-03-22 20:44:00.000000000 +1100 +++ linux-2.6/kernel/sysctl.c 2007-03-22 20:44:17.000000000 +1100 @@ -76,6 +76,9 @@ extern int pid_max_min, pid_max_max; extern int sysctl_drop_caches; extern int percpu_pagelist_fraction; extern int compat_log; +extern int sched_base_timeslice; +extern int sched_min_base; +extern int sched_max_base; /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ static int maxolduid = 65535; @@ -603,7 +606,17 @@ static ctl_table kern_table[] = { .proc_handler = &proc_dointvec, }, #endif - + { + .ctl_name = KERN_SCHED_TIMESLICE, + .procname = "base_timeslice", + .data = &sched_base_timeslice, + .maxlen = sizeof (sched_base_timeslice), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &sched_min_base, + .extra2 = &sched_max_base, + }, { .ctl_name = 0 } }; @@ -859,6 +872,7 @@ static ctl_table vm_table[] = { .extra1 = &zero, }, #endif + { .ctl_name = 0 } }; Index: linux-2.6/include/linux/init_task.h =================================================================== --- linux-2.6.orig/include/linux/init_task.h 2007-03-22 20:44:00.000000000 +1100 +++ linux-2.6/include/linux/init_task.h 2007-03-22 20:44:17.000000000 +1100 @@ -99,16 +99,15 @@ extern struct group_info init_groups; .usage = ATOMIC_INIT(2), \ .flags = 0, \ .lock_depth = -1, \ - .prio = MAX_PRIO-20, \ - .static_prio = MAX_PRIO-20, \ - .normal_prio = MAX_PRIO-20, \ + .prio = MAX_PRIO-29, \ + .static_prio = MAX_PRIO-29, \ + .normal_prio = MAX_PRIO-29, \ .policy = SCHED_NORMAL, \ .cpus_allowed = CPU_MASK_ALL, \ .mm = NULL, \ .active_mm = &init_mm, \ .run_list = LIST_HEAD_INIT(tsk.run_list), \ .ioprio = 0, \ - .time_slice = HZ, \ .tasks = LIST_HEAD_INIT(tsk.tasks), \ .ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children), \ .ptrace_list = LIST_HEAD_INIT(tsk.ptrace_list), \ Index: linux-2.6/include/linux/sysctl.h =================================================================== --- linux-2.6.orig/include/linux/sysctl.h 2007-03-22 20:44:00.000000000 +1100 +++ linux-2.6/include/linux/sysctl.h 2007-03-22 20:44:17.000000000 +1100 @@ -165,6 +165,7 @@ enum KERN_MAX_LOCK_DEPTH=74, KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */ KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */ + KERN_SCHED_TIMESLICE=77, /* int: base timeslice for scheduler */ };