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, &current->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 */
 };
 
 

Reply via email to