diff --git a/include/linux/sched.h b/include/linux/sched.h
index ed6c384..e75b309 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -147,13 +147,19 @@ extern void calc_global_load(unsigned long ticks);
 extern unsigned long get_parent_ip(unsigned long addr);
 
 struct seq_file;
+#ifdef CONFIG_SCHED_FAIR_CFS
 struct cfs_rq;
+#elif CONFIG_SCHED_FAIR_HTFS
+struct htfs_rqs;
+#endif
 struct task_group;
 #ifdef CONFIG_SCHED_DEBUG
 extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m);
 extern void proc_sched_set_task(struct task_struct *p);
+#ifdef CONFIG_SCHED_FAIR_CFS
 extern void
 print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq);
+#endif
 #else
 static inline void
 proc_sched_show_task(struct task_struct *p, struct seq_file *m)
@@ -162,11 +168,13 @@ proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 static inline void proc_sched_set_task(struct task_struct *p)
 {
 }
+#ifdef CONFIG_SCHED_FAIR_CFS
 static inline void
 print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 {
 }
 #endif
+#endif
 
 /*
  * Task state bitmask. NOTE! These bits are also
@@ -1049,6 +1057,7 @@ struct sched_domain;
 #define ENQUEUE_WAKEUP		1
 #define ENQUEUE_WAKING		2
 #define ENQUEUE_HEAD		4
+#define ENQUEUE_PRESERVE_INTERACTIVITY	8
 
 #define DEQUEUE_SLEEP		1
 
@@ -1139,12 +1148,49 @@ struct sched_statistics {
 };
 #endif
 
+#ifdef CONFIG_SCHED_FAIR_HTFS
+
+#define HTFS_LAST_VTIME_STATE 3
+
+#define HTFS_VTIME_DIFF_INIT		0x00
+#define HTFS_VTIME_DIFF_INIT2		0x01
+#define HTFS_VTIME_DIFF_OK		0x02
+
+#define HTFS_PREEMPTED			0x04
+#define HTFS_NEED_INTERQ		0x08
+
+#endif
+
 struct sched_entity {
 	struct load_weight	load;		/* for load-balancing */
-	struct rb_node		run_node;
+#ifdef CONFIG_SCHED_FAIR_CFS
 	struct list_head	group_node;
+#endif
 	unsigned int		on_rq;
 
+#ifdef CONFIG_SCHED_FAIR_CFS
+	struct rb_node		run_node;
+#elif CONFIG_SCHED_FAIR_HTFS
+	/*
+	 * item on the priorityqueue list
+	 */
+	struct list_head	htfs_pq_item;
+	struct htfs_rq		*htfs_rq;	// FIXME: replace by relative addressing?
+	/*
+	 * state of the entity to reduce the number of calculations and comparisons
+	 */
+	u32			htfs_state;
+
+	/*
+	 * boosted weight to correct vruntime
+	 */
+	unsigned int		bw_ind;
+
+	u64			wakeup_time;
+
+	s64			last_vdiff;
+#endif
+
 	u64			exec_start;
 	u64			sum_exec_runtime;
 	u64			vruntime;
@@ -1159,10 +1205,25 @@ struct sched_entity {
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	struct sched_entity	*parent;
 	/* rq on which this entity is (to be) queued: */
+#ifdef CONFIG_SCHED_FAIR_CFS
 	struct cfs_rq		*cfs_rq;
 	/* rq "owned" by this entity/group: */
 	struct cfs_rq		*my_q;
+#elif CONFIG_SCHED_FAIR_HTFS
+	struct list_head group_node;
+	struct htfs_rqs		*htfs_rqs;
+	/* rq "owned" by this entity/group: */
+	struct htfs_rqs		*my_q;
+#ifdef CONFIG_SMP
+	/*
+	 * interactivity value to balance interactive tasks
+	 */
+	unsigned long inter;
+	unsigned long inter_avg;
+	unsigned long load_avg;
 #endif
+#endif /* CONFIG_SCHED_FAIR_HTFS */
+#endif /* CONFIG_FAIR_GROUP_SCHED */
 };
 
 struct sched_rt_entity {
@@ -1283,9 +1344,9 @@ struct task_struct {
 	unsigned long stack_canary;
 #endif
 
-	/* 
+	/*
 	 * pointers to (original) parent process, youngest child, younger sibling,
-	 * older sibling, respectively.  (p->father can be replaced with 
+	 * older sibling, respectively.  (p->father can be replaced with
 	 * p->real_parent->pid)
 	 */
 	struct task_struct *real_parent; /* real parent process */
@@ -1906,6 +1967,7 @@ extern void wake_up_idle_cpu(int cpu);
 static inline void wake_up_idle_cpu(int cpu) { }
 #endif
 
+#ifdef CONFIG_SCHED_FAIR_CFS
 extern unsigned int sysctl_sched_latency;
 extern unsigned int sysctl_sched_min_granularity;
 extern unsigned int sysctl_sched_wakeup_granularity;
@@ -1918,6 +1980,11 @@ enum sched_tunable_scaling {
 	SCHED_TUNABLESCALING_END,
 };
 extern enum sched_tunable_scaling sysctl_sched_tunable_scaling;
+#elif CONFIG_SCHED_FAIR_HTFS
+extern unsigned int sysctl_sched_inter_slice_shift;
+extern u64 sysctl_sched_inter_latency;
+extern unsigned int sysctl_sched_slice_max_shift;
+#endif
 
 #ifdef CONFIG_SCHED_DEBUG
 extern unsigned int sysctl_sched_migration_cost;
@@ -1925,11 +1992,11 @@ extern unsigned int sysctl_sched_nr_migrate;
 extern unsigned int sysctl_sched_time_avg;
 extern unsigned int sysctl_timer_migration;
 extern unsigned int sysctl_sched_shares_window;
+#endif
 
 int sched_proc_update_handler(struct ctl_table *table, int write,
 		void __user *buffer, size_t *length,
 		loff_t *ppos);
-#endif
 #ifdef CONFIG_SCHED_DEBUG
 static inline unsigned int get_sysctl_timer_migration(void)
 {
@@ -2083,7 +2150,7 @@ static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, s
 	spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
 
 	return ret;
-}	
+}
 
 extern void block_all_signals(int (*notifier)(void *priv), void *priv,
 			      sigset_t *mask);
diff --git a/init/Kconfig b/init/Kconfig
index 47dd02f..3569cfb 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -797,6 +797,23 @@ config NET_NS
 
 endif # NAMESPACES
 
+choice
+	prompt "Fair CPU Scheduler"
+	default SCHED_FAIR_CFS
+
+config SCHED_FAIR_CFS
+	bool "Completely Fair Scheduler (CFS)"
+	help
+	  This scheduler is really fair, but has time complexity O(log n).
+
+config SCHED_FAIR_HTFS
+	bool "High Throughput Fair Scheduler (HTFS)"
+	help
+	  HTFS aims at high throughput systems with high counts of
+	  processes. Time complexity is only O(1).
+
+endchoice
+
 config SCHED_AUTOGROUP
 	bool "Automatic process group scheduling"
 	select EVENTFD
diff --git a/kernel/sched.c b/kernel/sched.c
index c164920..1e09a3b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -253,7 +253,11 @@ struct task_group {
 	/* schedulable entities of this group on each cpu */
 	struct sched_entity **se;
 	/* runqueue "owned" by this group on each cpu */
+#ifdef CONFIG_SCHED_FAIR_CFS
 	struct cfs_rq **cfs_rq;
+#elif CONFIG_SCHED_FAIR_HTFS
+	struct htfs_rqs **htfs_rqs;
+#endif
 	unsigned long shares;
 
 	atomic_t load_weight;
@@ -306,6 +310,8 @@ struct task_group root_task_group;
 
 #endif	/* CONFIG_CGROUP_SCHED */
 
+#ifdef CONFIG_SCHED_FAIR_CFS
+
 /* CFS-related fields in a runqueue */
 struct cfs_rq {
 	struct load_weight load;
@@ -373,6 +379,89 @@ struct cfs_rq {
 #endif
 };
 
+#elif CONFIG_SCHED_FAIR_HTFS /* CONFIG_SCHED_FAIR_CFS */
+
+struct htfs_rq;
+struct htfs_rqs;
+
+struct htfs_pq {
+	struct list_head spqs_real_weight;
+	struct list_head queue;
+
+	// real weight of all queued entities
+	unsigned long real_bweight;
+
+	unsigned long balance_ct;
+};
+
+struct htfs_rq {
+	//s64 badness; no use for this right now
+	unsigned long bweight;
+	unsigned long run_cost;
+	struct htfs_pq *cur_pq;
+
+	struct list_head spqs_real_weight;
+
+	// 40 queues to match the priorities + 1 queue for shutdown + 2 max/min
+	struct htfs_pq pqs[50];
+
+	struct htfs_rqs *rqs;
+};
+
+struct htfs_rqs {
+	struct htfs_rq interq;
+	struct htfs_rq normalq;
+	unsigned long nr_running;
+	struct rq *rq;
+
+	int dbg_counter;
+
+	long rq_balance_ct;
+
+
+	u64 vtime;
+	unsigned long inv_weight;
+
+	unsigned long weight;
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+	struct list_head tasks;
+	/*
+	 * leaf htfs_rqs are those that hold tasks (lowest schedulable entity in
+	 * a hierarchy). Non-leaf lrqs hold other higher schedulable entities
+	 * (like users, containers etc.)
+	 *
+	 * leaf_htfs_rqs_list ties together list of leaf htfs_rqs in a cpu. This
+	 * list is used during load balance.
+	 */
+	int on_list;
+	struct list_head leaf_htfs_rqs_list;
+	struct task_group *tg;	/* group that "owns" this runqueue */
+
+	unsigned long h_load;
+#ifdef CONFIG_SMP
+
+	u64 offline_start;
+	/*
+	 * sum of the real load of all SEs on this queue
+	 */
+	u64 load;
+	u64 load_avg;
+	u64 load_period;
+	u64 load_stamp, load_last, load_unacc_exec_time;
+	unsigned long load_contribution;
+
+	/*
+	 * interactivity values for balancing
+	 */
+	unsigned long inter;
+	unsigned long inter_avg;
+#endif
+#endif
+};
+
+#endif /* CONFIG_SCHED_FAIR_HTFS */
+
 /* Real-Time classes' related field in a runqueue: */
 struct rt_rq {
 	struct rt_prio_array active;
@@ -468,12 +557,36 @@ struct rq {
 	unsigned long nr_load_updates;
 	u64 nr_switches;
 
+#ifdef CONFIG_SCHED_FAIR_CFS
 	struct cfs_rq cfs;
+#elif CONFIG_SCHED_FAIR_HTFS
+	struct htfs_rqs htfs_rqs;
+#endif
 	struct rt_rq rt;
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
 	/* list of leaf cfs_rq on this cpu: */
+#ifdef CONFIG_SCHED_FAIR_CFS
 	struct list_head leaf_cfs_rq_list;
+#elif CONFIG_SCHED_FAIR_HTFS
+	struct list_head leaf_htfs_rqs_list;
+	u64 slice;
+	unsigned int slice_shift;
+
+	u64 slice_granted;
+	u64 slice_remain;
+
+	u64 slice_change_last;
+	unsigned long slice_shrink; // Indicator if we should shrink the timeslice
+	u64 slice_shrink_last_dec; // Last indicator reset/decrease
+	
+	u64 last_call;
+	u64 call_time_diff;
+	struct task_struct *continue_run;
+	int force_sched;
+	int continues;
+#endif
+
 #endif
 #ifdef CONFIG_RT_GROUP_SCHED
 	struct list_head leaf_rt_rq_list;
@@ -620,8 +733,13 @@ static inline struct task_group *task_group(struct task_struct *p)
 static inline void set_task_rq(struct task_struct *p, unsigned int cpu)
 {
 #ifdef CONFIG_FAIR_GROUP_SCHED
+#ifdef CONFIG_SCHED_FAIR_CFS
 	p->se.cfs_rq = task_group(p)->cfs_rq[cpu];
 	p->se.parent = task_group(p)->se[cpu];
+#elif CONFIG_SCHED_FAIR_HTFS
+	p->se.htfs_rqs = task_group(p)->htfs_rqs[cpu];
+	p->se.parent = task_group(p)->se[cpu];
+#endif
 #endif
 
 #ifdef CONFIG_RT_GROUP_SCHED
@@ -1303,6 +1421,15 @@ static void sched_avg_update(struct rq *rq)
  */
 #define SRR(x, y) (((x) + (1UL << ((y) - 1))) >> (y))
 
+static inline unsigned long calc_inv_weight(unsigned long weight)
+{
+	if (BITS_PER_LONG > 32 && unlikely(weight >= WMULT_CONST))
+		return 1;
+	else
+		return (1 + (WMULT_CONST-weight/2)
+				/ (weight+1));
+}
+
 /*
  * delta *= weight / lw
  */
@@ -1313,11 +1440,7 @@ calc_delta_mine(unsigned long delta_exec, unsigned long weight,
 	u64 tmp;
 
 	if (!lw->inv_weight) {
-		if (BITS_PER_LONG > 32 && unlikely(lw->weight >= WMULT_CONST))
-			lw->inv_weight = 1;
-		else
-			lw->inv_weight = 1 + (WMULT_CONST-lw->weight/2)
-				/ (lw->weight+1);
+		lw->inv_weight = calc_inv_weight(lw->weight);
 	}
 
 	tmp = (u64)delta_exec * weight;
@@ -1537,38 +1660,6 @@ static unsigned long cpu_avg_load_per_task(int cpu)
 	return rq->avg_load_per_task;
 }
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
-
-/*
- * Compute the cpu's hierarchical load factor for each task group.
- * This needs to be done in a top-down fashion because the load of a child
- * group is a fraction of its parents load.
- */
-static int tg_load_down(struct task_group *tg, void *data)
-{
-	unsigned long load;
-	long cpu = (long)data;
-
-	if (!tg->parent) {
-		load = cpu_rq(cpu)->load.weight;
-	} else {
-		load = tg->parent->cfs_rq[cpu]->h_load;
-		load *= tg->se[cpu]->load.weight;
-		load /= tg->parent->cfs_rq[cpu]->load.weight + 1;
-	}
-
-	tg->cfs_rq[cpu]->h_load = load;
-
-	return 0;
-}
-
-static void update_h_load(long cpu)
-{
-	walk_tg_tree(tg_load_down, tg_nop, (void *)cpu);
-}
-
-#endif
-
 #ifdef CONFIG_PREEMPT
 
 static void double_rq_lock(struct rq *rq1, struct rq *rq2);
@@ -1690,7 +1781,9 @@ static void double_rq_unlock(struct rq *rq1, struct rq *rq2)
 
 static void calc_load_account_idle(struct rq *this_rq);
 static void update_sysctl(void);
+#ifdef CONFIG_SCHED_FAIR_CFS
 static int get_update_sysctl_factor(void);
+#endif
 static void update_cpu_load(struct rq *this_rq);
 
 static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
@@ -2061,6 +2154,23 @@ static void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags)
 }
 
 #ifdef CONFIG_SMP
+
+#ifdef CONFIG_SCHED_FAIR_CFS
+
+static int fair_se_is_first_last(struct sched_entity *se)
+{
+	return (se == cfs_rq_of(se)->next || se == cfs_rq_of(se)->last);
+}
+
+#elif CONFIG_SCHED_FAIR_HTFS
+
+static int fair_se_is_first_last(struct sched_entity *se)
+{
+	//TODO:
+	return 0;
+}
+#endif
+
 /*
  * Is this task likely cache-hot:
  */
@@ -2079,8 +2189,7 @@ task_hot(struct task_struct *p, u64 now, struct sched_domain *sd)
 	 * Buddy candidates are cache hot:
 	 */
 	if (sched_feat(CACHE_HOT_BUDDY) && this_rq()->nr_running &&
-			(&p->se == cfs_rq_of(&p->se)->next ||
-			 &p->se == cfs_rq_of(&p->se)->last))
+			fair_se_is_first_last(&p->se))
 		return 1;
 
 	if (sysctl_sched_migration_cost == -1)
@@ -3900,6 +4009,22 @@ static void put_prev_task(struct rq *rq, struct task_struct *prev)
 	prev->sched_class->put_prev_task(rq, prev);
 }
 
+#ifdef CONFIG_SCHED_FAIR_CFS
+
+static inline int tasks_all_fair_class(struct rq *rq)
+{
+	return likely(rq->nr_running == rq->cfs.nr_running);
+}
+
+#elif CONFIG_SCHED_FAIR_HTFS
+
+static inline int tasks_all_fair_class(struct rq *rq)
+{
+	return likely(rq->nr_running == rq->htfs_rqs.nr_running);
+}
+
+#endif
+
 /*
  * Pick up the highest-prio task:
  */
@@ -3913,7 +4038,7 @@ pick_next_task(struct rq *rq)
 	 * Optimization: we know that if all tasks are in
 	 * the fair class we can call that function directly:
 	 */
-	if (likely(rq->nr_running == rq->cfs.nr_running)) {
+	if (likely(tasks_all_fair_class(rq))) {
 		p = fair_sched_class.pick_next_task(rq);
 		if (likely(p))
 			return p;
@@ -5584,6 +5709,7 @@ void __cpuinit init_idle(struct task_struct *idle, int cpu)
  */
 cpumask_var_t nohz_cpu_mask;
 
+#ifdef CONFIG_SCHED_FAIR_CFS
 /*
  * Increase the granularity value when there are more CPUs,
  * because with more CPUs the 'effective latency' as visible
@@ -5625,6 +5751,11 @@ static void update_sysctl(void)
 	SET_SYSCTL(sched_wakeup_granularity);
 #undef SET_SYSCTL
 }
+#else
+static void update_sysctl(void)
+{
+}
+#endif /* CONFIG_SCHED_FAIR_CFS */
 
 static inline void sched_init_granularity(void)
 {
@@ -7790,7 +7921,7 @@ int in_sched_functions(unsigned long addr)
 		(addr >= (unsigned long)__sched_text_start
 		&& addr < (unsigned long)__sched_text_end);
 }
-
+#ifdef CONFIG_SCHED_FAIR_CFS
 static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
 {
 	cfs_rq->tasks_timeline = RB_ROOT;
@@ -7800,6 +7931,46 @@ static void init_cfs_rq(struct cfs_rq *cfs_rq, struct rq *rq)
 #endif
 	cfs_rq->min_vruntime = (u64)(-(1LL << 20));
 }
+#elif CONFIG_SCHED_FAIR_HTFS
+
+static void init_htfs_pq(struct htfs_pq *pq, struct htfs_rq *rq)
+{
+	INIT_LIST_HEAD(&pq->spqs_real_weight);
+	INIT_LIST_HEAD(&pq->queue);
+	pq->real_bweight = 0;
+	pq->balance_ct = 0;
+}
+static void init_htfs_rq(struct htfs_rq *rq, struct htfs_rqs *rqs)
+{
+	int i = 50;
+	rq->bweight = 0;
+	rq->cur_pq = NULL;
+
+	INIT_LIST_HEAD(&rq->spqs_real_weight);
+
+	while (i--) {
+		init_htfs_pq(&rq->pqs[i], rq);
+	}
+	rq->rqs = rqs;
+}
+
+static void init_htfs_rqs(struct htfs_rqs *rqs, struct rq *rq)
+{
+	init_htfs_rq(&rqs->interq, rqs);
+	init_htfs_rq(&rqs->normalq, rqs);
+	rqs->nr_running = 0;
+	rqs->rq = rq;
+	rqs->dbg_counter = 0;
+	rqs->rq_balance_ct = 0;
+	rqs->vtime = 0; //TODO: perhaps in relation to the vtimes on other rqs
+	rqs->load_avg = 0;
+	rqs->load = 0;
+	rqs->offline_start = rq->clock;
+	rqs->weight = 0;
+	rqs->inv_weight = 0;
+	INIT_LIST_HEAD(&rqs->tasks);
+}
+#endif
 
 static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq)
 {
@@ -7838,6 +8009,8 @@ static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq)
 }
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
+
+#ifdef CONFIG_SCHED_FAIR_CFS
 static void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
 				struct sched_entity *se, int cpu,
 				struct sched_entity *parent)
@@ -7861,8 +8034,34 @@ static void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq,
 	update_load_set(&se->load, 0);
 	se->parent = parent;
 }
+#elif CONFIG_SCHED_FAIR_HTFS
+static void init_tg_htfs_entry(struct task_group *tg, struct htfs_rqs *rqs,
+				struct sched_entity *se, int cpu,
+				struct sched_entity *parent)
+{
+	struct rq *rq = cpu_rq(cpu);
+	tg->htfs_rqs[cpu] = rqs;
+	init_htfs_rqs(rqs, rq);
+	rqs->tg = tg;
+
+	tg->se[cpu] = se;
+	/* se could be NULL for root_task_group */
+	if (!se)
+		return;
+
+	if (!parent)
+		se->htfs_rqs = &rq->htfs_rqs;
+	else
+		se->htfs_rqs = parent->my_q;
+
+	se->my_q = rqs;
+	update_load_set(&se->load, 0);
+	se->parent = parent;
+}
 #endif
 
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
 #ifdef CONFIG_RT_GROUP_SCHED
 static void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq,
 		struct sched_rt_entity *rt_se, int cpu,
@@ -7910,8 +8109,11 @@ void __init sched_init(void)
 #ifdef CONFIG_FAIR_GROUP_SCHED
 		root_task_group.se = (struct sched_entity **)ptr;
 		ptr += nr_cpu_ids * sizeof(void **);
-
+#ifdef CONFIG_SCHED_FAIR_CFS
 		root_task_group.cfs_rq = (struct cfs_rq **)ptr;
+#elif CONFIG_SCHED_FAIR_HTFS
+		root_task_group.htfs_rqs = (struct htfs_rqs **)ptr;
+#endif
 		ptr += nr_cpu_ids * sizeof(void **);
 
 #endif /* CONFIG_FAIR_GROUP_SCHED */
@@ -7957,10 +8159,27 @@ void __init sched_init(void)
 		rq->nr_running = 0;
 		rq->calc_load_active = 0;
 		rq->calc_load_update = jiffies + LOAD_FREQ;
+#ifdef CONFIG_SCHED_FAIR_CFS
 		init_cfs_rq(&rq->cfs, rq);
+#elif CONFIG_SCHED_FAIR_HTFS
+		init_htfs_rqs(&rq->htfs_rqs, rq);
+		rq->slice_shift = 20;
+		rq->slice = (1UL << rq->slice_shift);
+		rq->slice_granted = rq->slice;
+		rq->slice_remain = 0;
+		rq->slice_change_last = 0;
+		rq->slice_shrink = 0;
+		rq->slice_shrink_last_dec = 0;
+		rq->last_call = 0;
+		rq->call_time_diff = 0;
+		rq->continue_run = NULL;
+		rq->force_sched = 0;
+		rq->continues = 0;
+#endif
 		init_rt_rq(&rq->rt, rq);
 #ifdef CONFIG_FAIR_GROUP_SCHED
 		root_task_group.shares = root_task_group_load;
+#ifdef CONFIG_SCHED_FAIR_CFS
 		INIT_LIST_HEAD(&rq->leaf_cfs_rq_list);
 		/*
 		 * How much cpu bandwidth does root_task_group get?
@@ -7982,6 +8201,11 @@ void __init sched_init(void)
 		 * directly in rq->cfs (i.e root_task_group->se[] = NULL).
 		 */
 		init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, NULL);
+#elif CONFIG_SCHED_FAIR_HTFS
+		INIT_LIST_HEAD(&rq->leaf_htfs_rqs_list);
+		init_tg_htfs_entry(&root_task_group, &rq->htfs_rqs, NULL, i, NULL);
+#endif
+
 #endif /* CONFIG_FAIR_GROUP_SCHED */
 
 		rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
@@ -8215,6 +8439,7 @@ void set_curr_task(int cpu, struct task_struct *p)
 #endif
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
+#ifdef CONFIG_SCHED_FAIR_CFS
 static void free_fair_sched_group(struct task_group *tg)
 {
 	int i;
@@ -8287,6 +8512,81 @@ static inline void unregister_fair_sched_group(struct task_group *tg, int cpu)
 	list_del_leaf_cfs_rq(tg->cfs_rq[cpu]);
 	raw_spin_unlock_irqrestore(&rq->lock, flags);
 }
+#elif CONFIG_SCHED_FAIR_HTFS
+static void free_fair_sched_group(struct task_group *tg)
+{
+	int i;
+
+	for_each_possible_cpu(i) {
+		if (tg->htfs_rqs)
+			kfree(tg->htfs_rqs[i]);
+		if (tg->se)
+			kfree(tg->se[i]);
+	}
+
+	kfree(tg->htfs_rqs);
+	kfree(tg->se);
+}
+
+static
+int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
+{
+	struct htfs_rqs *rqs;
+	struct sched_entity *se;
+	struct rq *rq;
+	int i;
+
+	tg->htfs_rqs = kzalloc(sizeof(rqs) * nr_cpu_ids, GFP_KERNEL);
+	if (!tg->htfs_rqs)
+		goto err;
+	tg->se = kzalloc(sizeof(se) * nr_cpu_ids, GFP_KERNEL);
+	if (!tg->se)
+		goto err;
+
+	tg->shares = NICE_0_LOAD;
+
+	for_each_possible_cpu(i) {
+		rq = cpu_rq(i);
+
+		rqs = kzalloc_node(sizeof(struct htfs_rqs),
+				      GFP_KERNEL, cpu_to_node(i));
+		if (!rqs)
+			goto err;
+
+		se = kzalloc_node(sizeof(struct sched_entity),
+				  GFP_KERNEL, cpu_to_node(i));
+		if (!se)
+			goto err_free_rq;
+
+		init_tg_htfs_entry(tg, rqs, se, i, parent->se[i]);
+	}
+
+	return 1;
+
+err_free_rq:
+	kfree(rqs);
+err:
+	return 0;
+}
+
+static inline void unregister_fair_sched_group(struct task_group *tg, int cpu)
+{
+	struct rq *rq = cpu_rq(cpu);
+	unsigned long flags;
+
+	/*
+	* Only empty task groups can be destroyed; so we can speculatively
+	* check on_list without danger of it being re-added.
+	*/
+	if (!tg->htfs_rqs[cpu]->on_list)
+		return;
+
+	raw_spin_lock_irqsave(&rq->lock, flags);
+	list_del_leaf_htfs_rqs(tg->htfs_rqs[cpu]);
+	raw_spin_unlock_irqrestore(&rq->lock, flags);
+}
+
+#endif /* CONFIG_SCHED_FAIR_HTFS */
 #else /* !CONFG_FAIR_GROUP_SCHED */
 static inline void free_fair_sched_group(struct task_group *tg)
 {
@@ -8510,8 +8810,13 @@ int sched_group_set_shares(struct task_group *tg, unsigned long shares)
 		se = tg->se[i];
 		/* Propagate contribution to hierarchy */
 		raw_spin_lock_irqsave(&rq->lock, flags);
-		for_each_sched_entity(se)
+		for_each_sched_entity(se) {
+#ifdef CONFIG_SCHED_FAIR_CFS
 			update_cfs_shares(group_cfs_rq(se), 0);
+#elif CONFIG_SCHED_FAIR_HTFS
+			update_htfs_shares(group_htfs_rqs(se));
+#endif
+		}
 		raw_spin_unlock_irqrestore(&rq->lock, flags);
 	}
 
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index eb6cb8e..55797fe 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -56,7 +56,7 @@ static unsigned long nsec_low(unsigned long long nsec)
 #define SPLIT_NS(x) nsec_high(x), nsec_low(x)
 
 #ifdef CONFIG_FAIR_GROUP_SCHED
-static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group *tg)
+static void print_fair_group_stats(struct seq_file *m, int cpu, struct task_group *tg)
 {
 	struct sched_entity *se = tg->se[cpu];
 	if (!se)
@@ -83,6 +83,14 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group
 	P(se->statistics.wait_count);
 #endif
 	P(se->load.weight);
+#ifdef CONFIG_SCHED_FAIR_HTFS
+	P(se->bw_ind);
+	P(se->inter);
+	P(se->inter_avg);
+	P(se->load.weight);
+	P(se->load_avg);
+	P(se->vruntime);
+#endif
 #undef PN
 #undef P
 }
@@ -130,6 +138,9 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
 	SEQ_printf(m, "%15Ld %15Ld %15Ld.%06ld %15Ld.%06ld %15Ld.%06ld",
 		0LL, 0LL, 0LL, 0L, 0LL, 0L, 0LL, 0L);
 #endif
+	SEQ_printf(m, "%d %u %u",
+		se_is_on_interq(&p->se),
+		p->se.htfs_state, p->se.bw_ind);
 #ifdef CONFIG_CGROUP_SCHED
 	SEQ_printf(m, " %s", task_group_path(task_group(p)));
 #endif
@@ -161,6 +172,8 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
 	read_unlock_irqrestore(&tasklist_lock, flags);
 }
 
+#ifdef CONFIG_SCHED_FAIR_CFS
+
 void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 {
 	s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1,
@@ -214,10 +227,63 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 			atomic_read(&cfs_rq->tg->load_weight));
 #endif
 
-	print_cfs_group_stats(m, cpu, cfs_rq->tg);
+	print_fair_group_stats(m, cpu, cfs_rq->tg);
+#endif
+}
+
+#elif CONFIG_SCHED_FAIR_HTFS /* CONFIG_SCHED_FAIR_CFS */
+
+void print_htfs_pq(struct seq_file *m, struct htfs_pq *pq)
+{
+	SEQ_printf(m, "      .%-30s: %lu\n", "real_bweight", pq->real_bweight);
+	SEQ_printf(m, "      .%-30s: %lu\n", "balance_ct", pq->balance_ct);
+}
+
+void print_htfs_rq(struct seq_file *m, struct htfs_rq *rq)
+{
+	struct htfs_pq *pq, *tmp;
+	SEQ_printf(m, "    .%-30s: %lu\n", "bweight", rq->bweight);
+	SEQ_printf(m, "    .%-30s: %lu\n", "run_cost", rq->run_cost);
+	list_for_each_entry_safe_reverse(pq, tmp, &rq->spqs_real_weight, spqs_real_weight) {
+		SEQ_printf(m, "    .pqs\n");
+		print_htfs_pq(m, pq);
+	}
+}
+
+void print_htfs_rqs(struct seq_file *m, int cpu, struct htfs_rqs *rqs)
+{
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+	SEQ_printf(m, "\nhtfs_rqs[%d]:%s\n", cpu, task_group_path(rqs->tg));
+#else
+	SEQ_printf(m, "\nhtfs_rqs[%d]:\n", cpu);
+#endif
+	SEQ_printf(m, "  .%-30s: %ld\n", "nr_running", rqs->nr_running);
+	SEQ_printf(m, "  .%-30s: %ld\n", "rq_balance_ct", rqs->rq_balance_ct);
+	SEQ_printf(m, "  .%-30s: %llu\n", "vtime", rqs->vtime);
+	SEQ_printf(m, "  .%-30s: %lu\n", "inv_weight", rqs->inv_weight);
+	SEQ_printf(m, "  .%-30s: %lu\n", "weight", rqs->weight);
+#ifdef CONFIG_FAIR_GROUP_SCHED
+	SEQ_printf(m, "  .%-30s: %d\n", "on_list", rqs->on_list);
+	SEQ_printf(m, "  .%-30s: %lu\n", "h_load", rqs->h_load);
+#ifdef CONFIG_SMP
+	SEQ_printf(m, "  .%-30s: %llu\n", "offline_start", rqs->offline_start);
+	SEQ_printf(m, "  .%-30s: %lu\n", "load", rqs->load);
+	SEQ_printf(m, "  .%-30s: %lu\n", "load_avg", rqs->load_avg);
+	SEQ_printf(m, "  .%-30s: %lu\n", "load_contribution", rqs->load_contribution);
+	SEQ_printf(m, "  .%-30s: %lu\n", "inter", rqs->inter);
+	SEQ_printf(m, "  .%-30s: %lu\n", "inter_avg", rqs->inter_avg);
 #endif
+	print_fair_group_stats(m, cpu, rqs->tg);
+#endif
+	SEQ_printf(m, "  .normalq\n");
+	print_htfs_rq(m, &rqs->normalq);
+	SEQ_printf(m, "  .interq\n");
+	print_htfs_rq(m, &rqs->interq);
 }
 
+#endif /* CONFIG_SCHED_FAIR_HTFS */
+
 void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
 {
 #ifdef CONFIG_RT_GROUP_SCHED
@@ -277,6 +343,15 @@ static void print_cpu(struct seq_file *m, int cpu)
 	P(cpu_load[2]);
 	P(cpu_load[3]);
 	P(cpu_load[4]);
+#ifdef CONFIG_SCHED_FAIR_HTFS
+	P(slice);
+	P(slice_shift);
+	P(slice_granted);
+	P(slice_remain);
+	P(slice_change_last);
+	P(slice_shrink);
+	P(slice_shrink_last_dec);
+#endif
 #undef P
 #undef PN
 
@@ -303,7 +378,11 @@ static void print_cpu(struct seq_file *m, int cpu)
 #undef P64
 #endif
 	spin_lock_irqsave(&sched_debug_lock, flags);
+#ifdef CONFIG_SCHED_FAIR_CFS
 	print_cfs_stats(m, cpu);
+#elif CONFIG_SCHED_FAIR_HTFS
+	print_htfs_stats(m, cpu);
+#endif
 	print_rt_stats(m, cpu);
 
 	rcu_read_lock();
@@ -312,11 +391,13 @@ static void print_cpu(struct seq_file *m, int cpu)
 	spin_unlock_irqrestore(&sched_debug_lock, flags);
 }
 
+#ifdef CONFIG_SCHED_FAIR_CFS
 static const char *sched_tunable_scaling_names[] = {
 	"none",
 	"logaritmic",
 	"linear"
 };
+#endif
 
 static int sched_debug_show(struct seq_file *m, void *v)
 {
@@ -352,6 +433,7 @@ static int sched_debug_show(struct seq_file *m, void *v)
 	SEQ_printf(m, "\n");
 	SEQ_printf(m, "sysctl_sched\n");
 
+#ifdef CONFIG_FAIR_SCHED_CFS
 #define P(x) \
 	SEQ_printf(m, "  .%-40s: %Ld\n", #x, (long long)(x))
 #define PN(x) \
@@ -367,7 +449,7 @@ static int sched_debug_show(struct seq_file *m, void *v)
 	SEQ_printf(m, "  .%-40s: %d (%s)\n", "sysctl_sched_tunable_scaling",
 		sysctl_sched_tunable_scaling,
 		sched_tunable_scaling_names[sysctl_sched_tunable_scaling]);
-
+#endif
 	for_each_online_cpu(cpu)
 		print_cpu(m, cpu);
 
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 7406f36..6ce6379 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -20,96 +20,10 @@
  *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
  */
 
-#include <linux/latencytop.h>
-#include <linux/sched.h>
-
-/*
- * Targeted preemption latency for CPU-bound tasks:
- * (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds)
- *
- * NOTE: this latency value is not the same as the concept of
- * 'timeslice length' - timeslices in CFS are of variable length
- * and have no persistent notion like in traditional, time-slice
- * based scheduling concepts.
- *
- * (to see the precise effective timeslice length of your workload,
- *  run vmstat and monitor the context-switches (cs) field)
- */
-unsigned int sysctl_sched_latency = 6000000ULL;
-unsigned int normalized_sysctl_sched_latency = 6000000ULL;
-
-/*
- * The initial- and re-scaling of tunables is configurable
- * (default SCHED_TUNABLESCALING_LOG = *(1+ilog(ncpus))
- *
- * Options are:
- * SCHED_TUNABLESCALING_NONE - unscaled, always *1
- * SCHED_TUNABLESCALING_LOG - scaled logarithmical, *1+ilog(ncpus)
- * SCHED_TUNABLESCALING_LINEAR - scaled linear, *ncpus
- */
-enum sched_tunable_scaling sysctl_sched_tunable_scaling
-	= SCHED_TUNABLESCALING_LOG;
-
-/*
- * Minimal preemption granularity for CPU-bound tasks:
- * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds)
- */
-unsigned int sysctl_sched_min_granularity = 750000ULL;
-unsigned int normalized_sysctl_sched_min_granularity = 750000ULL;
-
-/*
- * is kept at sysctl_sched_latency / sysctl_sched_min_granularity
- */
-static unsigned int sched_nr_latency = 8;
-
-/*
- * After fork, child runs first. If set to 0 (default) then
- * parent will (try to) run first.
- */
-unsigned int sysctl_sched_child_runs_first __read_mostly;
-
-/*
- * sys_sched_yield() compat mode
- *
- * This option switches the agressive yield implementation of the
- * old scheduler back on.
- */
-unsigned int __read_mostly sysctl_sched_compat_yield;
-
-/*
- * SCHED_OTHER wake-up granularity.
- * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds)
- *
- * This option delays the preemption effects of decoupled workloads
- * and reduces their over-scheduling. Synchronous workloads will still
- * have immediate wakeup/sleep latencies.
- */
-unsigned int sysctl_sched_wakeup_granularity = 1000000UL;
-unsigned int normalized_sysctl_sched_wakeup_granularity = 1000000UL;
-
 const_debug unsigned int sysctl_sched_migration_cost = 500000UL;
 
-/*
- * The exponential sliding  window over which load is averaged for shares
- * distribution.
- * (default: 10msec)
- */
-unsigned int __read_mostly sysctl_sched_shares_window = 10000000UL;
-
-static const struct sched_class fair_sched_class;
-
-/**************************************************************
- * CFS operations on generic schedulable entities:
- */
-
 #ifdef CONFIG_FAIR_GROUP_SCHED
 
-/* cpu runqueue to which this cfs_rq is attached */
-static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
-{
-	return cfs_rq->rq;
-}
-
 /* An entity is a task if it doesn't "own" a runqueue */
 #define entity_is_task(se)	(!se->my_q)
 
@@ -125,75 +39,6 @@ static inline struct task_struct *task_of(struct sched_entity *se)
 #define for_each_sched_entity(se) \
 		for (; se; se = se->parent)
 
-static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
-{
-	return p->se.cfs_rq;
-}
-
-/* runqueue on which this entity is (to be) queued */
-static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
-{
-	return se->cfs_rq;
-}
-
-/* runqueue "owned" by this group */
-static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
-{
-	return grp->my_q;
-}
-
-/* Given a group's cfs_rq on one cpu, return its corresponding cfs_rq on
- * another cpu ('this_cpu')
- */
-static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
-{
-	return cfs_rq->tg->cfs_rq[this_cpu];
-}
-
-static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
-{
-	if (!cfs_rq->on_list) {
-		/*
-		 * Ensure we either appear before our parent (if already
-		 * enqueued) or force our parent to appear after us when it is
-		 * enqueued.  The fact that we always enqueue bottom-up
-		 * reduces this to two cases.
-		 */
-		if (cfs_rq->tg->parent &&
-		    cfs_rq->tg->parent->cfs_rq[cpu_of(rq_of(cfs_rq))]->on_list) {
-			list_add_rcu(&cfs_rq->leaf_cfs_rq_list,
-				&rq_of(cfs_rq)->leaf_cfs_rq_list);
-		} else {
-			list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
-				&rq_of(cfs_rq)->leaf_cfs_rq_list);
-		}
-
-		cfs_rq->on_list = 1;
-	}
-}
-
-static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
-{
-	if (cfs_rq->on_list) {
-		list_del_rcu(&cfs_rq->leaf_cfs_rq_list);
-		cfs_rq->on_list = 0;
-	}
-}
-
-/* Iterate thr' all leaf cfs_rq's on a runqueue */
-#define for_each_leaf_cfs_rq(rq, cfs_rq) \
-	list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
-
-/* Do the two (enqueued) entities belong to the same group ? */
-static inline int
-is_same_group(struct sched_entity *se, struct sched_entity *pse)
-{
-	if (se->cfs_rq == pse->cfs_rq)
-		return 1;
-
-	return 0;
-}
-
 static inline struct sched_entity *parent_entity(struct sched_entity *se)
 {
 	return se->parent;
@@ -210,38 +55,6 @@ static inline int depth_se(struct sched_entity *se)
 	return depth;
 }
 
-static void
-find_matching_se(struct sched_entity **se, struct sched_entity **pse)
-{
-	int se_depth, pse_depth;
-
-	/*
-	 * preemption test can be made between sibling entities who are in the
-	 * same cfs_rq i.e who have a common parent. Walk up the hierarchy of
-	 * both tasks until we find their ancestors who are siblings of common
-	 * parent.
-	 */
-
-	/* First walk up until both entities are at same depth */
-	se_depth = depth_se(*se);
-	pse_depth = depth_se(*pse);
-
-	while (se_depth > pse_depth) {
-		se_depth--;
-		*se = parent_entity(*se);
-	}
-
-	while (pse_depth > se_depth) {
-		pse_depth--;
-		*pse = parent_entity(*pse);
-	}
-
-	while (!is_same_group(*se, *pse)) {
-		*se = parent_entity(*se);
-		*pse = parent_entity(*pse);
-	}
-}
-
 #else	/* !CONFIG_FAIR_GROUP_SCHED */
 
 static inline struct task_struct *task_of(struct sched_entity *se)
@@ -249,1956 +62,441 @@ static inline struct task_struct *task_of(struct sched_entity *se)
 	return container_of(se, struct task_struct, se);
 }
 
-static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
-{
-	return container_of(cfs_rq, struct rq, cfs);
-}
-
 #define entity_is_task(se)	1
 
 #define for_each_sched_entity(se) \
 		for (; se; se = NULL)
 
-static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
+#endif	/* CONFIG_FAIR_GROUP_SCHED */
+
+#ifdef CONFIG_SMP
+/**
+ * group_first_cpu - Returns the first cpu in the cpumask of a sched_group.
+ * @group: The group whose first cpu is to be returned.
+ */
+static inline unsigned int group_first_cpu(struct sched_group *group)
 {
-	return &task_rq(p)->cfs;
+	return cpumask_first(sched_group_cpus(group));
 }
 
-static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
-{
-	struct task_struct *p = task_of(se);
-	struct rq *rq = task_rq(p);
+static void rq_online_fair(struct rq *rq);
+static void rq_offline_fair(struct rq *rq);
+static int
+select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_flags);
+#endif
 
-	return &rq->cfs;
-}
 
-/* runqueue "owned" by this group */
-static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
-{
-	return NULL;
-}
+#ifdef CONFIG_SCHED_FAIR_CFS
+#include "sched_fair_cfs.c"
+#elif CONFIG_SCHED_FAIR_HTFS
+#include "sched_fair_htfs.c"
+#endif
 
-static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
-{
-	return &cpu_rq(this_cpu)->cfs;
-}
 
-static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
-{
-}
 
-static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
-{
-}
 
-#define for_each_leaf_cfs_rq(rq, cfs_rq) \
-		for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
 
-static inline int
-is_same_group(struct sched_entity *se, struct sched_entity *pse)
-{
-	return 1;
-}
+#ifdef CONFIG_SMP
 
-static inline struct sched_entity *parent_entity(struct sched_entity *se)
+#ifdef CONFIG_FAIR_GROUP_SCHED
+/*
+ * effective_load() calculates the load change as seen from the root_task_group
+ *
+ * Adding load to a group doesn't make a group heavier, but can cause movement
+ * of group shares between cpus. Assuming the shares were perfectly aligned one
+ * can calculate the shift in shares.
+ */
+static long effective_load(struct task_group *tg, int cpu, long wl, long wg)
 {
-	return NULL;
-}
+	struct sched_entity *se = tg->se[cpu];
 
-static inline void
-find_matching_se(struct sched_entity **se, struct sched_entity **pse)
-{
-}
+	if (!tg->parent)
+		return wl;
 
-#endif	/* CONFIG_FAIR_GROUP_SCHED */
+	for_each_sched_entity(se) {
+		long lw, w;
 
+		tg = se->my_q->tg;
+#ifdef CONFIG_SCHED_FAIR_CFS
+		w = se->my_q->load.weight;
+#elif CONFIG_SCHED_FAIR_HTFS
+		w = se->my_q->weight;
+#endif
 
-/**************************************************************
- * Scheduling class tree data structure manipulation methods:
- */
+		/* use this cpu's instantaneous contribution */
+		lw = atomic_read(&tg->load_weight);
+		lw -= se->my_q->load_contribution;
+		lw += w + wg;
 
-static inline u64 max_vruntime(u64 min_vruntime, u64 vruntime)
-{
-	s64 delta = (s64)(vruntime - min_vruntime);
-	if (delta > 0)
-		min_vruntime = vruntime;
+		wl += w;
 
-	return min_vruntime;
-}
+		if (lw > 0 && wl < lw)
+			wl = (wl * tg->shares) / lw;
+		else
+			wl = tg->shares;
 
-static inline u64 min_vruntime(u64 min_vruntime, u64 vruntime)
-{
-	s64 delta = (s64)(vruntime - min_vruntime);
-	if (delta < 0)
-		min_vruntime = vruntime;
+		/* zero point is MIN_SHARES */
+		if (wl < MIN_SHARES)
+			wl = MIN_SHARES;
+		wl -= se->load.weight;
+		wg = 0;
+	}
 
-	return min_vruntime;
+	return wl;
 }
 
-static inline int entity_before(struct sched_entity *a,
-				struct sched_entity *b)
-{
-	return (s64)(a->vruntime - b->vruntime) < 0;
-}
+#else
 
-static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
+static inline unsigned long effective_load(struct task_group *tg, int cpu,
+		unsigned long wl, unsigned long wg)
 {
-	return se->vruntime - cfs_rq->min_vruntime;
+	return wl;
 }
 
-static void update_min_vruntime(struct cfs_rq *cfs_rq)
+#endif
+
+static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
 {
-	u64 vruntime = cfs_rq->min_vruntime;
+	s64 this_load, load;
+	int idx, this_cpu, prev_cpu;
+	unsigned long tl_per_task;
+	struct task_group *tg;
+	unsigned long weight;
+	int balanced;
 
-	if (cfs_rq->curr)
-		vruntime = cfs_rq->curr->vruntime;
+	idx	  = sd->wake_idx;
+	this_cpu  = smp_processor_id();
+	prev_cpu  = task_cpu(p);
+	load	  = source_load(prev_cpu, idx);
+	this_load = target_load(this_cpu, idx);
 
-	if (cfs_rq->rb_leftmost) {
-		struct sched_entity *se = rb_entry(cfs_rq->rb_leftmost,
-						   struct sched_entity,
-						   run_node);
+	/*
+	 * If sync wakeup then subtract the (maximum possible)
+	 * effect of the currently running task from the load
+	 * of the current CPU:
+	 */
+	rcu_read_lock();
+	if (sync) {
+		tg = task_group(current);
+		weight = current->se.load.weight;
 
-		if (!cfs_rq->curr)
-			vruntime = se->vruntime;
-		else
-			vruntime = min_vruntime(vruntime, se->vruntime);
+		this_load += effective_load(tg, this_cpu, -weight, -weight);
+		load += effective_load(tg, prev_cpu, 0, -weight);
 	}
 
-	cfs_rq->min_vruntime = max_vruntime(cfs_rq->min_vruntime, vruntime);
-}
-
-/*
- * Enqueue an entity into the rb-tree:
- */
-static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
-	struct rb_node *parent = NULL;
-	struct sched_entity *entry;
-	s64 key = entity_key(cfs_rq, se);
-	int leftmost = 1;
+	tg = task_group(p);
+	weight = p->se.load.weight;
 
 	/*
-	 * Find the right place in the rbtree:
+	 * In low-load situations, where prev_cpu is idle and this_cpu is idle
+	 * due to the sync cause above having dropped this_load to 0, we'll
+	 * always have an imbalance, but there's really nothing you can do
+	 * about that, so that's good too.
+	 *
+	 * Otherwise check if either cpus are near enough in load to allow this
+	 * task to be woken on this_cpu.
 	 */
-	while (*link) {
-		parent = *link;
-		entry = rb_entry(parent, struct sched_entity, run_node);
-		/*
-		 * We dont care about collisions. Nodes with
-		 * the same key stay together.
-		 */
-		if (key < entity_key(cfs_rq, entry)) {
-			link = &parent->rb_left;
-		} else {
-			link = &parent->rb_right;
-			leftmost = 0;
-		}
-	}
+	if (this_load > 0) {
+		s64 this_eff_load, prev_eff_load;
+
+		this_eff_load = 100;
+		this_eff_load *= power_of(prev_cpu);
+		this_eff_load *= this_load +
+			effective_load(tg, this_cpu, weight, weight);
+
+		prev_eff_load = 100 + (sd->imbalance_pct - 100) / 2;
+		prev_eff_load *= power_of(this_cpu);
+		prev_eff_load *= load + effective_load(tg, prev_cpu, 0, weight);
+
+		balanced = this_eff_load <= prev_eff_load;
+	} else
+		balanced = true;
+	rcu_read_unlock();
 
 	/*
-	 * Maintain a cache of leftmost tree entries (it is frequently
-	 * used):
+	 * If the currently running task will sleep within
+	 * a reasonable amount of time then attract this newly
+	 * woken task:
 	 */
-	if (leftmost)
-		cfs_rq->rb_leftmost = &se->run_node;
+	if (sync && balanced)
+		return 1;
 
-	rb_link_node(&se->run_node, parent, link);
-	rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
-}
+	schedstat_inc(p, se.statistics.nr_wakeups_affine_attempts);
+	tl_per_task = cpu_avg_load_per_task(this_cpu);
 
-static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	if (cfs_rq->rb_leftmost == &se->run_node) {
-		struct rb_node *next_node;
+	if (balanced ||
+	    (this_load <= load &&
+	     this_load + target_load(prev_cpu, idx) <= tl_per_task)) {
+		/*
+		 * This domain has SD_WAKE_AFFINE and
+		 * p is cache cold in this domain, and
+		 * there is no bad imbalance.
+		 */
+		schedstat_inc(sd, ttwu_move_affine);
+		schedstat_inc(p, se.statistics.nr_wakeups_affine);
 
-		next_node = rb_next(&se->run_node);
-		cfs_rq->rb_leftmost = next_node;
+		return 1;
 	}
-
-	rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
+	return 0;
 }
 
-static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
+/*
+ * find_idlest_group finds and returns the least busy CPU group within the
+ * domain.
+ */
+static struct sched_group *
+find_idlest_group(struct sched_domain *sd, struct task_struct *p,
+		  int this_cpu, int load_idx)
 {
-	struct rb_node *left = cfs_rq->rb_leftmost;
+	struct sched_group *idlest = NULL, *group = sd->groups;
+	unsigned long min_load = ULONG_MAX, this_load = 0;
+	int imbalance = 100 + (sd->imbalance_pct-100)/2;
 
-	if (!left)
-		return NULL;
-
-	return rb_entry(left, struct sched_entity, run_node);
-}
-
-static struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
-{
-	struct rb_node *last = rb_last(&cfs_rq->tasks_timeline);
-
-	if (!last)
-		return NULL;
-
-	return rb_entry(last, struct sched_entity, run_node);
-}
-
-/**************************************************************
- * Scheduling class statistics methods:
- */
-
-#ifdef CONFIG_SCHED_DEBUG
-int sched_proc_update_handler(struct ctl_table *table, int write,
-		void __user *buffer, size_t *lenp,
-		loff_t *ppos)
-{
-	int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
-	int factor = get_update_sysctl_factor();
-
-	if (ret || !write)
-		return ret;
-
-	sched_nr_latency = DIV_ROUND_UP(sysctl_sched_latency,
-					sysctl_sched_min_granularity);
-
-#define WRT_SYSCTL(name) \
-	(normalized_sysctl_##name = sysctl_##name / (factor))
-	WRT_SYSCTL(sched_min_granularity);
-	WRT_SYSCTL(sched_latency);
-	WRT_SYSCTL(sched_wakeup_granularity);
-#undef WRT_SYSCTL
-
-	return 0;
-}
-#endif
-
-/*
- * delta /= w
- */
-static inline unsigned long
-calc_delta_fair(unsigned long delta, struct sched_entity *se)
-{
-	if (unlikely(se->load.weight != NICE_0_LOAD))
-		delta = calc_delta_mine(delta, NICE_0_LOAD, &se->load);
-
-	return delta;
-}
-
-/*
- * The idea is to set a period in which each task runs once.
- *
- * When there are too many tasks (sysctl_sched_nr_latency) we have to stretch
- * this period because otherwise the slices get too small.
- *
- * p = (nr <= nl) ? l : l*nr/nl
- */
-static u64 __sched_period(unsigned long nr_running)
-{
-	u64 period = sysctl_sched_latency;
-	unsigned long nr_latency = sched_nr_latency;
-
-	if (unlikely(nr_running > nr_latency)) {
-		period = sysctl_sched_min_granularity;
-		period *= nr_running;
-	}
-
-	return period;
-}
-
-/*
- * We calculate the wall-time slice from the period by taking a part
- * proportional to the weight.
- *
- * s = p*P[w/rw]
- */
-static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	u64 slice = __sched_period(cfs_rq->nr_running + !se->on_rq);
-
-	for_each_sched_entity(se) {
-		struct load_weight *load;
-		struct load_weight lw;
-
-		cfs_rq = cfs_rq_of(se);
-		load = &cfs_rq->load;
-
-		if (unlikely(!se->on_rq)) {
-			lw = cfs_rq->load;
-
-			update_load_add(&lw, se->load.weight);
-			load = &lw;
-		}
-		slice = calc_delta_mine(slice, se->load.weight, load);
-	}
-	return slice;
-}
-
-/*
- * We calculate the vruntime slice of a to be inserted task
- *
- * vs = s/w
- */
-static u64 sched_vslice(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	return calc_delta_fair(sched_slice(cfs_rq, se), se);
-}
-
-static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update);
-static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta);
-
-/*
- * Update the current task's runtime statistics. Skip current tasks that
- * are not in our scheduling class.
- */
-static inline void
-__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
-	      unsigned long delta_exec)
-{
-	unsigned long delta_exec_weighted;
-
-	schedstat_set(curr->statistics.exec_max,
-		      max((u64)delta_exec, curr->statistics.exec_max));
-
-	curr->sum_exec_runtime += delta_exec;
-	schedstat_add(cfs_rq, exec_clock, delta_exec);
-	delta_exec_weighted = calc_delta_fair(delta_exec, curr);
-
-	curr->vruntime += delta_exec_weighted;
-	update_min_vruntime(cfs_rq);
-
-#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
-	cfs_rq->load_unacc_exec_time += delta_exec;
-#endif
-}
-
-static void update_curr(struct cfs_rq *cfs_rq)
-{
-	struct sched_entity *curr = cfs_rq->curr;
-	u64 now = rq_of(cfs_rq)->clock_task;
-	unsigned long delta_exec;
-
-	if (unlikely(!curr))
-		return;
-
-	/*
-	 * Get the amount of time the current task was running
-	 * since the last time we changed load (this cannot
-	 * overflow on 32 bits):
-	 */
-	delta_exec = (unsigned long)(now - curr->exec_start);
-	if (!delta_exec)
-		return;
-
-	__update_curr(cfs_rq, curr, delta_exec);
-	curr->exec_start = now;
-
-	if (entity_is_task(curr)) {
-		struct task_struct *curtask = task_of(curr);
-
-		trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime);
-		cpuacct_charge(curtask, delta_exec);
-		account_group_exec_runtime(curtask, delta_exec);
-	}
-}
-
-static inline void
-update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	schedstat_set(se->statistics.wait_start, rq_of(cfs_rq)->clock);
-}
-
-/*
- * Task is being enqueued - update stats:
- */
-static void update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	/*
-	 * Are we enqueueing a waiting task? (for current tasks
-	 * a dequeue/enqueue event is a NOP)
-	 */
-	if (se != cfs_rq->curr)
-		update_stats_wait_start(cfs_rq, se);
-}
-
-static void
-update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	schedstat_set(se->statistics.wait_max, max(se->statistics.wait_max,
-			rq_of(cfs_rq)->clock - se->statistics.wait_start));
-	schedstat_set(se->statistics.wait_count, se->statistics.wait_count + 1);
-	schedstat_set(se->statistics.wait_sum, se->statistics.wait_sum +
-			rq_of(cfs_rq)->clock - se->statistics.wait_start);
-#ifdef CONFIG_SCHEDSTATS
-	if (entity_is_task(se)) {
-		trace_sched_stat_wait(task_of(se),
-			rq_of(cfs_rq)->clock - se->statistics.wait_start);
-	}
-#endif
-	schedstat_set(se->statistics.wait_start, 0);
-}
-
-static inline void
-update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	/*
-	 * Mark the end of the wait period if dequeueing a
-	 * waiting task:
-	 */
-	if (se != cfs_rq->curr)
-		update_stats_wait_end(cfs_rq, se);
-}
-
-/*
- * We are picking a new current task - update its stats:
- */
-static inline void
-update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	/*
-	 * We are starting a new run period:
-	 */
-	se->exec_start = rq_of(cfs_rq)->clock_task;
-}
-
-/**************************************************
- * Scheduling class queueing methods:
- */
-
-#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
-static void
-add_cfs_task_weight(struct cfs_rq *cfs_rq, unsigned long weight)
-{
-	cfs_rq->task_weight += weight;
-}
-#else
-static inline void
-add_cfs_task_weight(struct cfs_rq *cfs_rq, unsigned long weight)
-{
-}
-#endif
-
-static void
-account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	update_load_add(&cfs_rq->load, se->load.weight);
-	if (!parent_entity(se))
-		inc_cpu_load(rq_of(cfs_rq), se->load.weight);
-	if (entity_is_task(se)) {
-		add_cfs_task_weight(cfs_rq, se->load.weight);
-		list_add(&se->group_node, &cfs_rq->tasks);
-	}
-	cfs_rq->nr_running++;
-}
-
-static void
-account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	update_load_sub(&cfs_rq->load, se->load.weight);
-	if (!parent_entity(se))
-		dec_cpu_load(rq_of(cfs_rq), se->load.weight);
-	if (entity_is_task(se)) {
-		add_cfs_task_weight(cfs_rq, -se->load.weight);
-		list_del_init(&se->group_node);
-	}
-	cfs_rq->nr_running--;
-}
-
-#ifdef CONFIG_FAIR_GROUP_SCHED
-# ifdef CONFIG_SMP
-static void update_cfs_rq_load_contribution(struct cfs_rq *cfs_rq,
-					    int global_update)
-{
-	struct task_group *tg = cfs_rq->tg;
-	long load_avg;
-
-	load_avg = div64_u64(cfs_rq->load_avg, cfs_rq->load_period+1);
-	load_avg -= cfs_rq->load_contribution;
-
-	if (global_update || abs(load_avg) > cfs_rq->load_contribution / 8) {
-		atomic_add(load_avg, &tg->load_weight);
-		cfs_rq->load_contribution += load_avg;
-	}
-}
-
-static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
-{
-	u64 period = sysctl_sched_shares_window;
-	u64 now, delta;
-	unsigned long load = cfs_rq->load.weight;
-
-	if (cfs_rq->tg == &root_task_group)
-		return;
-
-	now = rq_of(cfs_rq)->clock_task;
-	delta = now - cfs_rq->load_stamp;
-
-	/* truncate load history at 4 idle periods */
-	if (cfs_rq->load_stamp > cfs_rq->load_last &&
-	    now - cfs_rq->load_last > 4 * period) {
-		cfs_rq->load_period = 0;
-		cfs_rq->load_avg = 0;
-	}
-
-	cfs_rq->load_stamp = now;
-	cfs_rq->load_unacc_exec_time = 0;
-	cfs_rq->load_period += delta;
-	if (load) {
-		cfs_rq->load_last = now;
-		cfs_rq->load_avg += delta * load;
-	}
-
-	/* consider updating load contribution on each fold or truncate */
-	if (global_update || cfs_rq->load_period > period
-	    || !cfs_rq->load_period)
-		update_cfs_rq_load_contribution(cfs_rq, global_update);
-
-	while (cfs_rq->load_period > period) {
-		/*
-		 * Inline assembly required to prevent the compiler
-		 * optimising this loop into a divmod call.
-		 * See __iter_div_u64_rem() for another example of this.
-		 */
-		asm("" : "+rm" (cfs_rq->load_period));
-		cfs_rq->load_period /= 2;
-		cfs_rq->load_avg /= 2;
-	}
-
-	if (!cfs_rq->curr && !cfs_rq->nr_running && !cfs_rq->load_avg)
-		list_del_leaf_cfs_rq(cfs_rq);
-}
-
-static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
-				long weight_delta)
-{
-	long load_weight, load, shares;
-
-	load = cfs_rq->load.weight + weight_delta;
-
-	load_weight = atomic_read(&tg->load_weight);
-	load_weight -= cfs_rq->load_contribution;
-	load_weight += load;
-
-	shares = (tg->shares * load);
-	if (load_weight)
-		shares /= load_weight;
-
-	if (shares < MIN_SHARES)
-		shares = MIN_SHARES;
-	if (shares > tg->shares)
-		shares = tg->shares;
-
-	return shares;
-}
-
-static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
-{
-	if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
-		update_cfs_load(cfs_rq, 0);
-		update_cfs_shares(cfs_rq, 0);
-	}
-}
-# else /* CONFIG_SMP */
-static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
-{
-}
-
-static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
-				long weight_delta)
-{
-	return tg->shares;
-}
-
-static inline void update_entity_shares_tick(struct cfs_rq *cfs_rq)
-{
-}
-# endif /* CONFIG_SMP */
-static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
-			    unsigned long weight)
-{
-	if (se->on_rq) {
-		/* commit outstanding execution time */
-		if (cfs_rq->curr == se)
-			update_curr(cfs_rq);
-		account_entity_dequeue(cfs_rq, se);
-	}
-
-	update_load_set(&se->load, weight);
-
-	if (se->on_rq)
-		account_entity_enqueue(cfs_rq, se);
-}
-
-static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
-{
-	struct task_group *tg;
-	struct sched_entity *se;
-	long shares;
-
-	tg = cfs_rq->tg;
-	se = tg->se[cpu_of(rq_of(cfs_rq))];
-	if (!se)
-		return;
-#ifndef CONFIG_SMP
-	if (likely(se->load.weight == tg->shares))
-		return;
-#endif
-	shares = calc_cfs_shares(cfs_rq, tg, weight_delta);
-
-	reweight_entity(cfs_rq_of(se), se, shares);
-}
-#else /* CONFIG_FAIR_GROUP_SCHED */
-static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
-{
-}
-
-static inline void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
-{
-}
-
-static inline void update_entity_shares_tick(struct cfs_rq *cfs_rq)
-{
-}
-#endif /* CONFIG_FAIR_GROUP_SCHED */
-
-static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-#ifdef CONFIG_SCHEDSTATS
-	struct task_struct *tsk = NULL;
-
-	if (entity_is_task(se))
-		tsk = task_of(se);
-
-	if (se->statistics.sleep_start) {
-		u64 delta = rq_of(cfs_rq)->clock - se->statistics.sleep_start;
-
-		if ((s64)delta < 0)
-			delta = 0;
-
-		if (unlikely(delta > se->statistics.sleep_max))
-			se->statistics.sleep_max = delta;
-
-		se->statistics.sleep_start = 0;
-		se->statistics.sum_sleep_runtime += delta;
-
-		if (tsk) {
-			account_scheduler_latency(tsk, delta >> 10, 1);
-			trace_sched_stat_sleep(tsk, delta);
-		}
-	}
-	if (se->statistics.block_start) {
-		u64 delta = rq_of(cfs_rq)->clock - se->statistics.block_start;
-
-		if ((s64)delta < 0)
-			delta = 0;
-
-		if (unlikely(delta > se->statistics.block_max))
-			se->statistics.block_max = delta;
-
-		se->statistics.block_start = 0;
-		se->statistics.sum_sleep_runtime += delta;
-
-		if (tsk) {
-			if (tsk->in_iowait) {
-				se->statistics.iowait_sum += delta;
-				se->statistics.iowait_count++;
-				trace_sched_stat_iowait(tsk, delta);
-			}
-
-			/*
-			 * Blocking time is in units of nanosecs, so shift by
-			 * 20 to get a milliseconds-range estimation of the
-			 * amount of time that the task spent sleeping:
-			 */
-			if (unlikely(prof_on == SLEEP_PROFILING)) {
-				profile_hits(SLEEP_PROFILING,
-						(void *)get_wchan(tsk),
-						delta >> 20);
-			}
-			account_scheduler_latency(tsk, delta >> 10, 0);
-		}
-	}
-#endif
-}
-
-static void check_spread(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-#ifdef CONFIG_SCHED_DEBUG
-	s64 d = se->vruntime - cfs_rq->min_vruntime;
-
-	if (d < 0)
-		d = -d;
-
-	if (d > 3*sysctl_sched_latency)
-		schedstat_inc(cfs_rq, nr_spread_over);
-#endif
-}
-
-static void
-place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
-{
-	u64 vruntime = cfs_rq->min_vruntime;
-
-	/*
-	 * The 'current' period is already promised to the current tasks,
-	 * however the extra weight of the new task will slow them down a
-	 * little, place the new task so that it fits in the slot that
-	 * stays open at the end.
-	 */
-	if (initial && sched_feat(START_DEBIT))
-		vruntime += sched_vslice(cfs_rq, se);
-
-	/* sleeps up to a single latency don't count. */
-	if (!initial) {
-		unsigned long thresh = sysctl_sched_latency;
-
-		/*
-		 * Halve their sleep time's effect, to allow
-		 * for a gentler effect of sleepers:
-		 */
-		if (sched_feat(GENTLE_FAIR_SLEEPERS))
-			thresh >>= 1;
-
-		vruntime -= thresh;
-	}
-
-	/* ensure we never gain time by being placed backwards. */
-	vruntime = max_vruntime(se->vruntime, vruntime);
-
-	se->vruntime = vruntime;
-}
-
-static void
-enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
-{
-	/*
-	 * Update the normalized vruntime before updating min_vruntime
-	 * through callig update_curr().
-	 */
-	if (!(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_WAKING))
-		se->vruntime += cfs_rq->min_vruntime;
-
-	/*
-	 * Update run-time statistics of the 'current'.
-	 */
-	update_curr(cfs_rq);
-	update_cfs_load(cfs_rq, 0);
-	update_cfs_shares(cfs_rq, se->load.weight);
-	account_entity_enqueue(cfs_rq, se);
-
-	if (flags & ENQUEUE_WAKEUP) {
-		place_entity(cfs_rq, se, 0);
-		enqueue_sleeper(cfs_rq, se);
-	}
-
-	update_stats_enqueue(cfs_rq, se);
-	check_spread(cfs_rq, se);
-	if (se != cfs_rq->curr)
-		__enqueue_entity(cfs_rq, se);
-	se->on_rq = 1;
-
-	if (cfs_rq->nr_running == 1)
-		list_add_leaf_cfs_rq(cfs_rq);
-}
-
-static void __clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	if (!se || cfs_rq->last == se)
-		cfs_rq->last = NULL;
-
-	if (!se || cfs_rq->next == se)
-		cfs_rq->next = NULL;
-}
-
-static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	for_each_sched_entity(se)
-		__clear_buddies(cfs_rq_of(se), se);
-}
-
-static void
-dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
-{
-	/*
-	 * Update run-time statistics of the 'current'.
-	 */
-	update_curr(cfs_rq);
-
-	update_stats_dequeue(cfs_rq, se);
-	if (flags & DEQUEUE_SLEEP) {
-#ifdef CONFIG_SCHEDSTATS
-		if (entity_is_task(se)) {
-			struct task_struct *tsk = task_of(se);
-
-			if (tsk->state & TASK_INTERRUPTIBLE)
-				se->statistics.sleep_start = rq_of(cfs_rq)->clock;
-			if (tsk->state & TASK_UNINTERRUPTIBLE)
-				se->statistics.block_start = rq_of(cfs_rq)->clock;
-		}
-#endif
-	}
-
-	clear_buddies(cfs_rq, se);
-
-	if (se != cfs_rq->curr)
-		__dequeue_entity(cfs_rq, se);
-	se->on_rq = 0;
-	update_cfs_load(cfs_rq, 0);
-	account_entity_dequeue(cfs_rq, se);
-	update_min_vruntime(cfs_rq);
-	update_cfs_shares(cfs_rq, 0);
-
-	/*
-	 * Normalize the entity after updating the min_vruntime because the
-	 * update can refer to the ->curr item and we need to reflect this
-	 * movement in our normalized position.
-	 */
-	if (!(flags & DEQUEUE_SLEEP))
-		se->vruntime -= cfs_rq->min_vruntime;
-}
-
-/*
- * Preempt the current task with a newly woken task if needed:
- */
-static void
-check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
-{
-	unsigned long ideal_runtime, delta_exec;
-
-	ideal_runtime = sched_slice(cfs_rq, curr);
-	delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
-	if (delta_exec > ideal_runtime) {
-		resched_task(rq_of(cfs_rq)->curr);
-		/*
-		 * The current task ran long enough, ensure it doesn't get
-		 * re-elected due to buddy favours.
-		 */
-		clear_buddies(cfs_rq, curr);
-		return;
-	}
-
-	/*
-	 * Ensure that a task that missed wakeup preemption by a
-	 * narrow margin doesn't have to wait for a full slice.
-	 * This also mitigates buddy induced latencies under load.
-	 */
-	if (!sched_feat(WAKEUP_PREEMPT))
-		return;
-
-	if (delta_exec < sysctl_sched_min_granularity)
-		return;
-
-	if (cfs_rq->nr_running > 1) {
-		struct sched_entity *se = __pick_next_entity(cfs_rq);
-		s64 delta = curr->vruntime - se->vruntime;
-
-		if (delta < 0)
-			return;
-
-		if (delta > ideal_runtime)
-			resched_task(rq_of(cfs_rq)->curr);
-	}
-}
-
-static void
-set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
-	/* 'current' is not kept within the tree. */
-	if (se->on_rq) {
-		/*
-		 * Any task has to be enqueued before it get to execute on
-		 * a CPU. So account for the time it spent waiting on the
-		 * runqueue.
-		 */
-		update_stats_wait_end(cfs_rq, se);
-		__dequeue_entity(cfs_rq, se);
-	}
-
-	update_stats_curr_start(cfs_rq, se);
-	cfs_rq->curr = se;
-#ifdef CONFIG_SCHEDSTATS
-	/*
-	 * Track our maximum slice length, if the CPU's load is at
-	 * least twice that of our own weight (i.e. dont track it
-	 * when there are only lesser-weight tasks around):
-	 */
-	if (rq_of(cfs_rq)->load.weight >= 2*se->load.weight) {
-		se->statistics.slice_max = max(se->statistics.slice_max,
-			se->sum_exec_runtime - se->prev_sum_exec_runtime);
-	}
-#endif
-	se->prev_sum_exec_runtime = se->sum_exec_runtime;
-}
-
-static int
-wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
-
-static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
-{
-	struct sched_entity *se = __pick_next_entity(cfs_rq);
-	struct sched_entity *left = se;
-
-	if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1)
-		se = cfs_rq->next;
-
-	/*
-	 * Prefer last buddy, try to return the CPU to a preempted task.
-	 */
-	if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1)
-		se = cfs_rq->last;
-
-	clear_buddies(cfs_rq, se);
-
-	return se;
-}
-
-static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
-{
-	/*
-	 * If still on the runqueue then deactivate_task()
-	 * was not called and update_curr() has to be done:
-	 */
-	if (prev->on_rq)
-		update_curr(cfs_rq);
-
-	check_spread(cfs_rq, prev);
-	if (prev->on_rq) {
-		update_stats_wait_start(cfs_rq, prev);
-		/* Put 'current' back into the tree. */
-		__enqueue_entity(cfs_rq, prev);
-	}
-	cfs_rq->curr = NULL;
-}
-
-static void
-entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
-{
-	/*
-	 * Update run-time statistics of the 'current'.
-	 */
-	update_curr(cfs_rq);
-
-	/*
-	 * Update share accounting for long-running entities.
-	 */
-	update_entity_shares_tick(cfs_rq);
-
-#ifdef CONFIG_SCHED_HRTICK
-	/*
-	 * queued ticks are scheduled to match the slice, so don't bother
-	 * validating it and just reschedule.
-	 */
-	if (queued) {
-		resched_task(rq_of(cfs_rq)->curr);
-		return;
-	}
-	/*
-	 * don't let the period tick interfere with the hrtick preemption
-	 */
-	if (!sched_feat(DOUBLE_TICK) &&
-			hrtimer_active(&rq_of(cfs_rq)->hrtick_timer))
-		return;
-#endif
-
-	if (cfs_rq->nr_running > 1 || !sched_feat(WAKEUP_PREEMPT))
-		check_preempt_tick(cfs_rq, curr);
-}
-
-/**************************************************
- * CFS operations on tasks:
- */
-
-#ifdef CONFIG_SCHED_HRTICK
-static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
-{
-	struct sched_entity *se = &p->se;
-	struct cfs_rq *cfs_rq = cfs_rq_of(se);
-
-	WARN_ON(task_rq(p) != rq);
-
-	if (hrtick_enabled(rq) && cfs_rq->nr_running > 1) {
-		u64 slice = sched_slice(cfs_rq, se);
-		u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
-		s64 delta = slice - ran;
-
-		if (delta < 0) {
-			if (rq->curr == p)
-				resched_task(p);
-			return;
-		}
-
-		/*
-		 * Don't schedule slices shorter than 10000ns, that just
-		 * doesn't make sense. Rely on vruntime for fairness.
-		 */
-		if (rq->curr != p)
-			delta = max_t(s64, 10000LL, delta);
-
-		hrtick_start(rq, delta);
-	}
-}
-
-/*
- * called from enqueue/dequeue and updates the hrtick when the
- * current task is from our class and nr_running is low enough
- * to matter.
- */
-static void hrtick_update(struct rq *rq)
-{
-	struct task_struct *curr = rq->curr;
-
-	if (curr->sched_class != &fair_sched_class)
-		return;
-
-	if (cfs_rq_of(&curr->se)->nr_running < sched_nr_latency)
-		hrtick_start_fair(rq, curr);
-}
-#else /* !CONFIG_SCHED_HRTICK */
-static inline void
-hrtick_start_fair(struct rq *rq, struct task_struct *p)
-{
-}
-
-static inline void hrtick_update(struct rq *rq)
-{
-}
-#endif
-
-/*
- * The enqueue_task method is called before nr_running is
- * increased. Here we update the fair scheduling stats and
- * then put the task into the rbtree:
- */
-static void
-enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
-{
-	struct cfs_rq *cfs_rq;
-	struct sched_entity *se = &p->se;
-
-	for_each_sched_entity(se) {
-		if (se->on_rq)
-			break;
-		cfs_rq = cfs_rq_of(se);
-		enqueue_entity(cfs_rq, se, flags);
-		flags = ENQUEUE_WAKEUP;
-	}
-
-	for_each_sched_entity(se) {
-		struct cfs_rq *cfs_rq = cfs_rq_of(se);
-
-		update_cfs_load(cfs_rq, 0);
-		update_cfs_shares(cfs_rq, 0);
-	}
-
-	hrtick_update(rq);
-}
-
-/*
- * The dequeue_task method is called before nr_running is
- * decreased. We remove the task from the rbtree and
- * update the fair scheduling stats:
- */
-static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
-{
-	struct cfs_rq *cfs_rq;
-	struct sched_entity *se = &p->se;
-
-	for_each_sched_entity(se) {
-		cfs_rq = cfs_rq_of(se);
-		dequeue_entity(cfs_rq, se, flags);
-
-		/* Don't dequeue parent if it has other entities besides us */
-		if (cfs_rq->load.weight)
-			break;
-		flags |= DEQUEUE_SLEEP;
-	}
-
-	for_each_sched_entity(se) {
-		struct cfs_rq *cfs_rq = cfs_rq_of(se);
-
-		update_cfs_load(cfs_rq, 0);
-		update_cfs_shares(cfs_rq, 0);
-	}
-
-	hrtick_update(rq);
-}
-
-/*
- * sched_yield() support is very simple - we dequeue and enqueue.
- *
- * If compat_yield is turned on then we requeue to the end of the tree.
- */
-static void yield_task_fair(struct rq *rq)
-{
-	struct task_struct *curr = rq->curr;
-	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
-	struct sched_entity *rightmost, *se = &curr->se;
-
-	/*
-	 * Are we the only task in the tree?
-	 */
-	if (unlikely(cfs_rq->nr_running == 1))
-		return;
-
-	clear_buddies(cfs_rq, se);
-
-	if (likely(!sysctl_sched_compat_yield) && curr->policy != SCHED_BATCH) {
-		update_rq_clock(rq);
-		/*
-		 * Update run-time statistics of the 'current'.
-		 */
-		update_curr(cfs_rq);
-
-		return;
-	}
-	/*
-	 * Find the rightmost entry in the rbtree:
-	 */
-	rightmost = __pick_last_entity(cfs_rq);
-	/*
-	 * Already in the rightmost position?
-	 */
-	if (unlikely(!rightmost || entity_before(rightmost, se)))
-		return;
-
-	/*
-	 * Minimally necessary key value to be last in the tree:
-	 * Upon rescheduling, sched_class::put_prev_task() will place
-	 * 'current' within the tree based on its new key value.
-	 */
-	se->vruntime = rightmost->vruntime + 1;
-}
-
-#ifdef CONFIG_SMP
-
-static void task_waking_fair(struct rq *rq, struct task_struct *p)
-{
-	struct sched_entity *se = &p->se;
-	struct cfs_rq *cfs_rq = cfs_rq_of(se);
-
-	se->vruntime -= cfs_rq->min_vruntime;
-}
-
-#ifdef CONFIG_FAIR_GROUP_SCHED
-/*
- * effective_load() calculates the load change as seen from the root_task_group
- *
- * Adding load to a group doesn't make a group heavier, but can cause movement
- * of group shares between cpus. Assuming the shares were perfectly aligned one
- * can calculate the shift in shares.
- */
-static long effective_load(struct task_group *tg, int cpu, long wl, long wg)
-{
-	struct sched_entity *se = tg->se[cpu];
-
-	if (!tg->parent)
-		return wl;
-
-	for_each_sched_entity(se) {
-		long lw, w;
-
-		tg = se->my_q->tg;
-		w = se->my_q->load.weight;
-
-		/* use this cpu's instantaneous contribution */
-		lw = atomic_read(&tg->load_weight);
-		lw -= se->my_q->load_contribution;
-		lw += w + wg;
-
-		wl += w;
-
-		if (lw > 0 && wl < lw)
-			wl = (wl * tg->shares) / lw;
-		else
-			wl = tg->shares;
-
-		/* zero point is MIN_SHARES */
-		if (wl < MIN_SHARES)
-			wl = MIN_SHARES;
-		wl -= se->load.weight;
-		wg = 0;
-	}
-
-	return wl;
-}
-
-#else
-
-static inline unsigned long effective_load(struct task_group *tg, int cpu,
-		unsigned long wl, unsigned long wg)
-{
-	return wl;
-}
-
-#endif
-
-static int wake_affine(struct sched_domain *sd, struct task_struct *p, int sync)
-{
-	s64 this_load, load;
-	int idx, this_cpu, prev_cpu;
-	unsigned long tl_per_task;
-	struct task_group *tg;
-	unsigned long weight;
-	int balanced;
-
-	idx	  = sd->wake_idx;
-	this_cpu  = smp_processor_id();
-	prev_cpu  = task_cpu(p);
-	load	  = source_load(prev_cpu, idx);
-	this_load = target_load(this_cpu, idx);
-
-	/*
-	 * If sync wakeup then subtract the (maximum possible)
-	 * effect of the currently running task from the load
-	 * of the current CPU:
-	 */
-	rcu_read_lock();
-	if (sync) {
-		tg = task_group(current);
-		weight = current->se.load.weight;
-
-		this_load += effective_load(tg, this_cpu, -weight, -weight);
-		load += effective_load(tg, prev_cpu, 0, -weight);
-	}
-
-	tg = task_group(p);
-	weight = p->se.load.weight;
-
-	/*
-	 * In low-load situations, where prev_cpu is idle and this_cpu is idle
-	 * due to the sync cause above having dropped this_load to 0, we'll
-	 * always have an imbalance, but there's really nothing you can do
-	 * about that, so that's good too.
-	 *
-	 * Otherwise check if either cpus are near enough in load to allow this
-	 * task to be woken on this_cpu.
-	 */
-	if (this_load > 0) {
-		s64 this_eff_load, prev_eff_load;
-
-		this_eff_load = 100;
-		this_eff_load *= power_of(prev_cpu);
-		this_eff_load *= this_load +
-			effective_load(tg, this_cpu, weight, weight);
-
-		prev_eff_load = 100 + (sd->imbalance_pct - 100) / 2;
-		prev_eff_load *= power_of(this_cpu);
-		prev_eff_load *= load + effective_load(tg, prev_cpu, 0, weight);
-
-		balanced = this_eff_load <= prev_eff_load;
-	} else
-		balanced = true;
-	rcu_read_unlock();
-
-	/*
-	 * If the currently running task will sleep within
-	 * a reasonable amount of time then attract this newly
-	 * woken task:
-	 */
-	if (sync && balanced)
-		return 1;
-
-	schedstat_inc(p, se.statistics.nr_wakeups_affine_attempts);
-	tl_per_task = cpu_avg_load_per_task(this_cpu);
-
-	if (balanced ||
-	    (this_load <= load &&
-	     this_load + target_load(prev_cpu, idx) <= tl_per_task)) {
-		/*
-		 * This domain has SD_WAKE_AFFINE and
-		 * p is cache cold in this domain, and
-		 * there is no bad imbalance.
-		 */
-		schedstat_inc(sd, ttwu_move_affine);
-		schedstat_inc(p, se.statistics.nr_wakeups_affine);
-
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * find_idlest_group finds and returns the least busy CPU group within the
- * domain.
- */
-static struct sched_group *
-find_idlest_group(struct sched_domain *sd, struct task_struct *p,
-		  int this_cpu, int load_idx)
-{
-	struct sched_group *idlest = NULL, *group = sd->groups;
-	unsigned long min_load = ULONG_MAX, this_load = 0;
-	int imbalance = 100 + (sd->imbalance_pct-100)/2;
-
-	do {
-		unsigned long load, avg_load;
-		int local_group;
-		int i;
-
-		/* Skip over this group if it has no CPUs allowed */
-		if (!cpumask_intersects(sched_group_cpus(group),
-					&p->cpus_allowed))
-			continue;
-
-		local_group = cpumask_test_cpu(this_cpu,
-					       sched_group_cpus(group));
-
-		/* Tally up the load of all CPUs in the group */
-		avg_load = 0;
-
-		for_each_cpu(i, sched_group_cpus(group)) {
-			/* Bias balancing toward cpus of our domain */
-			if (local_group)
-				load = source_load(i, load_idx);
-			else
-				load = target_load(i, load_idx);
-
-			avg_load += load;
-		}
-
-		/* Adjust by relative CPU power of the group */
-		avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
-
-		if (local_group) {
-			this_load = avg_load;
-		} else if (avg_load < min_load) {
-			min_load = avg_load;
-			idlest = group;
-		}
-	} while (group = group->next, group != sd->groups);
-
-	if (!idlest || 100*this_load < imbalance*min_load)
-		return NULL;
-	return idlest;
-}
-
-/*
- * find_idlest_cpu - find the idlest cpu among the cpus in group.
- */
-static int
-find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
-{
-	unsigned long load, min_load = ULONG_MAX;
-	int idlest = -1;
-	int i;
-
-	/* Traverse only the allowed CPUs */
-	for_each_cpu_and(i, sched_group_cpus(group), &p->cpus_allowed) {
-		load = weighted_cpuload(i);
-
-		if (load < min_load || (load == min_load && i == this_cpu)) {
-			min_load = load;
-			idlest = i;
-		}
-	}
-
-	return idlest;
-}
-
-/*
- * Try and locate an idle CPU in the sched_domain.
- */
-static int select_idle_sibling(struct task_struct *p, int target)
-{
-	int cpu = smp_processor_id();
-	int prev_cpu = task_cpu(p);
-	struct sched_domain *sd;
-	int i;
-
-	/*
-	 * If the task is going to be woken-up on this cpu and if it is
-	 * already idle, then it is the right target.
-	 */
-	if (target == cpu && idle_cpu(cpu))
-		return cpu;
-
-	/*
-	 * If the task is going to be woken-up on the cpu where it previously
-	 * ran and if it is currently idle, then it the right target.
-	 */
-	if (target == prev_cpu && idle_cpu(prev_cpu))
-		return prev_cpu;
-
-	/*
-	 * Otherwise, iterate the domains and find an elegible idle cpu.
-	 */
-	for_each_domain(target, sd) {
-		if (!(sd->flags & SD_SHARE_PKG_RESOURCES))
-			break;
-
-		for_each_cpu_and(i, sched_domain_span(sd), &p->cpus_allowed) {
-			if (idle_cpu(i)) {
-				target = i;
-				break;
-			}
-		}
-
-		/*
-		 * Lets stop looking for an idle sibling when we reached
-		 * the domain that spans the current cpu and prev_cpu.
-		 */
-		if (cpumask_test_cpu(cpu, sched_domain_span(sd)) &&
-		    cpumask_test_cpu(prev_cpu, sched_domain_span(sd)))
-			break;
-	}
-
-	return target;
-}
-
-/*
- * sched_balance_self: balance the current task (running on cpu) in domains
- * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and
- * SD_BALANCE_EXEC.
- *
- * Balance, ie. select the least loaded group.
- *
- * Returns the target CPU number, or the same CPU if no balancing is needed.
- *
- * preempt must be disabled.
- */
-static int
-select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_flags)
-{
-	struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL;
-	int cpu = smp_processor_id();
-	int prev_cpu = task_cpu(p);
-	int new_cpu = cpu;
-	int want_affine = 0;
-	int want_sd = 1;
-	int sync = wake_flags & WF_SYNC;
-
-	if (sd_flag & SD_BALANCE_WAKE) {
-		if (cpumask_test_cpu(cpu, &p->cpus_allowed))
-			want_affine = 1;
-		new_cpu = prev_cpu;
-	}
-
-	for_each_domain(cpu, tmp) {
-		if (!(tmp->flags & SD_LOAD_BALANCE))
-			continue;
-
-		/*
-		 * If power savings logic is enabled for a domain, see if we
-		 * are not overloaded, if so, don't balance wider.
-		 */
-		if (tmp->flags & (SD_POWERSAVINGS_BALANCE|SD_PREFER_LOCAL)) {
-			unsigned long power = 0;
-			unsigned long nr_running = 0;
-			unsigned long capacity;
-			int i;
-
-			for_each_cpu(i, sched_domain_span(tmp)) {
-				power += power_of(i);
-				nr_running += cpu_rq(i)->cfs.nr_running;
-			}
-
-			capacity = DIV_ROUND_CLOSEST(power, SCHED_LOAD_SCALE);
-
-			if (tmp->flags & SD_POWERSAVINGS_BALANCE)
-				nr_running /= 2;
-
-			if (nr_running < capacity)
-				want_sd = 0;
-		}
-
-		/*
-		 * If both cpu and prev_cpu are part of this domain,
-		 * cpu is a valid SD_WAKE_AFFINE target.
-		 */
-		if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
-		    cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
-			affine_sd = tmp;
-			want_affine = 0;
-		}
-
-		if (!want_sd && !want_affine)
-			break;
+	do {
+		unsigned long load, avg_load;
+		int local_group;
+		int i;
 
-		if (!(tmp->flags & sd_flag))
+		/* Skip over this group if it has no CPUs allowed */
+		if (!cpumask_intersects(sched_group_cpus(group),
+					&p->cpus_allowed))
 			continue;
 
-		if (want_sd)
-			sd = tmp;
-	}
-
-	if (affine_sd) {
-		if (cpu == prev_cpu || wake_affine(affine_sd, p, sync))
-			return select_idle_sibling(p, cpu);
-		else
-			return select_idle_sibling(p, prev_cpu);
-	}
-
-	while (sd) {
-		int load_idx = sd->forkexec_idx;
-		struct sched_group *group;
-		int weight;
+		local_group = cpumask_test_cpu(this_cpu,
+					       sched_group_cpus(group));
 
-		if (!(sd->flags & sd_flag)) {
-			sd = sd->child;
-			continue;
-		}
+		/* Tally up the load of all CPUs in the group */
+		avg_load = 0;
 
-		if (sd_flag & SD_BALANCE_WAKE)
-			load_idx = sd->wake_idx;
+		for_each_cpu(i, sched_group_cpus(group)) {
+			/* Bias balancing toward cpus of our domain */
+			if (local_group)
+				load = source_load(i, load_idx);
+			else
+				load = target_load(i, load_idx);
 
-		group = find_idlest_group(sd, p, cpu, load_idx);
-		if (!group) {
-			sd = sd->child;
-			continue;
+			avg_load += load;
 		}
 
-		new_cpu = find_idlest_cpu(group, p, cpu);
-		if (new_cpu == -1 || new_cpu == cpu) {
-			/* Now try balancing at a lower domain level of cpu */
-			sd = sd->child;
-			continue;
-		}
+		/* Adjust by relative CPU power of the group */
+		avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
 
-		/* Now try balancing at a lower domain level of new_cpu */
-		cpu = new_cpu;
-		weight = sd->span_weight;
-		sd = NULL;
-		for_each_domain(cpu, tmp) {
-			if (weight <= tmp->span_weight)
-				break;
-			if (tmp->flags & sd_flag)
-				sd = tmp;
+		if (local_group) {
+			this_load = avg_load;
+		} else if (avg_load < min_load) {
+			min_load = avg_load;
+			idlest = group;
 		}
-		/* while loop will break here if sd == NULL */
-	}
-
-	return new_cpu;
-}
-#endif /* CONFIG_SMP */
-
-static unsigned long
-wakeup_gran(struct sched_entity *curr, struct sched_entity *se)
-{
-	unsigned long gran = sysctl_sched_wakeup_granularity;
-
-	/*
-	 * Since its curr running now, convert the gran from real-time
-	 * to virtual-time in his units.
-	 *
-	 * By using 'se' instead of 'curr' we penalize light tasks, so
-	 * they get preempted easier. That is, if 'se' < 'curr' then
-	 * the resulting gran will be larger, therefore penalizing the
-	 * lighter, if otoh 'se' > 'curr' then the resulting gran will
-	 * be smaller, again penalizing the lighter task.
-	 *
-	 * This is especially important for buddies when the leftmost
-	 * task is higher priority than the buddy.
-	 */
-	if (unlikely(se->load.weight != NICE_0_LOAD))
-		gran = calc_delta_fair(gran, se);
+	} while (group = group->next, group != sd->groups);
 
-	return gran;
+	if (!idlest || 100*this_load < imbalance*min_load)
+		return NULL;
+	return idlest;
 }
 
 /*
- * Should 'se' preempt 'curr'.
- *
- *             |s1
- *        |s2
- *   |s3
- *         g
- *      |<--->|c
- *
- *  w(c, s1) = -1
- *  w(c, s2) =  0
- *  w(c, s3) =  1
- *
+ * find_idlest_cpu - find the idlest cpu among the cpus in group.
  */
 static int
-wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
+find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
 {
-	s64 gran, vdiff = curr->vruntime - se->vruntime;
-
-	if (vdiff <= 0)
-		return -1;
-
-	gran = wakeup_gran(curr, se);
-	if (vdiff > gran)
-		return 1;
-
-	return 0;
-}
+	unsigned long load, min_load = ULONG_MAX;
+	int idlest = -1;
+	int i;
 
-static void set_last_buddy(struct sched_entity *se)
-{
-	if (likely(task_of(se)->policy != SCHED_IDLE)) {
-		for_each_sched_entity(se)
-			cfs_rq_of(se)->last = se;
-	}
-}
+	/* Traverse only the allowed CPUs */
+	for_each_cpu_and(i, sched_group_cpus(group), &p->cpus_allowed) {
+		load = weighted_cpuload(i);
 
-static void set_next_buddy(struct sched_entity *se)
-{
-	if (likely(task_of(se)->policy != SCHED_IDLE)) {
-		for_each_sched_entity(se)
-			cfs_rq_of(se)->next = se;
+		if (load < min_load || (load == min_load && i == this_cpu)) {
+			min_load = load;
+			idlest = i;
+		}
 	}
-}
-
-/*
- * Preempt the current task with a newly woken task if needed:
- */
-static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
-{
-	struct task_struct *curr = rq->curr;
-	struct sched_entity *se = &curr->se, *pse = &p->se;
-	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
-	int scale = cfs_rq->nr_running >= sched_nr_latency;
-
-	if (unlikely(se == pse))
-		return;
-
-	if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK))
-		set_next_buddy(pse);
-
-	/*
-	 * We can come here with TIF_NEED_RESCHED already set from new task
-	 * wake up path.
-	 */
-	if (test_tsk_need_resched(curr))
-		return;
-
-	/*
-	 * Batch and idle tasks do not preempt (their preemption is driven by
-	 * the tick):
-	 */
-	if (unlikely(p->policy != SCHED_NORMAL))
-		return;
-
-	/* Idle tasks are by definition preempted by everybody. */
-	if (unlikely(curr->policy == SCHED_IDLE))
-		goto preempt;
-
-	if (!sched_feat(WAKEUP_PREEMPT))
-		return;
-
-	update_curr(cfs_rq);
-	find_matching_se(&se, &pse);
-	BUG_ON(!pse);
-	if (wakeup_preempt_entity(se, pse) == 1)
-		goto preempt;
-
-	return;
-
-preempt:
-	resched_task(curr);
-	/*
-	 * Only set the backward buddy when the current task is still
-	 * on the rq. This can happen when a wakeup gets interleaved
-	 * with schedule on the ->pre_schedule() or idle_balance()
-	 * point, either of which can * drop the rq lock.
-	 *
-	 * Also, during early boot the idle thread is in the fair class,
-	 * for obvious reasons its a bad idea to schedule back to it.
-	 */
-	if (unlikely(!se->on_rq || curr == rq->idle))
-		return;
 
-	if (sched_feat(LAST_BUDDY) && scale && entity_is_task(se))
-		set_last_buddy(se);
-}
-
-static struct task_struct *pick_next_task_fair(struct rq *rq)
-{
-	struct task_struct *p;
-	struct cfs_rq *cfs_rq = &rq->cfs;
-	struct sched_entity *se;
-
-	if (!cfs_rq->nr_running)
-		return NULL;
-
-	do {
-		se = pick_next_entity(cfs_rq);
-		set_next_entity(cfs_rq, se);
-		cfs_rq = group_cfs_rq(se);
-	} while (cfs_rq);
-
-	p = task_of(se);
-	hrtick_start_fair(rq, p);
-
-	return p;
-}
-
-/*
- * Account for a descheduled task:
- */
-static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
-{
-	struct sched_entity *se = &prev->se;
-	struct cfs_rq *cfs_rq;
-
-	for_each_sched_entity(se) {
-		cfs_rq = cfs_rq_of(se);
-		put_prev_entity(cfs_rq, se);
-	}
+	return idlest;
 }
 
-#ifdef CONFIG_SMP
-/**************************************************
- * Fair scheduling class load-balancing methods:
- */
-
 /*
- * pull_task - move a task from a remote runqueue to the local runqueue.
- * Both runqueues must be locked.
+ * Try and locate an idle CPU in the sched_domain.
  */
-static void pull_task(struct rq *src_rq, struct task_struct *p,
-		      struct rq *this_rq, int this_cpu)
+static int select_idle_sibling(struct task_struct *p, int target)
 {
-	deactivate_task(src_rq, p, 0);
-	set_task_cpu(p, this_cpu);
-	activate_task(this_rq, p, 0);
-	check_preempt_curr(this_rq, p, 0);
-}
+	int cpu = smp_processor_id();
+	int prev_cpu = task_cpu(p);
+	struct sched_domain *sd;
+	int i;
 
-/*
- * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
- */
-static
-int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
-		     struct sched_domain *sd, enum cpu_idle_type idle,
-		     int *all_pinned)
-{
-	int tsk_cache_hot = 0;
 	/*
-	 * We do not migrate tasks that are:
-	 * 1) running (obviously), or
-	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
-	 * 3) are cache-hot on their current CPU.
+	 * If the task is going to be woken-up on this cpu and if it is
+	 * already idle, then it is the right target.
 	 */
-	if (!cpumask_test_cpu(this_cpu, &p->cpus_allowed)) {
-		schedstat_inc(p, se.statistics.nr_failed_migrations_affine);
-		return 0;
-	}
-	*all_pinned = 0;
-
-	if (task_running(rq, p)) {
-		schedstat_inc(p, se.statistics.nr_failed_migrations_running);
-		return 0;
-	}
+	if (target == cpu && idle_cpu(cpu))
+		return cpu;
 
 	/*
-	 * Aggressive migration if:
-	 * 1) task is cache cold, or
-	 * 2) too many balance attempts have failed.
+	 * If the task is going to be woken-up on the cpu where it previously
+	 * ran and if it is currently idle, then it the right target.
 	 */
+	if (target == prev_cpu && idle_cpu(prev_cpu))
+		return prev_cpu;
 
-	tsk_cache_hot = task_hot(p, rq->clock_task, sd);
-	if (!tsk_cache_hot ||
-		sd->nr_balance_failed > sd->cache_nice_tries) {
-#ifdef CONFIG_SCHEDSTATS
-		if (tsk_cache_hot) {
-			schedstat_inc(sd, lb_hot_gained[idle]);
-			schedstat_inc(p, se.statistics.nr_forced_migrations);
-		}
-#endif
-		return 1;
-	}
-
-	if (tsk_cache_hot) {
-		schedstat_inc(p, se.statistics.nr_failed_migrations_hot);
-		return 0;
-	}
-	return 1;
-}
-
-/*
- * move_one_task tries to move exactly one task from busiest to this_rq, as
- * part of active balancing operations within "domain".
- * Returns 1 if successful and 0 otherwise.
- *
- * Called with both runqueues locked.
- */
-static int
-move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest,
-	      struct sched_domain *sd, enum cpu_idle_type idle)
-{
-	struct task_struct *p, *n;
-	struct cfs_rq *cfs_rq;
-	int pinned = 0;
-
-	for_each_leaf_cfs_rq(busiest, cfs_rq) {
-		list_for_each_entry_safe(p, n, &cfs_rq->tasks, se.group_node) {
-
-			if (!can_migrate_task(p, busiest, this_cpu,
-						sd, idle, &pinned))
-				continue;
-
-			pull_task(busiest, p, this_rq, this_cpu);
-			/*
-			 * Right now, this is only the second place pull_task()
-			 * is called, so we can safely collect pull_task()
-			 * stats here rather than inside pull_task().
-			 */
-			schedstat_inc(sd, lb_gained[idle]);
-			return 1;
-		}
-	}
-
-	return 0;
-}
-
-static unsigned long
-balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
-	      unsigned long max_load_move, struct sched_domain *sd,
-	      enum cpu_idle_type idle, int *all_pinned,
-	      int *this_best_prio, struct cfs_rq *busiest_cfs_rq)
-{
-	int loops = 0, pulled = 0;
-	long rem_load_move = max_load_move;
-	struct task_struct *p, *n;
-
-	if (max_load_move == 0)
-		goto out;
-
-	list_for_each_entry_safe(p, n, &busiest_cfs_rq->tasks, se.group_node) {
-		if (loops++ > sysctl_sched_nr_migrate)
-			break;
-
-		if ((p->se.load.weight >> 1) > rem_load_move ||
-		    !can_migrate_task(p, busiest, this_cpu, sd, idle,
-				      all_pinned))
-			continue;
-
-		pull_task(busiest, p, this_rq, this_cpu);
-		pulled++;
-		rem_load_move -= p->se.load.weight;
-
-#ifdef CONFIG_PREEMPT
-		/*
-		 * NEWIDLE balancing is a source of latency, so preemptible
-		 * kernels will stop after the first task is pulled to minimize
-		 * the critical section.
-		 */
-		if (idle == CPU_NEWLY_IDLE)
+	/*
+	 * Otherwise, iterate the domains and find an elegible idle cpu.
+	 */
+	for_each_domain(target, sd) {
+		if (!(sd->flags & SD_SHARE_PKG_RESOURCES))
 			break;
-#endif
+
+		for_each_cpu_and(i, sched_domain_span(sd), &p->cpus_allowed) {
+			if (idle_cpu(i)) {
+				target = i;
+				break;
+			}
+		}
 
 		/*
-		 * We only want to steal up to the prescribed amount of
-		 * weighted load.
+		 * Lets stop looking for an idle sibling when we reached
+		 * the domain that spans the current cpu and prev_cpu.
 		 */
-		if (rem_load_move <= 0)
+		if (cpumask_test_cpu(cpu, sched_domain_span(sd)) &&
+		    cpumask_test_cpu(prev_cpu, sched_domain_span(sd)))
 			break;
-
-		if (p->prio < *this_best_prio)
-			*this_best_prio = p->prio;
 	}
-out:
-	/*
-	 * Right now, this is one of only two places pull_task() is called,
-	 * so we can safely collect pull_task() stats here rather than
-	 * inside pull_task().
-	 */
-	schedstat_add(sd, lb_gained[idle], pulled);
 
-	return max_load_move - rem_load_move;
+	return target;
 }
 
-#ifdef CONFIG_FAIR_GROUP_SCHED
 /*
- * update tg->load_weight by folding this cpu's load_avg
+ * sched_balance_self: balance the current task (running on cpu) in domains
+ * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and
+ * SD_BALANCE_EXEC.
+ *
+ * Balance, ie. select the least loaded group.
+ *
+ * Returns the target CPU number, or the same CPU if no balancing is needed.
+ *
+ * preempt must be disabled.
  */
-static int update_shares_cpu(struct task_group *tg, int cpu)
+static int
+select_task_rq_fair(struct rq *rq, struct task_struct *p, int sd_flag, int wake_flags)
 {
-	struct cfs_rq *cfs_rq;
-	unsigned long flags;
-	struct rq *rq;
+	struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL;
+	int cpu = smp_processor_id();
+	int prev_cpu = task_cpu(p);
+	int new_cpu = cpu;
+	int want_affine = 0;
+	int want_sd = 1;
+	int sync = wake_flags & WF_SYNC;
 
-	if (!tg->se[cpu])
-		return 0;
+	if (sd_flag & SD_BALANCE_WAKE) {
+		if (cpumask_test_cpu(cpu, &p->cpus_allowed))
+			want_affine = 1;
+		new_cpu = prev_cpu;
+	}
 
-	rq = cpu_rq(cpu);
-	cfs_rq = tg->cfs_rq[cpu];
+	for_each_domain(cpu, tmp) {
+		if (!(tmp->flags & SD_LOAD_BALANCE))
+			continue;
+
+		/*
+		 * If power savings logic is enabled for a domain, see if we
+		 * are not overloaded, if so, don't balance wider.
+		 */
+		if (tmp->flags & (SD_POWERSAVINGS_BALANCE|SD_PREFER_LOCAL)) {
+			unsigned long power = 0;
+			unsigned long nr_running = 0;
+			unsigned long capacity;
+			int i;
 
-	raw_spin_lock_irqsave(&rq->lock, flags);
+			for_each_cpu(i, sched_domain_span(tmp)) {
+				power += power_of(i);
+#ifdef CONFIG_SCHED_FAIR_CFS
+				nr_running += cpu_rq(i)->cfs.nr_running;
+#elif CONFIG_SCHED_FAIR_HTFS
+				nr_running += cpu_rq(i)->htfs_rqs.nr_running;
+#endif
+			}
 
-	update_rq_clock(rq);
-	update_cfs_load(cfs_rq, 1);
+			capacity = DIV_ROUND_CLOSEST(power, SCHED_LOAD_SCALE);
 
-	/*
-	 * We need to update shares after updating tg->load_weight in
-	 * order to adjust the weight of groups with long running tasks.
-	 */
-	update_cfs_shares(cfs_rq, 0);
+			if (tmp->flags & SD_POWERSAVINGS_BALANCE)
+				nr_running /= 2;
 
-	raw_spin_unlock_irqrestore(&rq->lock, flags);
+			if (nr_running < capacity)
+				want_sd = 0;
+		}
 
-	return 0;
-}
+		/*
+		 * If both cpu and prev_cpu are part of this domain,
+		 * cpu is a valid SD_WAKE_AFFINE target.
+		 */
+		if (want_affine && (tmp->flags & SD_WAKE_AFFINE) &&
+		    cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) {
+			affine_sd = tmp;
+			want_affine = 0;
+		}
 
-static void update_shares(int cpu)
-{
-	struct cfs_rq *cfs_rq;
-	struct rq *rq = cpu_rq(cpu);
+		if (!want_sd && !want_affine)
+			break;
 
-	rcu_read_lock();
-	for_each_leaf_cfs_rq(rq, cfs_rq)
-		update_shares_cpu(cfs_rq->tg, cpu);
-	rcu_read_unlock();
-}
+		if (!(tmp->flags & sd_flag))
+			continue;
 
-static unsigned long
-load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
-		  unsigned long max_load_move,
-		  struct sched_domain *sd, enum cpu_idle_type idle,
-		  int *all_pinned, int *this_best_prio)
-{
-	long rem_load_move = max_load_move;
-	int busiest_cpu = cpu_of(busiest);
-	struct task_group *tg;
+		if (want_sd)
+			sd = tmp;
+	}
 
-	rcu_read_lock();
-	update_h_load(busiest_cpu);
+	if (affine_sd) {
+		if (cpu == prev_cpu || wake_affine(affine_sd, p, sync))
+			return select_idle_sibling(p, cpu);
+		else
+			return select_idle_sibling(p, prev_cpu);
+	}
 
-	list_for_each_entry_rcu(tg, &task_groups, list) {
-		struct cfs_rq *busiest_cfs_rq = tg->cfs_rq[busiest_cpu];
-		unsigned long busiest_h_load = busiest_cfs_rq->h_load;
-		unsigned long busiest_weight = busiest_cfs_rq->load.weight;
-		u64 rem_load, moved_load;
+	while (sd) {
+		int load_idx = sd->forkexec_idx;
+		struct sched_group *group;
+		int weight;
 
-		/*
-		 * empty group
-		 */
-		if (!busiest_cfs_rq->task_weight)
+		if (!(sd->flags & sd_flag)) {
+			sd = sd->child;
 			continue;
+		}
 
-		rem_load = (u64)rem_load_move * busiest_weight;
-		rem_load = div_u64(rem_load, busiest_h_load + 1);
-
-		moved_load = balance_tasks(this_rq, this_cpu, busiest,
-				rem_load, sd, idle, all_pinned, this_best_prio,
-				busiest_cfs_rq);
+		if (sd_flag & SD_BALANCE_WAKE)
+			load_idx = sd->wake_idx;
 
-		if (!moved_load)
+		group = find_idlest_group(sd, p, cpu, load_idx);
+		if (!group) {
+			sd = sd->child;
 			continue;
+		}
 
-		moved_load *= busiest_h_load;
-		moved_load = div_u64(moved_load, busiest_weight + 1);
+		new_cpu = find_idlest_cpu(group, p, cpu);
+		if (new_cpu == -1 || new_cpu == cpu) {
+			/* Now try balancing at a lower domain level of cpu */
+			sd = sd->child;
+			continue;
+		}
 
-		rem_load_move -= moved_load;
-		if (rem_load_move < 0)
-			break;
+		/* Now try balancing at a lower domain level of new_cpu */
+		cpu = new_cpu;
+		weight = sd->span_weight;
+		sd = NULL;
+		for_each_domain(cpu, tmp) {
+			if (weight <= tmp->span_weight)
+				break;
+			if (tmp->flags & sd_flag)
+				sd = tmp;
+		}
+		/* while loop will break here if sd == NULL */
 	}
-	rcu_read_unlock();
 
-	return max_load_move - rem_load_move;
-}
-#else
-static inline void update_shares(int cpu)
-{
+	return new_cpu;
 }
 
-static unsigned long
-load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
-		  unsigned long max_load_move,
-		  struct sched_domain *sd, enum cpu_idle_type idle,
-		  int *all_pinned, int *this_best_prio)
-{
-	return balance_tasks(this_rq, this_cpu, busiest,
-			max_load_move, sd, idle, all_pinned,
-			this_best_prio, &busiest->cfs);
-}
-#endif
+
 
 /*
  * move_tasks tries to move up to max_load_move weighted load from busiest to
@@ -2295,15 +593,6 @@ struct sg_lb_stats {
 };
 
 /**
- * group_first_cpu - Returns the first cpu in the cpumask of a sched_group.
- * @group: The group whose first cpu is to be returned.
- */
-static inline unsigned int group_first_cpu(struct sched_group *group)
-{
-	return cpumask_first(sched_group_cpus(group));
-}
-
-/**
  * get_sd_load_idx - Obtain the load index for a given sched domain.
  * @sd: The sched_domain whose load_idx is to be obtained.
  * @idle: The Idle status of the CPU for whose sd load_icx is obtained.
@@ -4015,196 +2304,3 @@ static inline void idle_balance(int cpu, struct rq *rq)
 
 #endif /* CONFIG_SMP */
 
-/*
- * scheduler tick hitting a task of our scheduling class:
- */
-static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
-{
-	struct cfs_rq *cfs_rq;
-	struct sched_entity *se = &curr->se;
-
-	for_each_sched_entity(se) {
-		cfs_rq = cfs_rq_of(se);
-		entity_tick(cfs_rq, se, queued);
-	}
-}
-
-/*
- * called on fork with the child task as argument from the parent's context
- *  - child not yet on the tasklist
- *  - preemption disabled
- */
-static void task_fork_fair(struct task_struct *p)
-{
-	struct cfs_rq *cfs_rq = task_cfs_rq(current);
-	struct sched_entity *se = &p->se, *curr = cfs_rq->curr;
-	int this_cpu = smp_processor_id();
-	struct rq *rq = this_rq();
-	unsigned long flags;
-
-	raw_spin_lock_irqsave(&rq->lock, flags);
-
-	update_rq_clock(rq);
-
-	if (unlikely(task_cpu(p) != this_cpu)) {
-		rcu_read_lock();
-		__set_task_cpu(p, this_cpu);
-		rcu_read_unlock();
-	}
-
-	update_curr(cfs_rq);
-
-	if (curr)
-		se->vruntime = curr->vruntime;
-	place_entity(cfs_rq, se, 1);
-
-	if (sysctl_sched_child_runs_first && curr && entity_before(curr, se)) {
-		/*
-		 * Upon rescheduling, sched_class::put_prev_task() will place
-		 * 'current' within the tree based on its new key value.
-		 */
-		swap(curr->vruntime, se->vruntime);
-		resched_task(rq->curr);
-	}
-
-	se->vruntime -= cfs_rq->min_vruntime;
-
-	raw_spin_unlock_irqrestore(&rq->lock, flags);
-}
-
-/*
- * Priority of the task has changed. Check to see if we preempt
- * the current task.
- */
-static void prio_changed_fair(struct rq *rq, struct task_struct *p,
-			      int oldprio, int running)
-{
-	/*
-	 * Reschedule if we are currently running on this runqueue and
-	 * our priority decreased, or if we are not currently running on
-	 * this runqueue and our priority is higher than the current's
-	 */
-	if (running) {
-		if (p->prio > oldprio)
-			resched_task(rq->curr);
-	} else
-		check_preempt_curr(rq, p, 0);
-}
-
-/*
- * We switched to the sched_fair class.
- */
-static void switched_to_fair(struct rq *rq, struct task_struct *p,
-			     int running)
-{
-	/*
-	 * We were most likely switched from sched_rt, so
-	 * kick off the schedule if running, otherwise just see
-	 * if we can still preempt the current task.
-	 */
-	if (running)
-		resched_task(rq->curr);
-	else
-		check_preempt_curr(rq, p, 0);
-}
-
-/* Account for a task changing its policy or group.
- *
- * This routine is mostly called to set cfs_rq->curr field when a task
- * migrates between groups/classes.
- */
-static void set_curr_task_fair(struct rq *rq)
-{
-	struct sched_entity *se = &rq->curr->se;
-
-	for_each_sched_entity(se)
-		set_next_entity(cfs_rq_of(se), se);
-}
-
-#ifdef CONFIG_FAIR_GROUP_SCHED
-static void task_move_group_fair(struct task_struct *p, int on_rq)
-{
-	/*
-	 * If the task was not on the rq at the time of this cgroup movement
-	 * it must have been asleep, sleeping tasks keep their ->vruntime
-	 * absolute on their old rq until wakeup (needed for the fair sleeper
-	 * bonus in place_entity()).
-	 *
-	 * If it was on the rq, we've just 'preempted' it, which does convert
-	 * ->vruntime to a relative base.
-	 *
-	 * Make sure both cases convert their relative position when migrating
-	 * to another cgroup's rq. This does somewhat interfere with the
-	 * fair sleeper stuff for the first placement, but who cares.
-	 */
-	if (!on_rq)
-		p->se.vruntime -= cfs_rq_of(&p->se)->min_vruntime;
-	set_task_rq(p, task_cpu(p));
-	if (!on_rq)
-		p->se.vruntime += cfs_rq_of(&p->se)->min_vruntime;
-}
-#endif
-
-static unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task)
-{
-	struct sched_entity *se = &task->se;
-	unsigned int rr_interval = 0;
-
-	/*
-	 * Time slice is 0 for SCHED_OTHER tasks that are on an otherwise
-	 * idle runqueue:
-	 */
-	if (rq->cfs.load.weight)
-		rr_interval = NS_TO_JIFFIES(sched_slice(&rq->cfs, se));
-
-	return rr_interval;
-}
-
-/*
- * All the scheduling class methods:
- */
-static const struct sched_class fair_sched_class = {
-	.next			= &idle_sched_class,
-	.enqueue_task		= enqueue_task_fair,
-	.dequeue_task		= dequeue_task_fair,
-	.yield_task		= yield_task_fair,
-
-	.check_preempt_curr	= check_preempt_wakeup,
-
-	.pick_next_task		= pick_next_task_fair,
-	.put_prev_task		= put_prev_task_fair,
-
-#ifdef CONFIG_SMP
-	.select_task_rq		= select_task_rq_fair,
-
-	.rq_online		= rq_online_fair,
-	.rq_offline		= rq_offline_fair,
-
-	.task_waking		= task_waking_fair,
-#endif
-
-	.set_curr_task          = set_curr_task_fair,
-	.task_tick		= task_tick_fair,
-	.task_fork		= task_fork_fair,
-
-	.prio_changed		= prio_changed_fair,
-	.switched_to		= switched_to_fair,
-
-	.get_rr_interval	= get_rr_interval_fair,
-
-#ifdef CONFIG_FAIR_GROUP_SCHED
-	.task_move_group	= task_move_group_fair,
-#endif
-};
-
-#ifdef CONFIG_SCHED_DEBUG
-static void print_cfs_stats(struct seq_file *m, int cpu)
-{
-	struct cfs_rq *cfs_rq;
-
-	rcu_read_lock();
-	for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq)
-		print_cfs_rq(m, cpu, cfs_rq);
-	rcu_read_unlock();
-}
-#endif
diff --git a/kernel/sched_fair_cfs.c b/kernel/sched_fair_cfs.c
new file mode 100644
index 0000000..57da3fa
--- /dev/null
+++ b/kernel/sched_fair_cfs.c
@@ -0,0 +1,1991 @@
+/*
+ * Completely Fair Scheduling (CFS) Class (SCHED_NORMAL/SCHED_BATCH)
+ *
+ *  Copyright (C) 2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *
+ *  Interactivity improvements by Mike Galbraith
+ *  (C) 2007 Mike Galbraith <efault@gmx.de>
+ *
+ *  Various enhancements by Dmitry Adamushko.
+ *  (C) 2007 Dmitry Adamushko <dmitry.adamushko@gmail.com>
+ *
+ *  Group scheduling enhancements by Srivatsa Vaddagiri
+ *  Copyright IBM Corporation, 2007
+ *  Author: Srivatsa Vaddagiri <vatsa@linux.vnet.ibm.com>
+ *
+ *  Scaled math optimizations by Thomas Gleixner
+ *  Copyright (C) 2007, Thomas Gleixner <tglx@linutronix.de>
+ *
+ *  Adaptive scheduling granularity, math enhancements by Peter Zijlstra
+ *  Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ */
+
+#include <linux/latencytop.h>
+#include <linux/sched.h>
+
+/*
+ * Targeted preemption latency for CPU-bound tasks:
+ * (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds)
+ *
+ * NOTE: this latency value is not the same as the concept of
+ * 'timeslice length' - timeslices in CFS are of variable length
+ * and have no persistent notion like in traditional, time-slice
+ * based scheduling concepts.
+ *
+ * (to see the precise effective timeslice length of your workload,
+ *  run vmstat and monitor the context-switches (cs) field)
+ */
+unsigned int sysctl_sched_latency = 6000000ULL;
+unsigned int normalized_sysctl_sched_latency = 6000000ULL;
+
+/*
+ * The initial- and re-scaling of tunables is configurable
+ * (default SCHED_TUNABLESCALING_LOG = *(1+ilog(ncpus))
+ *
+ * Options are:
+ * SCHED_TUNABLESCALING_NONE - unscaled, always *1
+ * SCHED_TUNABLESCALING_LOG - scaled logarithmical, *1+ilog(ncpus)
+ * SCHED_TUNABLESCALING_LINEAR - scaled linear, *ncpus
+ */
+enum sched_tunable_scaling sysctl_sched_tunable_scaling
+	= SCHED_TUNABLESCALING_LOG;
+
+/*
+ * Minimal preemption granularity for CPU-bound tasks:
+ * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds)
+ */
+unsigned int sysctl_sched_min_granularity = 750000ULL;
+unsigned int normalized_sysctl_sched_min_granularity = 750000ULL;
+
+/*
+ * is kept at sysctl_sched_latency / sysctl_sched_min_granularity
+ */
+static unsigned int sched_nr_latency = 8;
+
+/*
+ * After fork, child runs first. If set to 0 (default) then
+ * parent will (try to) run first.
+ */
+unsigned int sysctl_sched_child_runs_first __read_mostly;
+
+/*
+ * sys_sched_yield() compat mode
+ *
+ * This option switches the agressive yield implementation of the
+ * old scheduler back on.
+ */
+unsigned int __read_mostly sysctl_sched_compat_yield;
+
+/*
+ * SCHED_OTHER wake-up granularity.
+ * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds)
+ *
+ * This option delays the preemption effects of decoupled workloads
+ * and reduces their over-scheduling. Synchronous workloads will still
+ * have immediate wakeup/sleep latencies.
+ */
+unsigned int sysctl_sched_wakeup_granularity = 1000000UL;
+unsigned int normalized_sysctl_sched_wakeup_granularity = 1000000UL;
+
+
+/*
+ * The exponential sliding  window over which load is averaged for shares
+ * distribution.
+ * (default: 10msec)
+ */
+unsigned int __read_mostly sysctl_sched_shares_window = 10000000UL;
+
+static const struct sched_class fair_sched_class;
+
+/**************************************************************
+ * CFS operations on generic schedulable entities:
+ */
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+/* cpu runqueue to which this cfs_rq is attached */
+static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
+{
+	return cfs_rq->rq;
+}
+
+static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
+{
+	return p->se.cfs_rq;
+}
+
+/* runqueue on which this entity is (to be) queued */
+static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
+{
+	return se->cfs_rq;
+}
+
+/* runqueue "owned" by this group */
+static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
+{
+	return grp->my_q;
+}
+
+/* Given a group's cfs_rq on one cpu, return its corresponding cfs_rq on
+ * another cpu ('this_cpu')
+ */
+static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
+{
+	return cfs_rq->tg->cfs_rq[this_cpu];
+}
+
+static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
+{
+	if (!cfs_rq->on_list) {
+		/*
+		 * Ensure we either appear before our parent (if already
+		 * enqueued) or force our parent to appear after us when it is
+		 * enqueued.  The fact that we always enqueue bottom-up
+		 * reduces this to two cases.
+		 */
+		if (cfs_rq->tg->parent &&
+		    cfs_rq->tg->parent->cfs_rq[cpu_of(rq_of(cfs_rq))]->on_list) {
+			list_add_rcu(&cfs_rq->leaf_cfs_rq_list,
+				&rq_of(cfs_rq)->leaf_cfs_rq_list);
+		} else {
+			list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list,
+				&rq_of(cfs_rq)->leaf_cfs_rq_list);
+		}
+
+		cfs_rq->on_list = 1;
+	}
+}
+
+static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
+{
+	if (cfs_rq->on_list) {
+		list_del_rcu(&cfs_rq->leaf_cfs_rq_list);
+		cfs_rq->on_list = 0;
+	}
+}
+
+/* Iterate thr' all leaf cfs_rq's on a runqueue */
+#define for_each_leaf_cfs_rq(rq, cfs_rq) \
+	list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list)
+
+/* Do the two (enqueued) entities belong to the same group ? */
+static inline int
+is_same_group(struct sched_entity *se, struct sched_entity *pse)
+{
+	if (se->cfs_rq == pse->cfs_rq)
+		return 1;
+
+	return 0;
+}
+
+static void
+find_matching_se(struct sched_entity **se, struct sched_entity **pse)
+{
+	int se_depth, pse_depth;
+
+	/*
+	 * preemption test can be made between sibling entities who are in the
+	 * same cfs_rq i.e who have a common parent. Walk up the hierarchy of
+	 * both tasks until we find their ancestors who are siblings of common
+	 * parent.
+	 */
+
+	/* First walk up until both entities are at same depth */
+	se_depth = depth_se(*se);
+	pse_depth = depth_se(*pse);
+
+	while (se_depth > pse_depth) {
+		se_depth--;
+		*se = parent_entity(*se);
+	}
+
+	while (pse_depth > se_depth) {
+		pse_depth--;
+		*pse = parent_entity(*pse);
+	}
+
+	while (!is_same_group(*se, *pse)) {
+		*se = parent_entity(*se);
+		*pse = parent_entity(*pse);
+	}
+}
+
+#else	/* !CONFIG_FAIR_GROUP_SCHED */
+
+static inline struct rq *rq_of(struct cfs_rq *cfs_rq)
+{
+	return container_of(cfs_rq, struct rq, cfs);
+}
+
+static inline struct cfs_rq *task_cfs_rq(struct task_struct *p)
+{
+	return &task_rq(p)->cfs;
+}
+
+static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
+{
+	struct task_struct *p = task_of(se);
+	struct rq *rq = task_rq(p);
+
+	return &rq->cfs;
+}
+
+/* runqueue "owned" by this group */
+static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp)
+{
+	return NULL;
+}
+
+static inline struct cfs_rq *cpu_cfs_rq(struct cfs_rq *cfs_rq, int this_cpu)
+{
+	return &cpu_rq(this_cpu)->cfs;
+}
+
+static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq)
+{
+}
+
+static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq)
+{
+}
+
+#define for_each_leaf_cfs_rq(rq, cfs_rq) \
+		for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL)
+
+static inline int
+is_same_group(struct sched_entity *se, struct sched_entity *pse)
+{
+	return 1;
+}
+
+static inline struct sched_entity *parent_entity(struct sched_entity *se)
+{
+	return NULL;
+}
+
+static inline void
+find_matching_se(struct sched_entity **se, struct sched_entity **pse)
+{
+}
+
+#endif	/* CONFIG_FAIR_GROUP_SCHED */
+
+
+/**************************************************************
+ * Scheduling class tree data structure manipulation methods:
+ */
+
+static inline u64 max_vruntime(u64 min_vruntime, u64 vruntime)
+{
+	s64 delta = (s64)(vruntime - min_vruntime);
+	if (delta > 0)
+		min_vruntime = vruntime;
+
+	return min_vruntime;
+}
+
+static inline u64 min_vruntime(u64 min_vruntime, u64 vruntime)
+{
+	s64 delta = (s64)(vruntime - min_vruntime);
+	if (delta < 0)
+		min_vruntime = vruntime;
+
+	return min_vruntime;
+}
+
+static inline int entity_before(struct sched_entity *a,
+				struct sched_entity *b)
+{
+	return (s64)(a->vruntime - b->vruntime) < 0;
+}
+
+static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	return se->vruntime - cfs_rq->min_vruntime;
+}
+
+static void update_min_vruntime(struct cfs_rq *cfs_rq)
+{
+	u64 vruntime = cfs_rq->min_vruntime;
+
+	if (cfs_rq->curr)
+		vruntime = cfs_rq->curr->vruntime;
+
+	if (cfs_rq->rb_leftmost) {
+		struct sched_entity *se = rb_entry(cfs_rq->rb_leftmost,
+						   struct sched_entity,
+						   run_node);
+
+		if (!cfs_rq->curr)
+			vruntime = se->vruntime;
+		else
+			vruntime = min_vruntime(vruntime, se->vruntime);
+	}
+
+	cfs_rq->min_vruntime = max_vruntime(cfs_rq->min_vruntime, vruntime);
+}
+
+/*
+ * Enqueue an entity into the rb-tree:
+ */
+static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	struct rb_node **link = &cfs_rq->tasks_timeline.rb_node;
+	struct rb_node *parent = NULL;
+	struct sched_entity *entry;
+	s64 key = entity_key(cfs_rq, se);
+	int leftmost = 1;
+
+	/*
+	 * Find the right place in the rbtree:
+	 */
+	while (*link) {
+		parent = *link;
+		entry = rb_entry(parent, struct sched_entity, run_node);
+		/*
+		 * We dont care about collisions. Nodes with
+		 * the same key stay together.
+		 */
+		if (key < entity_key(cfs_rq, entry)) {
+			link = &parent->rb_left;
+		} else {
+			link = &parent->rb_right;
+			leftmost = 0;
+		}
+	}
+
+	/*
+	 * Maintain a cache of leftmost tree entries (it is frequently
+	 * used):
+	 */
+	if (leftmost)
+		cfs_rq->rb_leftmost = &se->run_node;
+
+	rb_link_node(&se->run_node, parent, link);
+	rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline);
+}
+
+static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	if (cfs_rq->rb_leftmost == &se->run_node) {
+		struct rb_node *next_node;
+
+		next_node = rb_next(&se->run_node);
+		cfs_rq->rb_leftmost = next_node;
+	}
+
+	rb_erase(&se->run_node, &cfs_rq->tasks_timeline);
+}
+
+static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
+{
+	struct rb_node *left = cfs_rq->rb_leftmost;
+
+	if (!left)
+		return NULL;
+
+	return rb_entry(left, struct sched_entity, run_node);
+}
+
+static struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq)
+{
+	struct rb_node *last = rb_last(&cfs_rq->tasks_timeline);
+
+	if (!last)
+		return NULL;
+
+	return rb_entry(last, struct sched_entity, run_node);
+}
+
+/**************************************************************
+ * Scheduling class statistics methods:
+ */
+
+#ifdef CONFIG_SCHED_DEBUG
+int sched_proc_update_handler(struct ctl_table *table, int write,
+		void __user *buffer, size_t *lenp,
+		loff_t *ppos)
+{
+	int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+	int factor = get_update_sysctl_factor();
+
+	if (ret || !write)
+		return ret;
+
+	sched_nr_latency = DIV_ROUND_UP(sysctl_sched_latency,
+					sysctl_sched_min_granularity);
+
+#define WRT_SYSCTL(name) \
+	(normalized_sysctl_##name = sysctl_##name / (factor))
+	WRT_SYSCTL(sched_min_granularity);
+	WRT_SYSCTL(sched_latency);
+	WRT_SYSCTL(sched_wakeup_granularity);
+#undef WRT_SYSCTL
+
+	return 0;
+}
+#endif
+
+/*
+ * delta /= w
+ */
+static inline unsigned long
+calc_delta_fair(unsigned long delta, struct sched_entity *se)
+{
+	if (unlikely(se->load.weight != NICE_0_LOAD))
+		delta = calc_delta_mine(delta, NICE_0_LOAD, &se->load);
+
+	return delta;
+}
+
+/*
+ * The idea is to set a period in which each task runs once.
+ *
+ * When there are too many tasks (sysctl_sched_nr_latency) we have to stretch
+ * this period because otherwise the slices get too small.
+ *
+ * p = (nr <= nl) ? l : l*nr/nl
+ */
+static u64 __sched_period(unsigned long nr_running)
+{
+	u64 period = sysctl_sched_latency;
+	unsigned long nr_latency = sched_nr_latency;
+
+	if (unlikely(nr_running > nr_latency)) {
+		period = sysctl_sched_min_granularity;
+		period *= nr_running;
+	}
+
+	return period;
+}
+
+/*
+ * We calculate the wall-time slice from the period by taking a part
+ * proportional to the weight.
+ *
+ * s = p*P[w/rw]
+ */
+static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	u64 slice = __sched_period(cfs_rq->nr_running + !se->on_rq);
+
+	for_each_sched_entity(se) {
+		struct load_weight *load;
+		struct load_weight lw;
+
+		cfs_rq = cfs_rq_of(se);
+		load = &cfs_rq->load;
+
+		if (unlikely(!se->on_rq)) {
+			lw = cfs_rq->load;
+
+			update_load_add(&lw, se->load.weight);
+			load = &lw;
+		}
+		slice = calc_delta_mine(slice, se->load.weight, load);
+	}
+	return slice;
+}
+
+/*
+ * We calculate the vruntime slice of a to be inserted task
+ *
+ * vs = s/w
+ */
+static u64 sched_vslice(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	return calc_delta_fair(sched_slice(cfs_rq, se), se);
+}
+
+static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update);
+static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta);
+
+/*
+ * Update the current task's runtime statistics. Skip current tasks that
+ * are not in our scheduling class.
+ */
+static inline void
+__update_curr(struct cfs_rq *cfs_rq, struct sched_entity *curr,
+	      unsigned long delta_exec)
+{
+	unsigned long delta_exec_weighted;
+
+	schedstat_set(curr->statistics.exec_max,
+		      max((u64)delta_exec, curr->statistics.exec_max));
+
+	curr->sum_exec_runtime += delta_exec;
+	schedstat_add(cfs_rq, exec_clock, delta_exec);
+	delta_exec_weighted = calc_delta_fair(delta_exec, curr);
+
+	curr->vruntime += delta_exec_weighted;
+	update_min_vruntime(cfs_rq);
+
+#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
+	cfs_rq->load_unacc_exec_time += delta_exec;
+#endif
+}
+
+static void update_curr(struct cfs_rq *cfs_rq)
+{
+	struct sched_entity *curr = cfs_rq->curr;
+	u64 now = rq_of(cfs_rq)->clock_task;
+	unsigned long delta_exec;
+
+	if (unlikely(!curr))
+		return;
+
+	/*
+	 * Get the amount of time the current task was running
+	 * since the last time we changed load (this cannot
+	 * overflow on 32 bits):
+	 */
+	delta_exec = (unsigned long)(now - curr->exec_start);
+	if (!delta_exec)
+		return;
+
+	__update_curr(cfs_rq, curr, delta_exec);
+	curr->exec_start = now;
+
+	if (entity_is_task(curr)) {
+		struct task_struct *curtask = task_of(curr);
+
+		trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime);
+		cpuacct_charge(curtask, delta_exec);
+		account_group_exec_runtime(curtask, delta_exec);
+	}
+}
+
+static inline void
+update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	schedstat_set(se->statistics.wait_start, rq_of(cfs_rq)->clock);
+}
+
+/*
+ * Task is being enqueued - update stats:
+ */
+static void update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	/*
+	 * Are we enqueueing a waiting task? (for current tasks
+	 * a dequeue/enqueue event is a NOP)
+	 */
+	if (se != cfs_rq->curr)
+		update_stats_wait_start(cfs_rq, se);
+}
+
+static void
+update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	schedstat_set(se->statistics.wait_max, max(se->statistics.wait_max,
+			rq_of(cfs_rq)->clock - se->statistics.wait_start));
+	schedstat_set(se->statistics.wait_count, se->statistics.wait_count + 1);
+	schedstat_set(se->statistics.wait_sum, se->statistics.wait_sum +
+			rq_of(cfs_rq)->clock - se->statistics.wait_start);
+#ifdef CONFIG_SCHEDSTATS
+	if (entity_is_task(se)) {
+		trace_sched_stat_wait(task_of(se),
+			rq_of(cfs_rq)->clock - se->statistics.wait_start);
+	}
+#endif
+	schedstat_set(se->statistics.wait_start, 0);
+}
+
+static inline void
+update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	/*
+	 * Mark the end of the wait period if dequeueing a
+	 * waiting task:
+	 */
+	if (se != cfs_rq->curr)
+		update_stats_wait_end(cfs_rq, se);
+}
+
+/*
+ * We are picking a new current task - update its stats:
+ */
+static inline void
+update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	/*
+	 * We are starting a new run period:
+	 */
+	se->exec_start = rq_of(cfs_rq)->clock_task;
+}
+
+/**************************************************
+ * Scheduling class queueing methods:
+ */
+
+#if defined CONFIG_SMP && defined CONFIG_FAIR_GROUP_SCHED
+static void
+add_cfs_task_weight(struct cfs_rq *cfs_rq, unsigned long weight)
+{
+	cfs_rq->task_weight += weight;
+}
+#else
+static inline void
+add_cfs_task_weight(struct cfs_rq *cfs_rq, unsigned long weight)
+{
+}
+#endif
+
+static void
+account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	update_load_add(&cfs_rq->load, se->load.weight);
+	if (!parent_entity(se))
+		inc_cpu_load(rq_of(cfs_rq), se->load.weight);
+	if (entity_is_task(se)) {
+		add_cfs_task_weight(cfs_rq, se->load.weight);
+		list_add(&se->group_node, &cfs_rq->tasks);
+	}
+	cfs_rq->nr_running++;
+}
+
+static void
+account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	update_load_sub(&cfs_rq->load, se->load.weight);
+	if (!parent_entity(se))
+		dec_cpu_load(rq_of(cfs_rq), se->load.weight);
+	if (entity_is_task(se)) {
+		add_cfs_task_weight(cfs_rq, -se->load.weight);
+		list_del_init(&se->group_node);
+	}
+	cfs_rq->nr_running--;
+}
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+# ifdef CONFIG_SMP
+static void update_cfs_rq_load_contribution(struct cfs_rq *cfs_rq,
+					    int global_update)
+{
+	struct task_group *tg = cfs_rq->tg;
+	long load_avg;
+
+	load_avg = div64_u64(cfs_rq->load_avg, cfs_rq->load_period+1);
+	load_avg -= cfs_rq->load_contribution;
+
+	if (global_update || abs(load_avg) > cfs_rq->load_contribution / 8) {
+		atomic_add(load_avg, &tg->load_weight);
+		cfs_rq->load_contribution += load_avg;
+	}
+}
+
+static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
+{
+	u64 period = sysctl_sched_shares_window;
+	u64 now, delta;
+	unsigned long load = cfs_rq->load.weight;
+
+	if (cfs_rq->tg == &root_task_group)
+		return;
+
+	now = rq_of(cfs_rq)->clock_task;
+	delta = now - cfs_rq->load_stamp;
+
+	/* truncate load history at 4 idle periods */
+	if (cfs_rq->load_stamp > cfs_rq->load_last &&
+	    now - cfs_rq->load_last > 4 * period) {
+		cfs_rq->load_period = 0;
+		cfs_rq->load_avg = 0;
+	}
+
+	cfs_rq->load_stamp = now;
+	cfs_rq->load_unacc_exec_time = 0;
+	cfs_rq->load_period += delta;
+	if (load) {
+		cfs_rq->load_last = now;
+		cfs_rq->load_avg += delta * load;
+	}
+
+	/* consider updating load contribution on each fold or truncate */
+	if (global_update || cfs_rq->load_period > period
+	    || !cfs_rq->load_period)
+		update_cfs_rq_load_contribution(cfs_rq, global_update);
+
+	while (cfs_rq->load_period > period) {
+		/*
+		 * Inline assembly required to prevent the compiler
+		 * optimising this loop into a divmod call.
+		 * See __iter_div_u64_rem() for another example of this.
+		 */
+		asm("" : "+rm" (cfs_rq->load_period));
+		cfs_rq->load_period /= 2;
+		cfs_rq->load_avg /= 2;
+	}
+
+	if (!cfs_rq->curr && !cfs_rq->nr_running && !cfs_rq->load_avg)
+		list_del_leaf_cfs_rq(cfs_rq);
+}
+
+static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
+				long weight_delta)
+{
+	long load_weight, load, shares;
+
+	load = cfs_rq->load.weight + weight_delta;
+
+	load_weight = atomic_read(&tg->load_weight);
+	load_weight -= cfs_rq->load_contribution;
+	load_weight += load;
+
+	shares = (tg->shares * load);
+	if (load_weight)
+		shares /= load_weight;
+
+	if (shares < MIN_SHARES)
+		shares = MIN_SHARES;
+	if (shares > tg->shares)
+		shares = tg->shares;
+
+	return shares;
+}
+
+static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
+{
+	if (cfs_rq->load_unacc_exec_time > sysctl_sched_shares_window) {
+		update_cfs_load(cfs_rq, 0);
+		update_cfs_shares(cfs_rq, 0);
+	}
+}
+# else /* CONFIG_SMP */
+static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
+{
+}
+
+static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg,
+				long weight_delta)
+{
+	return tg->shares;
+}
+
+static inline void update_entity_shares_tick(struct cfs_rq *cfs_rq)
+{
+}
+# endif /* CONFIG_SMP */
+static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se,
+			    unsigned long weight)
+{
+	if (se->on_rq) {
+		/* commit outstanding execution time */
+		if (cfs_rq->curr == se)
+			update_curr(cfs_rq);
+		account_entity_dequeue(cfs_rq, se);
+	}
+
+	update_load_set(&se->load, weight);
+
+	if (se->on_rq)
+		account_entity_enqueue(cfs_rq, se);
+}
+
+static void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
+{
+	struct task_group *tg;
+	struct sched_entity *se;
+	long shares;
+
+	tg = cfs_rq->tg;
+	se = tg->se[cpu_of(rq_of(cfs_rq))];
+	if (!se)
+		return;
+#ifndef CONFIG_SMP
+	if (likely(se->load.weight == tg->shares))
+		return;
+#endif
+	shares = calc_cfs_shares(cfs_rq, tg, weight_delta);
+
+	reweight_entity(cfs_rq_of(se), se, shares);
+}
+#else /* CONFIG_FAIR_GROUP_SCHED */
+static void update_cfs_load(struct cfs_rq *cfs_rq, int global_update)
+{
+}
+
+static inline void update_cfs_shares(struct cfs_rq *cfs_rq, long weight_delta)
+{
+}
+
+static inline void update_entity_shares_tick(struct cfs_rq *cfs_rq)
+{
+}
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
+static void enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+#ifdef CONFIG_SCHEDSTATS
+	struct task_struct *tsk = NULL;
+
+	if (entity_is_task(se))
+		tsk = task_of(se);
+
+	if (se->statistics.sleep_start) {
+		u64 delta = rq_of(cfs_rq)->clock - se->statistics.sleep_start;
+
+		if ((s64)delta < 0)
+			delta = 0;
+
+		if (unlikely(delta > se->statistics.sleep_max))
+			se->statistics.sleep_max = delta;
+
+		se->statistics.sleep_start = 0;
+		se->statistics.sum_sleep_runtime += delta;
+
+		if (tsk) {
+			account_scheduler_latency(tsk, delta >> 10, 1);
+			trace_sched_stat_sleep(tsk, delta);
+		}
+	}
+	if (se->statistics.block_start) {
+		u64 delta = rq_of(cfs_rq)->clock - se->statistics.block_start;
+
+		if ((s64)delta < 0)
+			delta = 0;
+
+		if (unlikely(delta > se->statistics.block_max))
+			se->statistics.block_max = delta;
+
+		se->statistics.block_start = 0;
+		se->statistics.sum_sleep_runtime += delta;
+
+		if (tsk) {
+			if (tsk->in_iowait) {
+				se->statistics.iowait_sum += delta;
+				se->statistics.iowait_count++;
+				trace_sched_stat_iowait(tsk, delta);
+			}
+
+			/*
+			 * Blocking time is in units of nanosecs, so shift by
+			 * 20 to get a milliseconds-range estimation of the
+			 * amount of time that the task spent sleeping:
+			 */
+			if (unlikely(prof_on == SLEEP_PROFILING)) {
+				profile_hits(SLEEP_PROFILING,
+						(void *)get_wchan(tsk),
+						delta >> 20);
+			}
+			account_scheduler_latency(tsk, delta >> 10, 0);
+		}
+	}
+#endif
+}
+
+static void check_spread(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+#ifdef CONFIG_SCHED_DEBUG
+	s64 d = se->vruntime - cfs_rq->min_vruntime;
+
+	if (d < 0)
+		d = -d;
+
+	if (d > 3*sysctl_sched_latency)
+		schedstat_inc(cfs_rq, nr_spread_over);
+#endif
+}
+
+static void
+place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial)
+{
+	u64 vruntime = cfs_rq->min_vruntime;
+
+	/*
+	 * The 'current' period is already promised to the current tasks,
+	 * however the extra weight of the new task will slow them down a
+	 * little, place the new task so that it fits in the slot that
+	 * stays open at the end.
+	 */
+	if (initial && sched_feat(START_DEBIT))
+		vruntime += sched_vslice(cfs_rq, se);
+
+	/* sleeps up to a single latency don't count. */
+	if (!initial) {
+		unsigned long thresh = sysctl_sched_latency;
+
+		/*
+		 * Halve their sleep time's effect, to allow
+		 * for a gentler effect of sleepers:
+		 */
+		if (sched_feat(GENTLE_FAIR_SLEEPERS))
+			thresh >>= 1;
+
+		vruntime -= thresh;
+	}
+
+	/* ensure we never gain time by being placed backwards. */
+	vruntime = max_vruntime(se->vruntime, vruntime);
+
+	se->vruntime = vruntime;
+}
+
+static void
+enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
+{
+	/*
+	 * Update the normalized vruntime before updating min_vruntime
+	 * through callig update_curr().
+	 */
+	if (!(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_WAKING))
+		se->vruntime += cfs_rq->min_vruntime;
+
+	/*
+	 * Update run-time statistics of the 'current'.
+	 */
+	update_curr(cfs_rq);
+	update_cfs_load(cfs_rq, 0);
+	update_cfs_shares(cfs_rq, se->load.weight);
+	account_entity_enqueue(cfs_rq, se);
+
+	if (flags & ENQUEUE_WAKEUP) {
+		place_entity(cfs_rq, se, 0);
+		enqueue_sleeper(cfs_rq, se);
+	}
+
+	update_stats_enqueue(cfs_rq, se);
+	check_spread(cfs_rq, se);
+	if (se != cfs_rq->curr)
+		__enqueue_entity(cfs_rq, se);
+	se->on_rq = 1;
+
+	if (cfs_rq->nr_running == 1)
+		list_add_leaf_cfs_rq(cfs_rq);
+}
+
+static void __clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	if (!se || cfs_rq->last == se)
+		cfs_rq->last = NULL;
+
+	if (!se || cfs_rq->next == se)
+		cfs_rq->next = NULL;
+}
+
+static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	for_each_sched_entity(se)
+		__clear_buddies(cfs_rq_of(se), se);
+}
+
+static void
+dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
+{
+	/*
+	 * Update run-time statistics of the 'current'.
+	 */
+	update_curr(cfs_rq);
+
+	update_stats_dequeue(cfs_rq, se);
+	if (flags & DEQUEUE_SLEEP) {
+#ifdef CONFIG_SCHEDSTATS
+		if (entity_is_task(se)) {
+			struct task_struct *tsk = task_of(se);
+
+			if (tsk->state & TASK_INTERRUPTIBLE)
+				se->statistics.sleep_start = rq_of(cfs_rq)->clock;
+			if (tsk->state & TASK_UNINTERRUPTIBLE)
+				se->statistics.block_start = rq_of(cfs_rq)->clock;
+		}
+#endif
+	}
+
+	clear_buddies(cfs_rq, se);
+
+	if (se != cfs_rq->curr)
+		__dequeue_entity(cfs_rq, se);
+	se->on_rq = 0;
+	update_cfs_load(cfs_rq, 0);
+	account_entity_dequeue(cfs_rq, se);
+	update_min_vruntime(cfs_rq);
+	update_cfs_shares(cfs_rq, 0);
+
+	/*
+	 * Normalize the entity after updating the min_vruntime because the
+	 * update can refer to the ->curr item and we need to reflect this
+	 * movement in our normalized position.
+	 */
+	if (!(flags & DEQUEUE_SLEEP))
+		se->vruntime -= cfs_rq->min_vruntime;
+}
+
+/*
+ * Preempt the current task with a newly woken task if needed:
+ */
+static void
+check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
+{
+	unsigned long ideal_runtime, delta_exec;
+
+	ideal_runtime = sched_slice(cfs_rq, curr);
+	delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;
+	if (delta_exec > ideal_runtime) {
+		resched_task(rq_of(cfs_rq)->curr);
+		/*
+		 * The current task ran long enough, ensure it doesn't get
+		 * re-elected due to buddy favours.
+		 */
+		clear_buddies(cfs_rq, curr);
+		return;
+	}
+
+	/*
+	 * Ensure that a task that missed wakeup preemption by a
+	 * narrow margin doesn't have to wait for a full slice.
+	 * This also mitigates buddy induced latencies under load.
+	 */
+	if (!sched_feat(WAKEUP_PREEMPT))
+		return;
+
+	if (delta_exec < sysctl_sched_min_granularity)
+		return;
+
+	if (cfs_rq->nr_running > 1) {
+		struct sched_entity *se = __pick_next_entity(cfs_rq);
+		s64 delta = curr->vruntime - se->vruntime;
+
+		if (delta < 0)
+			return;
+
+		if (delta > ideal_runtime)
+			resched_task(rq_of(cfs_rq)->curr);
+	}
+}
+
+static void
+set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+	/* 'current' is not kept within the tree. */
+	if (se->on_rq) {
+		/*
+		 * Any task has to be enqueued before it get to execute on
+		 * a CPU. So account for the time it spent waiting on the
+		 * runqueue.
+		 */
+		update_stats_wait_end(cfs_rq, se);
+		__dequeue_entity(cfs_rq, se);
+	}
+
+	update_stats_curr_start(cfs_rq, se);
+	cfs_rq->curr = se;
+#ifdef CONFIG_SCHEDSTATS
+	/*
+	 * Track our maximum slice length, if the CPU's load is at
+	 * least twice that of our own weight (i.e. dont track it
+	 * when there are only lesser-weight tasks around):
+	 */
+	if (rq_of(cfs_rq)->load.weight >= 2*se->load.weight) {
+		se->statistics.slice_max = max(se->statistics.slice_max,
+			se->sum_exec_runtime - se->prev_sum_exec_runtime);
+	}
+#endif
+	se->prev_sum_exec_runtime = se->sum_exec_runtime;
+}
+
+static int
+wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se);
+
+static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
+{
+	struct sched_entity *se = __pick_next_entity(cfs_rq);
+	struct sched_entity *left = se;
+
+	if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1)
+		se = cfs_rq->next;
+
+	/*
+	 * Prefer last buddy, try to return the CPU to a preempted task.
+	 */
+	if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1)
+		se = cfs_rq->last;
+
+	clear_buddies(cfs_rq, se);
+
+	return se;
+}
+
+static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev)
+{
+	/*
+	 * If still on the runqueue then deactivate_task()
+	 * was not called and update_curr() has to be done:
+	 */
+	if (prev->on_rq)
+		update_curr(cfs_rq);
+
+	check_spread(cfs_rq, prev);
+	if (prev->on_rq) {
+		update_stats_wait_start(cfs_rq, prev);
+		/* Put 'current' back into the tree. */
+		__enqueue_entity(cfs_rq, prev);
+	}
+	cfs_rq->curr = NULL;
+}
+
+static void
+entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
+{
+	/*
+	 * Update run-time statistics of the 'current'.
+	 */
+	update_curr(cfs_rq);
+
+	/*
+	 * Update share accounting for long-running entities.
+	 */
+	update_entity_shares_tick(cfs_rq);
+
+#ifdef CONFIG_SCHED_HRTICK
+	/*
+	 * queued ticks are scheduled to match the slice, so don't bother
+	 * validating it and just reschedule.
+	 */
+	if (queued) {
+		resched_task(rq_of(cfs_rq)->curr);
+		return;
+	}
+	/*
+	 * don't let the period tick interfere with the hrtick preemption
+	 */
+	if (!sched_feat(DOUBLE_TICK) &&
+			hrtimer_active(&rq_of(cfs_rq)->hrtick_timer))
+		return;
+#endif
+
+	if (cfs_rq->nr_running > 1 || !sched_feat(WAKEUP_PREEMPT))
+		check_preempt_tick(cfs_rq, curr);
+}
+
+/**************************************************
+ * CFS operations on tasks:
+ */
+
+#ifdef CONFIG_SCHED_HRTICK
+static void hrtick_start_fair(struct rq *rq, struct task_struct *p)
+{
+	struct sched_entity *se = &p->se;
+	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+	WARN_ON(task_rq(p) != rq);
+
+	if (hrtick_enabled(rq) && cfs_rq->nr_running > 1) {
+		u64 slice = sched_slice(cfs_rq, se);
+		u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
+		s64 delta = slice - ran;
+
+		if (delta < 0) {
+			if (rq->curr == p)
+				resched_task(p);
+			return;
+		}
+
+		/*
+		 * Don't schedule slices shorter than 10000ns, that just
+		 * doesn't make sense. Rely on vruntime for fairness.
+		 */
+		if (rq->curr != p)
+			delta = max_t(s64, 10000LL, delta);
+
+		hrtick_start(rq, delta);
+	}
+}
+
+/*
+ * called from enqueue/dequeue and updates the hrtick when the
+ * current task is from our class and nr_running is low enough
+ * to matter.
+ */
+static void hrtick_update(struct rq *rq)
+{
+	struct task_struct *curr = rq->curr;
+
+	if (curr->sched_class != &fair_sched_class)
+		return;
+
+	if (cfs_rq_of(&curr->se)->nr_running < sched_nr_latency)
+		hrtick_start_fair(rq, curr);
+}
+#else /* !CONFIG_SCHED_HRTICK */
+static inline void
+hrtick_start_fair(struct rq *rq, struct task_struct *p)
+{
+}
+
+static inline void hrtick_update(struct rq *rq)
+{
+}
+#endif
+
+/*
+ * The enqueue_task method is called before nr_running is
+ * increased. Here we update the fair scheduling stats and
+ * then put the task into the rbtree:
+ */
+static void
+enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
+{
+	struct cfs_rq *cfs_rq;
+	struct sched_entity *se = &p->se;
+
+	for_each_sched_entity(se) {
+		if (se->on_rq)
+			break;
+		cfs_rq = cfs_rq_of(se);
+		enqueue_entity(cfs_rq, se, flags);
+		flags = ENQUEUE_WAKEUP;
+	}
+
+	for_each_sched_entity(se) {
+		struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+		update_cfs_load(cfs_rq, 0);
+		update_cfs_shares(cfs_rq, 0);
+	}
+
+	hrtick_update(rq);
+}
+
+/*
+ * The dequeue_task method is called before nr_running is
+ * decreased. We remove the task from the rbtree and
+ * update the fair scheduling stats:
+ */
+static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
+{
+	struct cfs_rq *cfs_rq;
+	struct sched_entity *se = &p->se;
+
+	for_each_sched_entity(se) {
+		cfs_rq = cfs_rq_of(se);
+		dequeue_entity(cfs_rq, se, flags);
+
+		/* Don't dequeue parent if it has other entities besides us */
+		if (cfs_rq->load.weight)
+			break;
+		flags |= DEQUEUE_SLEEP;
+	}
+
+	for_each_sched_entity(se) {
+		struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+		update_cfs_load(cfs_rq, 0);
+		update_cfs_shares(cfs_rq, 0);
+	}
+
+	hrtick_update(rq);
+}
+
+/*
+ * sched_yield() support is very simple - we dequeue and enqueue.
+ *
+ * If compat_yield is turned on then we requeue to the end of the tree.
+ */
+static void yield_task_fair(struct rq *rq)
+{
+	struct task_struct *curr = rq->curr;
+	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+	struct sched_entity *rightmost, *se = &curr->se;
+
+	/*
+	 * Are we the only task in the tree?
+	 */
+	if (unlikely(cfs_rq->nr_running == 1))
+		return;
+
+	clear_buddies(cfs_rq, se);
+
+	if (likely(!sysctl_sched_compat_yield) && curr->policy != SCHED_BATCH) {
+		update_rq_clock(rq);
+		/*
+		 * Update run-time statistics of the 'current'.
+		 */
+		update_curr(cfs_rq);
+
+		return;
+	}
+	/*
+	 * Find the rightmost entry in the rbtree:
+	 */
+	rightmost = __pick_last_entity(cfs_rq);
+	/*
+	 * Already in the rightmost position?
+	 */
+	if (unlikely(!rightmost || entity_before(rightmost, se)))
+		return;
+
+	/*
+	 * Minimally necessary key value to be last in the tree:
+	 * Upon rescheduling, sched_class::put_prev_task() will place
+	 * 'current' within the tree based on its new key value.
+	 */
+	se->vruntime = rightmost->vruntime + 1;
+}
+
+#ifdef CONFIG_SMP
+static void task_waking_fair(struct rq *rq, struct task_struct *p)
+{
+	struct sched_entity *se = &p->se;
+	struct cfs_rq *cfs_rq = cfs_rq_of(se);
+
+	se->vruntime -= cfs_rq->min_vruntime;
+}
+#endif
+
+static unsigned long
+wakeup_gran(struct sched_entity *curr, struct sched_entity *se)
+{
+	unsigned long gran = sysctl_sched_wakeup_granularity;
+
+	/*
+	 * Since its curr running now, convert the gran from real-time
+	 * to virtual-time in his units.
+	 *
+	 * By using 'se' instead of 'curr' we penalize light tasks, so
+	 * they get preempted easier. That is, if 'se' < 'curr' then
+	 * the resulting gran will be larger, therefore penalizing the
+	 * lighter, if otoh 'se' > 'curr' then the resulting gran will
+	 * be smaller, again penalizing the lighter task.
+	 *
+	 * This is especially important for buddies when the leftmost
+	 * task is higher priority than the buddy.
+	 */
+	if (unlikely(se->load.weight != NICE_0_LOAD))
+		gran = calc_delta_fair(gran, se);
+
+	return gran;
+}
+
+/*
+ * Should 'se' preempt 'curr'.
+ *
+ *             |s1
+ *        |s2
+ *   |s3
+ *         g
+ *      |<--->|c
+ *
+ *  w(c, s1) = -1
+ *  w(c, s2) =  0
+ *  w(c, s3) =  1
+ *
+ */
+static int
+wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)
+{
+	s64 gran, vdiff = curr->vruntime - se->vruntime;
+
+	if (vdiff <= 0)
+		return -1;
+
+	gran = wakeup_gran(curr, se);
+	if (vdiff > gran)
+		return 1;
+
+	return 0;
+}
+
+static void set_last_buddy(struct sched_entity *se)
+{
+	if (likely(task_of(se)->policy != SCHED_IDLE)) {
+		for_each_sched_entity(se)
+			cfs_rq_of(se)->last = se;
+	}
+}
+
+static void set_next_buddy(struct sched_entity *se)
+{
+	if (likely(task_of(se)->policy != SCHED_IDLE)) {
+		for_each_sched_entity(se)
+			cfs_rq_of(se)->next = se;
+	}
+}
+
+/*
+ * Preempt the current task with a newly woken task if needed:
+ */
+static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_flags)
+{
+	struct task_struct *curr = rq->curr;
+	struct sched_entity *se = &curr->se, *pse = &p->se;
+	struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+	int scale = cfs_rq->nr_running >= sched_nr_latency;
+
+	if (unlikely(se == pse))
+		return;
+
+	if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK))
+		set_next_buddy(pse);
+
+	/*
+	 * We can come here with TIF_NEED_RESCHED already set from new task
+	 * wake up path.
+	 */
+	if (test_tsk_need_resched(curr))
+		return;
+
+	/*
+	 * Batch and idle tasks do not preempt (their preemption is driven by
+	 * the tick):
+	 */
+	if (unlikely(p->policy != SCHED_NORMAL))
+		return;
+
+	/* Idle tasks are by definition preempted by everybody. */
+	if (unlikely(curr->policy == SCHED_IDLE))
+		goto preempt;
+
+	if (!sched_feat(WAKEUP_PREEMPT))
+		return;
+
+	update_curr(cfs_rq);
+	find_matching_se(&se, &pse);
+	BUG_ON(!pse);
+	if (wakeup_preempt_entity(se, pse) == 1)
+		goto preempt;
+
+	return;
+
+preempt:
+	resched_task(curr);
+	/*
+	 * Only set the backward buddy when the current task is still
+	 * on the rq. This can happen when a wakeup gets interleaved
+	 * with schedule on the ->pre_schedule() or idle_balance()
+	 * point, either of which can * drop the rq lock.
+	 *
+	 * Also, during early boot the idle thread is in the fair class,
+	 * for obvious reasons its a bad idea to schedule back to it.
+	 */
+	if (unlikely(!se->on_rq || curr == rq->idle))
+		return;
+
+	if (sched_feat(LAST_BUDDY) && scale && entity_is_task(se))
+		set_last_buddy(se);
+}
+
+static struct task_struct *pick_next_task_fair(struct rq *rq)
+{
+	struct task_struct *p;
+	struct cfs_rq *cfs_rq = &rq->cfs;
+	struct sched_entity *se;
+
+	if (!cfs_rq->nr_running)
+		return NULL;
+
+	do {
+		se = pick_next_entity(cfs_rq);
+		set_next_entity(cfs_rq, se);
+		cfs_rq = group_cfs_rq(se);
+	} while (cfs_rq);
+
+	p = task_of(se);
+	hrtick_start_fair(rq, p);
+
+	return p;
+}
+
+/*
+ * Account for a descheduled task:
+ */
+static void put_prev_task_fair(struct rq *rq, struct task_struct *prev)
+{
+	struct sched_entity *se = &prev->se;
+	struct cfs_rq *cfs_rq;
+
+	for_each_sched_entity(se) {
+		cfs_rq = cfs_rq_of(se);
+		put_prev_entity(cfs_rq, se);
+	}
+}
+
+#ifdef CONFIG_SMP
+/**************************************************
+ * Fair scheduling class load-balancing methods:
+ */
+
+/*
+ * pull_task - move a task from a remote runqueue to the local runqueue.
+ * Both runqueues must be locked.
+ */
+static void pull_task(struct rq *src_rq, struct task_struct *p,
+		      struct rq *this_rq, int this_cpu)
+{
+	deactivate_task(src_rq, p, 0);
+	set_task_cpu(p, this_cpu);
+	activate_task(this_rq, p, 0);
+	check_preempt_curr(this_rq, p, 0);
+}
+
+/*
+ * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
+ */
+static
+int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
+		     struct sched_domain *sd, enum cpu_idle_type idle,
+		     int *all_pinned)
+{
+	int tsk_cache_hot = 0;
+	/*
+	 * We do not migrate tasks that are:
+	 * 1) running (obviously), or
+	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
+	 * 3) are cache-hot on their current CPU.
+	 */
+	if (!cpumask_test_cpu(this_cpu, &p->cpus_allowed)) {
+		schedstat_inc(p, se.statistics.nr_failed_migrations_affine);
+		return 0;
+	}
+	*all_pinned = 0;
+
+	if (task_running(rq, p)) {
+		schedstat_inc(p, se.statistics.nr_failed_migrations_running);
+		return 0;
+	}
+
+	/*
+	 * Aggressive migration if:
+	 * 1) task is cache cold, or
+	 * 2) too many balance attempts have failed.
+	 */
+
+	tsk_cache_hot = task_hot(p, rq->clock_task, sd);
+	if (!tsk_cache_hot ||
+		sd->nr_balance_failed > sd->cache_nice_tries) {
+#ifdef CONFIG_SCHEDSTATS
+		if (tsk_cache_hot) {
+			schedstat_inc(sd, lb_hot_gained[idle]);
+			schedstat_inc(p, se.statistics.nr_forced_migrations);
+		}
+#endif
+		return 1;
+	}
+
+	if (tsk_cache_hot) {
+		schedstat_inc(p, se.statistics.nr_failed_migrations_hot);
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * move_one_task tries to move exactly one task from busiest to this_rq, as
+ * part of active balancing operations within "domain".
+ * Returns 1 if successful and 0 otherwise.
+ *
+ * Called with both runqueues locked.
+ */
+static int
+move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest,
+	      struct sched_domain *sd, enum cpu_idle_type idle)
+{
+	struct task_struct *p, *n;
+	struct cfs_rq *cfs_rq;
+	int pinned = 0;
+
+	for_each_leaf_cfs_rq(busiest, cfs_rq) {
+		list_for_each_entry_safe(p, n, &cfs_rq->tasks, se.group_node) {
+
+			if (!can_migrate_task(p, busiest, this_cpu,
+						sd, idle, &pinned))
+				continue;
+
+			pull_task(busiest, p, this_rq, this_cpu);
+			/*
+			 * Right now, this is only the second place pull_task()
+			 * is called, so we can safely collect pull_task()
+			 * stats here rather than inside pull_task().
+			 */
+			schedstat_inc(sd, lb_gained[idle]);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned long
+balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
+	      unsigned long max_load_move, struct sched_domain *sd,
+	      enum cpu_idle_type idle, int *all_pinned,
+	      int *this_best_prio, struct cfs_rq *busiest_cfs_rq)
+{
+	int loops = 0, pulled = 0;
+	long rem_load_move = max_load_move;
+	struct task_struct *p, *n;
+
+	if (max_load_move == 0)
+		goto out;
+
+	list_for_each_entry_safe(p, n, &busiest_cfs_rq->tasks, se.group_node) {
+		if (loops++ > sysctl_sched_nr_migrate)
+			break;
+
+		if ((p->se.load.weight >> 1) > rem_load_move ||
+		    !can_migrate_task(p, busiest, this_cpu, sd, idle,
+				      all_pinned))
+			continue;
+
+		pull_task(busiest, p, this_rq, this_cpu);
+		pulled++;
+		rem_load_move -= p->se.load.weight;
+
+#ifdef CONFIG_PREEMPT
+		/*
+		 * NEWIDLE balancing is a source of latency, so preemptible
+		 * kernels will stop after the first task is pulled to minimize
+		 * the critical section.
+		 */
+		if (idle == CPU_NEWLY_IDLE)
+			break;
+#endif
+
+		/*
+		 * We only want to steal up to the prescribed amount of
+		 * weighted load.
+		 */
+		if (rem_load_move <= 0)
+			break;
+
+		if (p->prio < *this_best_prio)
+			*this_best_prio = p->prio;
+	}
+out:
+	/*
+	 * Right now, this is one of only two places pull_task() is called,
+	 * so we can safely collect pull_task() stats here rather than
+	 * inside pull_task().
+	 */
+	schedstat_add(sd, lb_gained[idle], pulled);
+
+	return max_load_move - rem_load_move;
+}
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+/*
+ * update tg->load_weight by folding this cpu's load_avg
+ */
+static int update_shares_cpu(struct task_group *tg, int cpu)
+{
+	struct cfs_rq *cfs_rq;
+	unsigned long flags;
+	struct rq *rq;
+
+	if (!tg->se[cpu])
+		return 0;
+
+	rq = cpu_rq(cpu);
+	cfs_rq = tg->cfs_rq[cpu];
+
+	raw_spin_lock_irqsave(&rq->lock, flags);
+
+	update_rq_clock(rq);
+	update_cfs_load(cfs_rq, 1);
+
+	/*
+	 * We need to update shares after updating tg->load_weight in
+	 * order to adjust the weight of groups with long running tasks.
+	 */
+	update_cfs_shares(cfs_rq, 0);
+
+	raw_spin_unlock_irqrestore(&rq->lock, flags);
+
+	return 0;
+}
+
+static void update_shares(int cpu)
+{
+	struct cfs_rq *cfs_rq;
+	struct rq *rq = cpu_rq(cpu);
+
+	rcu_read_lock();
+	for_each_leaf_cfs_rq(rq, cfs_rq)
+		update_shares_cpu(cfs_rq->tg, cpu);
+	rcu_read_unlock();
+}
+
+/*
+ * Compute the cpu's hierarchical load factor for each task group.
+ * This needs to be done in a top-down fashion because the load of a child
+ * group is a fraction of its parents load.
+ */
+static int tg_load_down(struct task_group *tg, void *data)
+{
+	unsigned long load;
+	long cpu = (long)data;
+
+	if (!tg->parent) {
+		load = cpu_rq(cpu)->load.weight;
+	} else {
+		load = tg->parent->cfs_rq[cpu]->h_load;
+		load *= tg->se[cpu]->load.weight;
+		load /= tg->parent->cfs_rq[cpu]->load.weight + 1;
+	}
+
+	tg->cfs_rq[cpu]->h_load = load;
+
+	return 0;
+}
+
+static void update_h_load(long cpu)
+{
+	walk_tg_tree(tg_load_down, tg_nop, (void *)cpu);
+}
+
+static unsigned long
+load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
+		  unsigned long max_load_move,
+		  struct sched_domain *sd, enum cpu_idle_type idle,
+		  int *all_pinned, int *this_best_prio)
+{
+	long rem_load_move = max_load_move;
+	int busiest_cpu = cpu_of(busiest);
+	struct task_group *tg;
+
+	rcu_read_lock();
+	update_h_load(busiest_cpu);
+
+	list_for_each_entry_rcu(tg, &task_groups, list) {
+		struct cfs_rq *busiest_cfs_rq = tg->cfs_rq[busiest_cpu];
+		unsigned long busiest_h_load = busiest_cfs_rq->h_load;
+		unsigned long busiest_weight = busiest_cfs_rq->load.weight;
+		u64 rem_load, moved_load;
+
+		/*
+		 * empty group
+		 */
+		if (!busiest_cfs_rq->task_weight)
+			continue;
+
+		rem_load = (u64)rem_load_move * busiest_weight;
+		rem_load = div_u64(rem_load, busiest_h_load + 1);
+
+		moved_load = balance_tasks(this_rq, this_cpu, busiest,
+				rem_load, sd, idle, all_pinned, this_best_prio,
+				busiest_cfs_rq);
+
+		if (!moved_load)
+			continue;
+
+		moved_load *= busiest_h_load;
+		moved_load = div_u64(moved_load, busiest_weight + 1);
+
+		rem_load_move -= moved_load;
+		if (rem_load_move < 0)
+			break;
+	}
+	rcu_read_unlock();
+
+	return max_load_move - rem_load_move;
+}
+#else
+static inline void update_shares(int cpu)
+{
+}
+
+static unsigned long
+load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
+		  unsigned long max_load_move,
+		  struct sched_domain *sd, enum cpu_idle_type idle,
+		  int *all_pinned, int *this_best_prio)
+{
+	return balance_tasks(this_rq, this_cpu, busiest,
+			max_load_move, sd, idle, all_pinned,
+			this_best_prio, &busiest->cfs);
+}
+#endif
+
+
+/*
+ * scheduler tick hitting a task of our scheduling class:
+ */
+static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
+{
+	struct cfs_rq *cfs_rq;
+	struct sched_entity *se = &curr->se;
+
+	for_each_sched_entity(se) {
+		cfs_rq = cfs_rq_of(se);
+		entity_tick(cfs_rq, se, queued);
+	}
+}
+
+/*
+ * called on fork with the child task as argument from the parent's context
+ *  - child not yet on the tasklist
+ *  - preemption disabled
+ */
+static void task_fork_fair(struct task_struct *p)
+{
+	struct cfs_rq *cfs_rq = task_cfs_rq(current);
+	struct sched_entity *se = &p->se, *curr = cfs_rq->curr;
+	int this_cpu = smp_processor_id();
+	struct rq *rq = this_rq();
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&rq->lock, flags);
+
+	update_rq_clock(rq);
+
+	if (unlikely(task_cpu(p) != this_cpu)) {
+		rcu_read_lock();
+		__set_task_cpu(p, this_cpu);
+		rcu_read_unlock();
+	}
+
+	update_curr(cfs_rq);
+
+	if (curr)
+		se->vruntime = curr->vruntime;
+	place_entity(cfs_rq, se, 1);
+
+	if (sysctl_sched_child_runs_first && curr && entity_before(curr, se)) {
+		/*
+		 * Upon rescheduling, sched_class::put_prev_task() will place
+		 * 'current' within the tree based on its new key value.
+		 */
+		swap(curr->vruntime, se->vruntime);
+		resched_task(rq->curr);
+	}
+
+	se->vruntime -= cfs_rq->min_vruntime;
+
+	raw_spin_unlock_irqrestore(&rq->lock, flags);
+}
+
+/*
+ * Priority of the task has changed. Check to see if we preempt
+ * the current task.
+ */
+static void prio_changed_fair(struct rq *rq, struct task_struct *p,
+			      int oldprio, int running)
+{
+	/*
+	 * Reschedule if we are currently running on this runqueue and
+	 * our priority decreased, or if we are not currently running on
+	 * this runqueue and our priority is higher than the current's
+	 */
+	if (running) {
+		if (p->prio > oldprio)
+			resched_task(rq->curr);
+	} else
+		check_preempt_curr(rq, p, 0);
+}
+
+/*
+ * We switched to the sched_fair class.
+ */
+static void switched_to_fair(struct rq *rq, struct task_struct *p,
+			     int running)
+{
+	/*
+	 * We were most likely switched from sched_rt, so
+	 * kick off the schedule if running, otherwise just see
+	 * if we can still preempt the current task.
+	 */
+	if (running)
+		resched_task(rq->curr);
+	else
+		check_preempt_curr(rq, p, 0);
+}
+
+/* Account for a task changing its policy or group.
+ *
+ * This routine is mostly called to set cfs_rq->curr field when a task
+ * migrates between groups/classes.
+ */
+static void set_curr_task_fair(struct rq *rq)
+{
+	struct sched_entity *se = &rq->curr->se;
+
+	for_each_sched_entity(se)
+		set_next_entity(cfs_rq_of(se), se);
+}
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+static void task_move_group_fair(struct task_struct *p, int on_rq)
+{
+	/*
+	 * If the task was not on the rq at the time of this cgroup movement
+	 * it must have been asleep, sleeping tasks keep their ->vruntime
+	 * absolute on their old rq until wakeup (needed for the fair sleeper
+	 * bonus in place_entity()).
+	 *
+	 * If it was on the rq, we've just 'preempted' it, which does convert
+	 * ->vruntime to a relative base.
+	 *
+	 * Make sure both cases convert their relative position when migrating
+	 * to another cgroup's rq. This does somewhat interfere with the
+	 * fair sleeper stuff for the first placement, but who cares.
+	 */
+	if (!on_rq)
+		p->se.vruntime -= cfs_rq_of(&p->se)->min_vruntime;
+	set_task_rq(p, task_cpu(p));
+	if (!on_rq)
+		p->se.vruntime += cfs_rq_of(&p->se)->min_vruntime;
+}
+#endif
+
+static unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task)
+{
+	struct sched_entity *se = &task->se;
+	unsigned int rr_interval = 0;
+
+	/*
+	 * Time slice is 0 for SCHED_OTHER tasks that are on an otherwise
+	 * idle runqueue:
+	 */
+	if (rq->cfs.load.weight)
+		rr_interval = NS_TO_JIFFIES(sched_slice(&rq->cfs, se));
+
+	return rr_interval;
+}
+
+/*
+ * All the scheduling class methods:
+ */
+static const struct sched_class fair_sched_class = {
+	.next			= &idle_sched_class,
+	.enqueue_task		= enqueue_task_fair,
+	.dequeue_task		= dequeue_task_fair,
+	.yield_task		= yield_task_fair,
+
+	.check_preempt_curr	= check_preempt_wakeup,
+
+	.pick_next_task		= pick_next_task_fair,
+	.put_prev_task		= put_prev_task_fair,
+
+#ifdef CONFIG_SMP
+	.select_task_rq		= select_task_rq_fair,
+
+	.rq_online		= rq_online_fair,
+	.rq_offline		= rq_offline_fair,
+
+	.task_waking		= task_waking_fair,
+#endif
+
+	.set_curr_task          = set_curr_task_fair,
+	.task_tick		= task_tick_fair,
+	.task_fork		= task_fork_fair,
+
+	.prio_changed		= prio_changed_fair,
+	.switched_to		= switched_to_fair,
+
+	.get_rr_interval	= get_rr_interval_fair,
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+	.task_move_group	= task_move_group_fair,
+#endif
+};
+
+#ifdef CONFIG_SCHED_DEBUG
+static void print_cfs_stats(struct seq_file *m, int cpu)
+{
+	struct cfs_rq *cfs_rq;
+
+	rcu_read_lock();
+	for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq)
+		print_cfs_rq(m, cpu, cfs_rq);
+	rcu_read_unlock();
+}
+#endif
diff --git a/kernel/sched_fair_htfs.c b/kernel/sched_fair_htfs.c
new file mode 100644
index 0000000..2f2aca0
--- /dev/null
+++ b/kernel/sched_fair_htfs.c
@@ -0,0 +1,2273 @@
+/*
+ *  High Throughput Fair Scheduler Class
+ *
+ *  Copyright (C) 2011 Markus Pargmann <mpargmann@allfex.org>
+ *
+ *  Some balancing routines from the original CFS
+ *  (C) 2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
+ *
+ */
+
+
+#ifdef CONFIG_SCHED_FAIR_HTFS
+
+#define HTFS_WEIGHT_LVLS 50
+
+static const unsigned long bweights[HTFS_WEIGHT_LVLS] = {
+              270877,    216701,    173361,    138689,    110951,
+ /* -20 */     88761,     71755,     56483,     46273,     36291,
+ /* -15 */     29154,     23254,     18705,     14949,     11916,
+ /* -10 */      9548,      7620,      6100,      4904,      3906,
+ /*  -5 */      3121,      2501,      1991,      1586,      1277,
+ /*   0 */      1024,       820,       655,       526,       423,
+ /*   5 */       335,       272,       215,       172,       137,
+ /*  10 */       110,        87,        70,        56,        45,
+ /*  15 */        36,        29,        23,        18,        15,
+                  12,         9,         6,         3,         1
+};
+
+
+static struct htfs_rq *rq_of_pq(struct htfs_pq *pq);
+
+
+/******************************************************************************
+ * Debugging functions
+ */
+#define DBG_WAIT(seconds) { volatile long i = seconds * (1L<<10); while(i--);}
+static const int dbg_level = 0;
+#define DBG_FUNC(level) {if (dbg_level >= level) {DBG_FUNC_NOWAIT(level); DBG_WAIT(0);}}
+#define DBG_FUNC_EXT(level, arg) {if (dbg_level >= level) {DBG_FUNC_NOWAIT_EXT(level, arg); DBG_WAIT(0);}}
+
+#define DBG_PRINTK(level, args) {if (dbg_level >= level) { printk(KERN_EMERG "HTFS: %s: ", __FUNCTION__); printk args ; DBG_WAIT(0)}}
+
+#define DBG_FUNC_NOWAIT(level) {if (dbg_level >= level) {DBG_FUNC_NOWAIT_EXT(level, "");}}
+#define DBG_FUNC_NOWAIT_EXT(level, arg) {if (dbg_level >= level) {printk(KERN_EMERG "HTFS: %s %s\n", __FUNCTION__, arg);}}
+
+#define DBG_ASSERT(condition) {if (unlikely(!(condition))) {printk(KERN_EMERG "HTFS ASSERT FAILED: %s function: %s line: %d\n", #condition, __FUNCTION__, __LINE__); DBG_WAIT(1000000);}}
+
+static void pq_dump(struct htfs_pq *pq, int level)
+{
+	struct list_head *lh = pq->queue.next;
+	if (level > dbg_level)
+		return;
+	while (lh != &pq->queue) {
+		struct sched_entity *se = list_entry(lh, struct sched_entity,
+				htfs_pq_item);
+		printk(KERN_EMERG "      vruntime: %lu weight: %lu "
+				"bweight: %lu inter:%lu inter_avg:%lu "
+				"load_avg: %lu\n",
+				(unsigned long)se->vruntime,
+				se->load.weight,
+				bweights[se->bw_ind],
+				se->inter,
+				se->inter_avg,
+				se->load_avg);
+		lh = lh->next;
+	}
+}
+
+static void rq_dump(struct htfs_rq *rq, int level)
+{
+	struct list_head *lh;
+	if (level > dbg_level)
+		return;
+	printk(KERN_EMERG "bw:%lu w:%lu run_cost:%lu\n",
+			rq->bweight,
+			(unsigned long)rq->bweight,
+			(unsigned long)rq->run_cost);
+	printk(KERN_EMERG "  sl:\n");
+	lh = &rq->spqs_real_weight;
+	while ((lh = lh->prev) != &rq->spqs_real_weight) {
+		struct htfs_pq *pq = list_entry(lh, struct htfs_pq, spqs_real_weight);
+		if (pq == rq->cur_pq) {
+			printk(KERN_EMERG "----vvvvv\n");
+		}
+		printk(KERN_EMERG "    real_bweight:%lu balance_ct:%lu\n",
+				(unsigned long)pq->real_bweight,
+				(unsigned long)pq->balance_ct);
+		pq_dump(pq, level);
+	}
+	printk(KERN_EMERG "\n");
+}
+
+static void rqs_dump(struct htfs_rqs *rqs, int level)
+{
+	if (level > dbg_level)
+		return;
+	printk(KERN_EMERG "rqs:%lu run:%lu vtime:%lu bct:%ld weight:%lu load:%lu load_avg:%lu load_contr:%lu slice_shift: %u\n",
+			(unsigned long)rqs, (unsigned long)rqs->nr_running,
+			(unsigned long)rqs->vtime,
+			(unsigned long)rqs->rq_balance_ct,
+			rqs->weight,
+			rqs->load,
+			rqs->load_avg,
+			rqs->load_contribution,
+			rqs->rq->slice_shift);
+	printk(KERN_EMERG "normalq ");
+	rq_dump(&rqs->normalq, level);
+	printk(KERN_EMERG "interq ");
+	rq_dump(&rqs->interq, level);
+	DBG_WAIT(1);
+}
+
+
+
+
+/******************************************************************************
+ * Function signatures and constant definitions
+ */
+static inline void pq_deactivate(struct htfs_rq *rq, struct htfs_pq *pq);
+static inline void pq_activate(struct htfs_rq *rq, struct htfs_pq *pq);
+static inline void
+pq_slist_resort_real_weight(struct htfs_rq *rq, struct htfs_pq *pq, int higher);
+
+
+
+
+// the static timeslice is used to decide boosted weight update, wakeup vruntime
+// updates, vtimestalls, and interq
+#define HTFS_STATIC_TIMESLICE_SHIFT 17
+// those defines are in number of shifts
+#define HTFS_TH_INTERQ 3
+#define HTFS_TH_BOOST 2
+#define HTFS_TH_WAKEUP 10
+
+#define HTFS_VTIME_ACCURACY 14
+
+//#define HTFS_LOAD_AVG 1
+#define HTFS_OLD_BALANCING 1
+
+#define calc_bweight_higher(weight) ((weight * weight_modifier[1]\
+	+ (1UL << (HTFS_WEIGHT_MOD_SHIFT - 1))) >> HTFS_WEIGHT_MOD_SHIFT)
+
+#define calc_bweight_lower(weight) ((weight * weight_modifier[0]\
+	+ (1UL << (HTFS_WEIGHT_MOD_SHIFT - 1))) >> HTFS_WEIGHT_MOD_SHIFT)
+
+
+/*
+ * The exponential sliding  window over which load is averaged for shares
+ * distribution.
+ * (default: 10msec)
+ */
+unsigned int __read_mostly sysctl_sched_shares_window = 10000000UL;
+
+unsigned int sysctl_sched_inter_slice_shift = 17;
+u64 sched_inter_slice = (1UL << 17);
+u64 sysctl_sched_inter_latency = 10000000ULL;
+
+unsigned int sysctl_sched_slice_max_shift = 30;
+
+
+int sched_proc_update_handler(struct ctl_table *table, int write,
+		void __user *buffer, size_t *lenp,
+		loff_t *ppos)
+{
+	int ret = proc_dointvec(table, write, buffer, lenp, ppos);
+	sched_inter_slice = (1UL << sysctl_sched_inter_slice_shift);
+
+	return ret;
+}
+
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+/* Walk up scheduling entities hierarchy */
+#define for_each_sched_entity(se) \
+		for (; se; se = se->parent)
+
+static inline struct htfs_rqs *group_htfs_rqs(struct sched_entity *se)
+{
+	return se->my_q;
+}
+
+#else
+#define for_each_sched_entity(se) \
+		for (; se; se = NULL)
+
+#endif
+
+static inline struct htfs_rqs *rqs_of_rq(struct htfs_rq *rq)
+{
+	return rq->rqs;
+}
+
+static inline struct htfs_rq *htfs_rq_of_se(struct sched_entity *se)
+{
+	return se->htfs_rq;
+}
+
+static inline struct htfs_rqs *rqs_of_se(struct sched_entity *se)
+{
+	return se->htfs_rqs;
+}
+
+static inline struct rq *rq_of_rqs(struct htfs_rqs *rqs)
+{
+	return rqs->rq;
+}
+
+static inline struct rq *rq_of_se(struct sched_entity *se)
+{
+	return rq_of_rqs(rqs_of_se(se));
+}
+
+/******************************************************************************
+ * operations about vtime and steppings
+ */
+
+static inline void rqs_update_vtime_concrete(struct htfs_rqs *rqs, u64 time)
+{
+	if (!rqs->inv_weight) {
+		rqs->inv_weight = calc_inv_weight(rqs->normalq.bweight);
+	}
+	rqs->vtime += (rqs->inv_weight * time)
+			>> (32 - HTFS_VTIME_ACCURACY);
+}
+
+/*
+ * updates the runqueues vtime
+ */
+static inline void rqs_update_vtime(struct htfs_rqs *rqs)
+{
+	if (!rqs->inv_weight) {
+		rqs->inv_weight = calc_inv_weight(rqs->normalq.bweight);
+	}
+	rqs->vtime += ((u64)rqs->inv_weight << rqs->rq->slice_shift)
+			>> (32 - HTFS_VTIME_ACCURACY);
+}
+
+/*
+ * updates the values of the runqueue rq if the new first pq in the real_weight
+ * list changed
+ */
+static inline void update_first_pq(struct htfs_rqs *rqs, struct htfs_rq *rq)
+{
+	struct htfs_pq *new_first = list_entry(rq->spqs_real_weight.prev,
+				struct htfs_pq, spqs_real_weight);
+	rq->run_cost = new_first->real_bweight;
+}
+
+/******************************************************************************
+ * se-operations
+ */
+static inline unsigned int se_find_bw_ind(struct sched_entity *se)
+{
+	int low = 0;
+	int up = HTFS_WEIGHT_LVLS;
+	int new;
+	const unsigned long w = se->load.weight;
+	while (low != up) {
+		new = ((up - low) >> 1) + low;
+		if (unlikely(w == bweights[new])) {
+			return new;
+		}
+		if (w < bweights[new]) {
+			low = new + 1;
+			if (unlikely(low >= HTFS_WEIGHT_LVLS))
+				return HTFS_WEIGHT_LVLS - 1;
+		} else {
+			up = new;
+			if (unlikely(up <= 0))
+				return 0;
+		}
+	}
+	return low;
+}
+
+static inline int se_is_on_interq(struct sched_entity *se)
+{
+	struct htfs_rqs *rqs = rqs_of_se(se);
+	return (&rqs->interq == htfs_rq_of_se(se));
+}
+
+#define HTFS_AVG_SHIFT 3
+#define HTFS_AVG_FACTOR ((1UL << HTFS_AVG_SHIFT) - 1)
+
+#if (defined CONFIG_SMP || !defined HTFS_OLD_BALANCING)
+
+static inline unsigned long calc_avg_after_sleep(u64 slice_shift, unsigned long avg,
+		u64 sleep_time)
+{
+	int i = sleep_time >> (slice_shift + 2);
+	if (i <= 0)
+		return avg;
+	avg >>= i;
+	return avg;
+}
+
+static inline void rqs_update_load_avg(struct htfs_rqs *rqs)
+{
+	unsigned long load_avg = (rqs->load_avg * HTFS_AVG_FACTOR + rqs->load
+			+ (1UL << (HTFS_AVG_SHIFT - 1)))
+			>> HTFS_AVG_SHIFT;
+#ifdef HTFS_LOAD_AVG
+	if (&rqs->rq->htfs_rqs == rqs) {
+		long diff = load_avg - rqs->load_avg;
+		if (diff < 0)
+			dec_cpu_load(rqs->rq, -diff);
+		else
+			inc_cpu_load(rqs->rq, diff);
+	}
+#endif
+	rqs->load_avg = load_avg;
+}
+
+static inline void rqs_wakeup_load_avg(struct htfs_rqs *rqs, struct rq *rq)
+{
+	u64 now = rq->clock;
+	u64 delta = now - rqs->offline_start;
+	unsigned long load_avg = calc_avg_after_sleep(HTFS_STATIC_TIMESLICE_SHIFT,
+			rqs->load_avg, delta);
+#ifdef HTFS_LOAD_AVG
+	if (&rqs->rq->htfs_rqs == rqs) {
+		long diff = load_avg - rqs->load_avg;
+		if (diff < 0)
+			dec_cpu_load(rqs->rq, -diff);
+		else
+			inc_cpu_load(rqs->rq, diff);
+	}
+#endif
+	rqs->load_avg = load_avg;
+}
+
+static inline void rqs_se_update_load_avg(struct htfs_rqs *rqs, struct sched_entity *se,
+		long load_diff);
+
+static inline void se_set_load_avg(struct htfs_rqs *rqs, struct sched_entity *se,
+		unsigned long new_load)
+{
+	rqs_se_update_load_avg(rqs_of_se(se), se, (long)(new_load - se->load_avg));
+	se->load_avg = new_load;
+}
+
+static inline void se_update_load_avg(struct htfs_rqs *rqs, struct sched_entity *se,
+		u64 unused_time)
+{
+#ifdef HTFS_LOAD_AVG
+	unsigned long new_load;
+	if (likely(unused_time == 0)) {
+		new_load = (se->load_avg * HTFS_AVG_FACTOR + se->load.weight)
+				>> HTFS_AVG_SHIFT;
+	} else {
+		if (rqs->rq->slice_granted <=
+				(1UL << sysctl_sched_inter_slice_shift)) {
+			new_load = (se->load_avg * HTFS_AVG_FACTOR
+				+ se->load.weight
+				- ((se->load.weight * unused_time)
+				>> sysctl_sched_inter_slice_shift))
+				>> HTFS_AVG_SHIFT;
+		} else if (rqs->rq->slice_granted <= rqs->rq->slice) {
+			new_load = (se->load_avg * HTFS_AVG_FACTOR
+				+ se->load.weight
+				- ((se->load.weight * unused_time)
+				>> rqs->rq->slice_shift))
+				>> HTFS_AVG_SHIFT;
+		} else {
+			new_load = se->load_avg;
+		}
+
+	}
+	se_set_load_avg(rqs, se, new_load);
+#endif
+}
+
+static inline void se_wakeup_load_avg(struct htfs_rqs *rqs, struct sched_entity *se,
+		u64 unused_time)
+{
+#ifdef HTFS_LOAD_AVG
+	if (unused_time == 0)
+		return;
+	se->load_avg = calc_avg_after_sleep(HTFS_STATIC_TIMESLICE_SHIFT,
+			se->load_avg, unused_time);
+#endif
+}
+
+#else /* CONFIG_SMP */
+
+static inline void rqs_update_load_avg(struct htfs_rqs *rqs)
+{
+}
+
+static inline void rqs_wakeup_load_avg(struct htfs_rqs *rqs, struct rq *rq)
+{
+}
+
+static inline void se_update_load_avg(struct htfs_rqs *rqs,struct sched_entity *se,
+		u64 unused_time)
+{
+}
+
+static inline void se_wakeup_load_avg(struct htfs_rqs *rqs, struct sched_entity *se,
+		u64 unused_time)
+{
+}
+
+#endif /* CONFIG_SMP */
+
+
+
+#define HTFS_INTER_MAX (1UL << 30)
+#define HTFS_INTER_MIN (0L)
+
+/*
+ * this interactive value is currently not used... but they are going to be used
+
+#ifdef CONFIG_SMP
+static void se_inter_inc(struct sched_entity *se, unsigned long delta)
+{
+	se->inter = min(HTFS_INTER_MAX, se->inter + delta);
+}
+
+static void se_inter_dec(struct sched_entity *se, unsigned long delta)
+{
+	se->inter = (unsigned long) max(HTFS_INTER_MIN, (long)(se->inter - delta));
+}
+
+static void se_update_rqs_inter_avg(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	unsigned long new_avg = (se->inter_avg * 3 + se->inter) >> 2;
+	rqs->inter = rqs->inter - se->inter_avg + new_avg;
+	se->inter_avg = new_avg;
+}
+
+static void se_update_inter_avg_punish(struct htfs_rqs *rqs,
+		struct sched_entity *se)
+{
+	se_inter_inc(se, se->load.weight);
+	se_update_rqs_inter_avg(rqs, se);
+}
+
+static void se_update_inter_avg(struct htfs_rqs *rqs,
+		struct sched_entity *se)
+{
+	se_inter_dec(se, se->load.weight);
+	se_update_rqs_inter_avg(rqs, se);
+}
+
+static void se_update_inter_dequeue(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	se_inter_inc(se, se->load.weight);
+	rqs->inter -= se->inter_avg;
+}
+
+static void se_update_inter_wakeup(struct htfs_rqs *rqs, struct sched_entity *se,
+		u64 sleep_time)
+{
+	u64 weighted_sleep = (sleep_time >> HTFS_STATIC_TIMESLICE_SHIFT)
+			* se->load.weight;
+	if (weighted_sleep > se->inter) {
+		se->inter = HTFS_INTER_MIN;
+		se->inter_avg = HTFS_INTER_MIN;
+	} else {
+		se_inter_dec(se, weighted_sleep);
+		se->inter_avg = max(HTFS_INTER_MIN,
+				(long)(se->inter_avg - weighted_sleep));
+	}
+	se_inter_inc(se, 2 * se->load.weight);
+	rqs->inter += se->inter_avg;
+}
+
+static void se_inter_init(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	se->inter = HTFS_INTER_MIN + 2 * se->load.weight;
+	se->inter_avg = HTFS_INTER_MIN + 2 * se->load.weight;
+}
+
+#else
+*/
+static inline void se_update_inter_avg_punish(struct htfs_rqs *rqs,
+		struct sched_entity *se)
+{
+}
+
+static inline void se_update_inter_avg(struct htfs_rqs *rqs,
+		struct sched_entity *se)
+{
+}
+
+static inline void se_update_inter_dequeue(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+}
+
+static inline void se_update_inter_wakeup(struct htfs_rqs *rqs, struct sched_entity *se,
+		u64 sleep_time)
+{
+
+}
+
+static inline void se_inter_init(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+
+}
+
+//#endif
+
+/*
+ * Set the vruntime after wakeup of se. The vruntime has to be higher than
+ * vtime - 2^HTFS_TH_WAKEUP * timeslice.
+ * 
+ */
+static inline void se_wakeup_set_vruntime(struct htfs_rqs *rqs,
+		struct sched_entity *se)
+{
+	u64 new_vruntime;
+	u64 thresh_vruntime = ((u64)se->load.inv_weight
+			<< HTFS_STATIC_TIMESLICE_SHIFT)
+			>> (32 - HTFS_TH_WAKEUP - HTFS_VTIME_ACCURACY);
+	if (se->vruntime > rqs->vtime) {
+		if (unlikely(se->vruntime - rqs->vtime > thresh_vruntime))
+			new_vruntime = rqs->vtime + thresh_vruntime;
+		else
+			new_vruntime = se->vruntime;
+	} else {
+		if (unlikely(rqs->vtime - se->vruntime > thresh_vruntime)) {
+			u64 vtime_diff;
+			u64 sleep_time;
+			new_vruntime = rqs->vtime - thresh_vruntime;
+			vtime_diff = new_vruntime - se->vruntime;
+			sleep_time = vtime_diff / se->load.inv_weight;
+			se_update_inter_wakeup(rqs, se, sleep_time);
+			se_wakeup_load_avg(rqs, se, sleep_time);
+		} else {
+			new_vruntime = se->vruntime;
+		}
+	}
+	se->vruntime = new_vruntime;
+}
+
+#define HTFS_SLICE_DEVIATION (1UL << 14)
+
+/*
+ * If the se did not use the full timeslice available, punish it by adding
+ * one eighth of the possible timeslice to the vruntime
+ */
+#define HTFS_NOT_FULL_SLICE 3
+
+/*
+ * update vruntime after runnig
+ */
+static inline void se_update_vruntime(struct sched_entity *se)
+{
+	struct htfs_rqs *rqs = rqs_of_se(se);
+	struct rq *rq = rqs->rq;
+	u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime;
+	u64 vran = (ran * se->load.inv_weight) >> (32 - HTFS_VTIME_ACCURACY);
+	s64 slice_deviation = rq->slice_granted - ran;
+	rq->slice_remain = max(rq->slice_remain, ran) - ran;
+	se->vruntime += vran;
+	if (unlikely(se->htfs_state & HTFS_PREEMPTED)) {
+		se->htfs_state &= ~HTFS_PREEMPTED;
+		if (!se_is_on_interq(se))
+			rqs_update_vtime_concrete(rqs, ran);
+		goto full_slice_usage;
+	}
+	if (!se_is_on_interq(se))
+		rqs_update_vtime_concrete(rqs, rq->slice_granted);
+
+	// Punishing the tasks that leave the cpu much too early...
+	if (abs(slice_deviation) > HTFS_SLICE_DEVIATION) {
+		if ((s64)(rqs->rq->slice_granted - ran)
+				< rqs->rq->slice_granted >> HTFS_NOT_FULL_SLICE) {
+			goto full_slice_usage;
+		}
+		se->vruntime += ((rqs->rq->slice_granted >> HTFS_NOT_FULL_SLICE)
+				* se->load.inv_weight)
+				>> (32 - HTFS_VTIME_ACCURACY);
+		se_update_inter_avg_punish(rqs, se);
+		se_update_load_avg(rqs, se,
+				rqs->rq->slice_granted >> HTFS_NOT_FULL_SLICE);
+	} else {
+full_slice_usage:
+		se_update_inter_avg(rqs, se);
+		se_update_load_avg(rqs, se, 0);
+	}
+
+	se->prev_sum_exec_runtime = se->sum_exec_runtime;
+}
+
+/*
+ * set the se exec_start to now
+ */
+static inline void se_start_exec(struct sched_entity *se, struct rq *rq)
+{
+	unsigned long now = rq->clock_task;
+	se->exec_start = now;
+}
+
+/*
+ * update the real runtime of the process and return the remaining time in this
+ * slice
+ */
+static inline s64 se_update_runtime(struct sched_entity *se, struct rq *rq)
+{
+	u64 now = rq->clock_task;
+	struct htfs_rqs *rqs = rqs_of_se(se);
+	s64 remaining;
+	se->sum_exec_runtime += now - se->exec_start;
+	se->exec_start = now;
+	remaining = rqs->rq->slice_granted
+			- (s64)(se->sum_exec_runtime - se->prev_sum_exec_runtime);
+	return remaining;
+}
+
+enum se_need_newpq
+{
+	SE_ENQUEUE_NEW,
+	SE_REENQUEUE_LAST
+};
+
+/*
+ * calculates the new weight of a se and stores it at new_weight. Returns if the
+ * se can be enqueued on the last priorityqueue or it has to be enqueued on a
+ * priorityqueue with higher or lower weight.
+ */
+static inline enum se_need_newpq rq_se_get_new_bw_ind(struct htfs_rqs *rqs,
+		struct htfs_rq *rq, struct sched_entity *se,
+		unsigned int *new_bw_ind)
+{
+	s64 vdiff = (s64)(se->vruntime - rqs->vtime);
+
+//	int badness = (abs(vdiff) << HTFS_VTIME_ACCURACY)
+//				>> (rqs->rq->slice_shift + HTFS_TH_BOOST);
+//	u64 vran = (ran * se->load.inv_weight) >> (32 - HTFS_VTIME_ACCURACY);
+//	int badness = (( (u64)abs(vdiff) << (32 - HTFS_VTIME_ACCURACY)) * se->load.weight)
+//			>> (32 + rqs->rq->slice_shift + HTFS_TH_BOOST);
+	int badness = ((u64)abs(vdiff) * se->load.weight)
+			>> (HTFS_VTIME_ACCURACY + rqs->rq->slice_shift + HTFS_TH_BOOST);
+	if (unlikely(badness)) {
+		if (vdiff < 0) {
+			if (unlikely(se->last_vdiff > vdiff)) {
+				if (likely(se->bw_ind != 0)) {
+					*new_bw_ind = se->bw_ind - 1;
+					goto new_weight;
+				}
+				se->htfs_state |= HTFS_NEED_INTERQ;
+			}
+		} else {
+			if (unlikely(se->last_vdiff < vdiff
+					&& se->bw_ind < HTFS_WEIGHT_LVLS - 1)) {
+				*new_bw_ind = se->bw_ind + 1;
+				goto new_weight;
+			}
+		}
+	}
+	*new_bw_ind = se->bw_ind;
+	se->last_vdiff = vdiff;
+	return SE_REENQUEUE_LAST;
+
+new_weight:
+	se->last_vdiff = vdiff;
+	return SE_ENQUEUE_NEW;
+
+}
+
+/******************************************************************************
+ * pq-operations
+ */
+
+/*
+ * Enqueue se on the pq
+ */
+static inline void pq_enqueue(struct htfs_pq *pq, struct sched_entity *se)
+{
+	list_add_tail(&se->htfs_pq_item, &pq->queue);
+}
+
+/*
+ * Dequeue se from the pq
+ */
+static inline void pq_dequeue(struct htfs_pq *pq, struct sched_entity *se)
+{
+	list_del(&se->htfs_pq_item);
+}
+
+/*
+ * Get the next se from this pq. This does not dequeue the se. Dequeuing is done
+ * when removing the task, or put the task back on the queue
+ */
+static inline struct sched_entity *pq_dequeue_next(struct htfs_pq *pq)
+{
+	struct sched_entity *se = list_entry(pq->queue.next,
+			struct sched_entity, htfs_pq_item);
+	return se;
+}
+
+/*
+ * Delete the se from the pq. Including weight updates
+ */
+static inline void pq_del(struct htfs_rq *rq, struct htfs_pq *pq,
+		struct sched_entity *se)
+{
+	pq_dequeue(pq, se);
+	pq->real_bweight -= bweights[se->bw_ind];
+	if (unlikely(pq->real_bweight == 0)) {
+		pq_deactivate(rq, pq);
+	} else {
+		pq_slist_resort_real_weight(rq, pq, 0);
+	}
+}
+
+/*
+ * Add a new se to this pq. This does only the weight changes and so on.
+ * se is not enqueued.
+ */
+static inline void pq_add(struct htfs_rq *rq, struct htfs_pq *pq,
+		struct sched_entity *se)
+{
+	if (unlikely(pq->real_bweight == 0)) {
+		pq_activate(rq, pq);
+	}
+	pq->real_bweight += bweights[se->bw_ind];
+	pq_slist_resort_real_weight(rq, pq, 1);
+}
+
+
+
+
+
+
+/******************************************************************************
+ * priorityqueue management in a runqueue
+ */
+
+/*
+ * resorts a pq into the right place, starting at the current pq's
+ * position
+ */
+//TODO: the direction to compare to is given.
+#define spqs_resort(rq, pq, itemname, pqvaluename, higher) \
+{\
+	struct list_head *lh = &pq->itemname;\
+	const unsigned long cur_val = pq->pqvaluename;\
+	struct list_head *lh_cur;\
+	struct list_head *end = &rq->itemname;\
+	struct htfs_pq *pq_cur;\
+	if (higher) {\
+		lh_cur = lh->next;\
+		pq_cur = list_entry(lh_cur, struct htfs_pq, itemname);\
+		if (lh_cur != end && cur_val > pq_cur->pqvaluename) {\
+			list_del(lh);\
+			lh_cur = lh_cur->next;\
+			pq_cur = list_entry(lh_cur, struct htfs_pq, itemname);\
+			while (lh_cur != end && cur_val > pq_cur->pqvaluename) {\
+				lh_cur = lh_cur->next;\
+				pq_cur = list_entry(lh_cur, struct htfs_pq, itemname);\
+			}\
+			list_add_tail(lh, lh_cur);\
+			return;\
+		}\
+	} else {\
+		lh_cur = lh->prev;\
+		pq_cur = list_entry(lh_cur, struct htfs_pq, itemname);\
+		if (lh_cur != end && cur_val < pq_cur->pqvaluename) {\
+			list_del(lh);\
+			lh_cur = lh_cur->prev;\
+			pq_cur = list_entry(lh_cur, struct htfs_pq, itemname);\
+			while (lh_cur != end && cur_val > pq_cur->pqvaluename) {\
+				lh_cur = lh_cur->prev;\
+				pq_cur = list_entry(lh_cur, struct htfs_pq, itemname);\
+			}\
+			list_add(lh, lh_cur);\
+		}\
+	}\
+}
+
+/**
+ * resorts the element (pq) in the sorted list of priorityqueues
+ */
+static inline void
+pq_slist_resort_real_weight(struct htfs_rq *rq, struct htfs_pq *pq, int higher)
+{
+	struct htfs_rqs *rqs = rqs_of_rq(rq);
+	int update_first = (rq->spqs_real_weight.prev == &pq->spqs_real_weight);
+	spqs_resort(rq, pq, spqs_real_weight, real_bweight, higher);
+	if (update_first || rq->spqs_real_weight.prev == &pq->spqs_real_weight) {
+		update_first_pq(rqs, rq);
+	}
+}
+
+static inline void pq_balance_inc(struct htfs_pq *pq)
+{
+	pq->balance_ct += pq->real_bweight;
+}
+
+/*
+ * deactivate a empty priorityqueue
+ */
+static inline void pq_deactivate(struct htfs_rq *rq, struct htfs_pq *pq)
+{
+	// if this is the cur_pq, we need to replace it by a the best next
+	// priorityqueue
+	if (unlikely(rq->cur_pq == pq)) {
+		if (pq->spqs_real_weight.prev == &rq->spqs_real_weight) {
+			if (pq->spqs_real_weight.next == &rq->spqs_real_weight) {
+				rq->cur_pq = NULL;
+			} else {
+				rq->cur_pq = list_entry(pq->spqs_real_weight.next,
+						struct htfs_pq, spqs_real_weight);
+			}
+		} else {
+			rq->cur_pq = list_entry(pq->spqs_real_weight.prev,
+					struct htfs_pq, spqs_real_weight);
+			pq_balance_inc(rq->cur_pq);
+		}
+	}
+	// in case this was the priorityqueue with the lowest real_bweight
+	// we need to update the real_weight list
+	if (&pq->spqs_real_weight == rq->spqs_real_weight.prev) {
+		list_del(&pq->spqs_real_weight);
+		if (likely(rq->spqs_real_weight.prev != &rq->spqs_real_weight)) {
+			update_first_pq(rqs_of_rq(rq), rq);
+		}
+	} else {
+		list_del(&pq->spqs_real_weight);
+	}
+}
+
+static inline void pq_activate(struct htfs_rq *rq, struct htfs_pq *pq)
+{
+	pq->balance_ct = 0;
+	list_add(&pq->spqs_real_weight, &rq->spqs_real_weight);
+	if (unlikely(rq->cur_pq == NULL)) {
+		rq->cur_pq = pq;
+	}
+}
+
+/******************************************************************************
+ * rq-operations
+ */
+
+static inline void rqs_update_balance_ct_inter(struct htfs_rqs *rqs);
+static inline void rqs_update_balance_ct_normal(struct htfs_rqs *rqs);
+
+/*
+ * update weight rq. Only use this with weight updates...
+ * do not use on add or remove operations.
+ */
+static inline void rq_update_weight(struct htfs_rq *rq, s64 diff)
+{
+	rq->bweight += diff;
+	if (&rq->rqs->normalq == rq)
+		rq->rqs->inv_weight = 0;
+}
+
+/*
+ * decreasing weight, used when removing an entity
+ */
+static inline void rq_dec_bweight(struct htfs_rq *rq, u64 decweight)
+{
+	rq->bweight -= decweight;
+	if (unlikely(rq->bweight == 0)) {
+		struct htfs_rqs *rqs = rqs_of_rq(rq);
+		if (&rqs->interq == rq)
+			rqs->rq_balance_ct = -1;
+		else
+			rqs->rq_balance_ct = 1;
+	}
+	if (&rq->rqs->normalq == rq)
+		rq->rqs->inv_weight = 0;
+}
+
+/*
+ * increasing weight, used when adding an entity
+ */
+static inline void rq_inc_bweight(struct htfs_rq *rq, u64 incweight)
+{
+	if (unlikely(rq->bweight == 0)) {
+		struct htfs_rqs *rqs = rqs_of_rq(rq);
+		/*
+		 * the interactive runqueue has to be priorised to give the
+		 * interactive tasks enough slices.
+		 */
+		if (&rqs->interq == rq) {
+			rqs->rq_balance_ct = 1;
+			rqs_update_balance_ct_normal(rqs);
+		} else {
+			rqs->rq_balance_ct = -1;
+		}
+	}
+	if (&rq->rqs->normalq == rq)
+		rq->rqs->inv_weight = 0;
+	rq->bweight += incweight;
+}
+
+/*
+ * set the boosted weight while the se is not on a priorityqueue
+ */
+static inline s64 rq_se_set_bw_ind(struct htfs_rq *rq,
+		struct sched_entity *se, unsigned int bw_ind)
+{
+	s64 result = bweights[bw_ind] - bweights[se->bw_ind];
+	rq_update_weight(rq, result);
+	se->bw_ind = bw_ind;
+	return result;
+}
+
+/*
+ * delete the entity from the runqueue
+ */
+static inline void rq_del(struct htfs_rq *rq, struct sched_entity *se)
+{
+	pq_del(rq, &rq->pqs[se->bw_ind], se);
+	rq_dec_bweight(rq, bweights[se->bw_ind]);
+}
+
+/**
+ * adding the se to this rq. this only adds values
+ */
+static inline void rq_add(struct htfs_rq *rq, struct sched_entity *se)
+{
+	rq_inc_bweight(rq, bweights[se->bw_ind]);
+	se->htfs_rq = rq;
+}
+
+/*
+ * enqueue an entity to this runqueue
+ */
+static inline void rq_enqueue(struct htfs_rqs *rqs, struct htfs_rq *rq,
+		struct sched_entity *se)
+{
+	struct htfs_pq *pq;
+	unsigned int new_bw_ind = 0;
+	if (SE_ENQUEUE_NEW == rq_se_get_new_bw_ind(rqs, rq, se, &new_bw_ind))
+		rq_se_set_bw_ind(rq, se, new_bw_ind);
+	pq = &rq->pqs[se->bw_ind];
+	pq_add(rq, pq, se);
+	pq_enqueue(pq, se);
+}
+
+/*
+ * reenqueue an entity to this runqueue. This also takes care of calculating a
+ * new weight
+ */
+static inline void rq_reenqueue(struct htfs_rqs *rqs, struct htfs_rq *rq,
+		struct sched_entity *se)
+{
+	struct htfs_pq *last_pq = &rq->pqs[se->bw_ind];
+	unsigned int new_bw_ind = 0;
+	struct htfs_pq *pq = NULL;
+	enum se_need_newpq status = rq_se_get_new_bw_ind(rqs, rq, se,
+			&new_bw_ind);
+	if (likely(status == SE_REENQUEUE_LAST)) {
+		pq_dequeue(last_pq, se);
+		pq_enqueue(last_pq, se);
+	} else {
+		pq_del(rq, last_pq, se);
+		rq_se_set_bw_ind(rq, se, new_bw_ind);
+		pq = &rq->pqs[se->bw_ind];
+		pq_add(rq, pq, se);
+		pq_enqueue(pq, se);
+	}
+}
+
+/*
+ * dequeue the next entity to schedule
+ *
+ * The function goes through all priorityqueues and looks for a share_ct >= 0.
+ * In this case the next task from that priorityqueue is scheduled
+ */
+static inline struct sched_entity *rq_dequeue_next(struct htfs_rqs *rqs,
+		struct htfs_rq *rq)
+{
+	struct htfs_pq *cur_pq = rq->cur_pq;
+	struct list_head *possible_next = &cur_pq->spqs_real_weight;
+	const unsigned long run_cost = rq->run_cost;
+	const struct list_head *end = &rq->spqs_real_weight;
+	while (cur_pq->balance_ct < run_cost) {
+		possible_next = possible_next->prev;
+		if (unlikely(possible_next == end)) {
+			possible_next = possible_next->prev;
+			cur_pq = list_entry(possible_next, struct htfs_pq,
+					spqs_real_weight);
+			goto dequeue;
+		}
+		cur_pq = list_entry(possible_next, struct htfs_pq,
+				spqs_real_weight);
+		pq_balance_inc(cur_pq);
+	}
+	cur_pq->balance_ct -= rq->run_cost;
+dequeue:
+	rq->cur_pq = cur_pq;
+	return pq_dequeue_next(cur_pq);
+}
+
+
+/******************************************************************************
+ * rqs-operations
+ */
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+
+#define for_each_leaf_htfs_rqs(rq, rqs) \
+	list_for_each_entry_rcu(rqs, &rq->leaf_htfs_rqs_list, leaf_htfs_rqs_list)
+
+static inline void list_add_leaf_htfs_rqs(struct htfs_rqs *rqs)
+{
+	struct task_group *tg = rqs->tg->parent;
+	if (tg) {
+		struct htfs_rqs *parent_rqs = tg->htfs_rqs[cpu_of(rq_of_rqs(rqs))];
+		if (parent_rqs->tasks.next != &parent_rqs->tasks) {
+			list_add_rcu(&rqs->leaf_htfs_rqs_list,
+					&rq_of_rqs(rqs)->leaf_htfs_rqs_list);
+			return;
+		}
+	}
+	list_add_tail_rcu(&rqs->leaf_htfs_rqs_list,
+			&rq_of_rqs(rqs)->leaf_htfs_rqs_list);
+}
+
+static inline void list_del_leaf_htfs_rqs(struct htfs_rqs *rqs)
+{
+	list_del_rcu(&rqs->leaf_htfs_rqs_list);
+}
+
+static inline void rqs_add_if_real(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	if (!entity_is_task(se))
+		return;
+	if (rqs->tasks.next == &rqs->tasks)
+		list_add_leaf_htfs_rqs(rqs);
+	// add_tail to group interactive tasks at the end of the list...
+	// this should increase the probability to choose stable running tasks
+	// for balancing...
+	list_add_tail(&se->group_node, &rqs->tasks);
+}
+
+static inline void rqs_del_if_real(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	if (!entity_is_task(se))
+		return;
+	list_del(&se->group_node);
+	if (rqs->tasks.next == &rqs->tasks)
+		list_del_leaf_htfs_rqs(rqs);
+}
+
+#else /* CONFIG_FAIR_GROUP_SCHED */
+
+static inline void list_add_leaf_htfs_rqs(struct htfs_rqs *rqs)
+{
+}
+
+static inline void list_del_leaf_htfs_rqs(struct htfs_rqs *rqs)
+{
+}
+
+static inline void rqs_add_if_real(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+}
+
+static inline void rqs_del_if_real(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+}
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
+static inline unsigned int
+should_interq(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	if (likely((s64)(se->vruntime - rqs->vtime) <
+			(s64)(se->load.inv_weight << HTFS_STATIC_TIMESLICE_SHIFT)
+			>> (32 - HTFS_VTIME_ACCURACY - HTFS_TH_INTERQ)))
+		return 1;
+	return 0;
+}
+
+/**
+ * Used to enqueue tasks after running on the CPU
+ */
+static inline void rqs_reenqueue(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	struct htfs_rq *rq = htfs_rq_of_se(se);
+	se_update_vruntime(se);
+	if (!se->on_rq)
+		return;
+	if (rq == &rqs->interq) {
+		if (should_interq(rqs, se)) {
+			se->wakeup_time = rqs->rq->clock;
+			rq_reenqueue(rqs, rq, se);
+		} else {
+			se->htfs_state &= ~HTFS_NEED_INTERQ;
+			rq_del(rq, se);
+			rq = &rqs->normalq;
+			rq_add(rq, se);
+			rq_enqueue(rqs, rq, se);
+		}
+	} else {
+		if (unlikely(se->htfs_state & HTFS_NEED_INTERQ)) {
+			se->wakeup_time = rqs->rq->clock;
+			rq_del(rq, se);
+			rq = &rqs->interq;
+			rq_add(rq, se);
+			rq_enqueue(rqs, rq, se);
+		} else {
+			rq_reenqueue(rqs, rq, se);
+		}
+	}
+}
+
+static inline void update_htfs_load_contribution(struct htfs_rqs *rqs,
+					    int global_update);
+static inline void update_htfs_shares(struct htfs_rqs *rqs);
+
+static inline void rqs_add_se_weights(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+#ifdef HTFS_LOAD_AVG
+	rqs->load += se->load_avg;
+#else
+	if (!parent_entity(se))
+		inc_cpu_load(rq_of_rqs(rqs), se->load.weight);
+	rqs->load += se->load.weight;
+#endif
+	rqs->weight += se->load.weight;
+	update_htfs_load_contribution(rqs, 0);
+	update_htfs_shares(rqs);
+}
+
+static inline void rqs_del_se_weights(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+#ifdef HTFS_LOAD_AVG
+	rqs->load -= se->load_avg;
+#else
+	if (!parent_entity(se))
+		dec_cpu_load(rq_of_rqs(rqs), se->load.weight);
+	rqs->load -= se->load.weight;
+#endif
+	rqs->weight -= se->load.weight;
+	update_htfs_load_contribution(rqs, 0);
+	update_htfs_shares(rqs);
+}
+
+static inline void rqs_se_update_weight(struct htfs_rqs *rqs, long weight_diff)
+{
+	rqs->weight += weight_diff;
+}
+
+static inline void rqs_se_update_load_avg(struct htfs_rqs *rqs, struct sched_entity *se,
+		long load_diff)
+{
+#ifdef HTFS_LOAD_AVG
+	rqs->load += load_diff;
+#endif
+}
+
+#ifdef HTFS_OLD_BALANCING
+static void update_htfs_load(struct htfs_rqs *rqs, int global_update);
+#endif
+
+/*
+ * add an entity to the htfs_rqs
+ */
+static inline void
+rqs_add(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	if (unlikely(++rqs->nr_running == 1))
+		rqs_wakeup_load_avg(rqs, rq_of_se(se));
+	rqs_add_se_weights(rqs, se);
+	rqs_add_if_real(rqs, se);
+#ifdef HTFS_OLD_BALANCING
+	update_htfs_load(rqs, 0);
+	update_htfs_shares(rqs);
+#endif
+	if (likely(should_interq(rqs, se))) {
+		se->wakeup_time = rqs->rq->clock;
+		rq_add(&rqs->interq, se);
+		rq_enqueue(rqs, &rqs->interq, se);
+	} else {
+		rq_add(&rqs->normalq, se);
+		rq_enqueue(rqs, &rqs->normalq, se);
+	}
+	se->on_rq = 1;
+}
+
+/*
+ * Remove an entity from the htfs_rqs
+ */
+static inline void
+rqs_del(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	struct htfs_rq *rq = htfs_rq_of_se(se);
+	se_update_runtime(se, rq_of_rqs(rqs));
+	se_update_inter_dequeue(rqs, se);
+	se_update_vruntime(se);
+	se_update_inter_dequeue(rqs, se);
+	if (unlikely(--rqs->nr_running == 0))
+		rqs->offline_start = rq_of_se(se)->clock;
+	rqs_del_se_weights(rqs, se);
+	rq_del(rq, se);
+	se->on_rq = 0;
+	rqs_del_if_real(rqs, se);
+#ifdef HTFS_OLD_BALANCING
+	update_htfs_load(rqs, 0);
+	update_htfs_shares(rqs);
+#endif
+}
+
+
+static inline void rq_run_inter_se(struct rq *rq, struct sched_entity *se)
+{
+	if (!entity_is_task(se))
+		return;
+	if (rq->clock - se->wakeup_time > sysctl_sched_inter_latency)
+		++rq->slice_shrink;
+}
+
+static inline void rqs_update_balance_ct_normal(struct htfs_rqs *rqs)
+{
+	rqs->rq_balance_ct += rqs->interq.bweight
+		<< (rqs->rq->slice_shift - sysctl_sched_inter_slice_shift + 4);
+}
+
+static inline void rqs_update_balance_ct_inter(struct htfs_rqs *rqs)
+{
+	rqs->rq_balance_ct -= rqs->normalq.bweight;
+}
+
+static inline struct sched_entity *rqs_pick_next_full_slice(
+		struct rq *rq, struct htfs_rqs *rqs, int *inter_entity)
+{
+	// TODO on rq add/del update the counter...
+	// TODO more sophisticated interactive queue handling
+	struct sched_entity *se;
+	//if (rqs->rq_balance_ct < 0) { // normal runqueue
+	if (rqs->interq.bweight == 0) {
+		rqs_update_balance_ct_normal(rqs);
+		se = rq_dequeue_next(rqs, &rqs->normalq);
+	} else { // interactive runqueue
+		rqs_update_balance_ct_inter(rqs);
+		se = rq_dequeue_next(rqs, &rqs->interq);
+		rq_run_inter_se(rq, se);
+		*inter_entity = 1;
+	}
+	return se;
+}
+
+static inline struct sched_entity *rqs_pick_next_inter_slice(
+		struct rq *rq, struct htfs_rqs *rqs, int *inter_entity)
+{
+	struct sched_entity *se;
+	if (rqs->interq.bweight != 0) {
+		rqs_update_balance_ct_inter(rqs);
+		se = rq_dequeue_next(rqs, &rqs->interq);
+		rq_run_inter_se(rq, se);
+		*inter_entity = 1;
+	} else {
+		rqs_update_balance_ct_normal(rqs);
+		se = rq_dequeue_next(rqs, &rqs->normalq);
+	}
+	return se;
+}
+
+static inline int rqs_se_move_interq(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	if (should_interq(rqs, se)) {
+		struct htfs_rq *rq = htfs_rq_of_se(se);
+		rq_del(rq, se);
+		rq = &rqs->interq;
+		rq_add(rq, se);
+		rq_enqueue(rqs, rq, se);
+		return 1;
+	}
+	return 0;
+}
+
+static inline int rqs_se_move_normalq(struct htfs_rqs *rqs, struct sched_entity *se)
+{
+	struct htfs_rq *rq = htfs_rq_of_se(se);
+	rq_del(rq, se);
+	rq = &rqs->normalq;
+	rq_add(rq, se);
+	rq_enqueue(rqs, rq, se);
+	return 1;
+}
+
+/******************************************************************************
+ * taskgroup operations
+ */
+
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+#ifdef CONFIG_SMP
+
+#ifdef HTFS_OLD_BALANCING
+
+static void update_htfs_load_contribution(struct htfs_rqs *rqs,
+					    int global_update)
+{
+	struct task_group *tg = rqs->tg;
+	long load_avg;
+
+	load_avg = div64_u64(rqs->load_avg, rqs->load_period+1);
+	load_avg -= rqs->load_contribution;
+
+	if (global_update || abs(load_avg) > rqs->load_contribution / 8) {
+		atomic_add(load_avg, &tg->load_weight);
+		rqs->load_contribution += load_avg;
+	}
+}
+
+static void update_htfs_load(struct htfs_rqs *rqs, int global_update)
+{
+	u64 period = sysctl_sched_shares_window;
+	u64 now, delta;
+	unsigned long load = rqs->load;
+
+	if (rqs->tg == &root_task_group)
+		return;
+
+	now = rq_of_rqs(rqs)->clock_task;
+	delta = now - rqs->load_stamp;
+
+	/* truncate load history at 4 idle periods */
+	if (rqs->load_stamp > rqs->load_last &&
+	    now - rqs->load_last > 4 * period) {
+		rqs->load_period = 0;
+		rqs->load_avg = 0;
+	}
+
+	rqs->load_stamp = now;
+	rqs->load_unacc_exec_time = 0;
+	rqs->load_period += delta;
+	if (load) {
+		rqs->load_last = now;
+		rqs->load_avg += delta * load;
+	}
+
+	/* consider updating load contribution on each fold or truncate */
+	if (global_update || rqs->load_period > period
+	    || !rqs->load_period)
+		update_htfs_load_contribution(rqs, global_update);
+
+	while (rqs->load_period > period) {
+		/*
+		 * Inline assembly required to prevent the compiler
+		 * optimising this loop into a divmod call.
+		 * See __iter_div_u64_rem() for another example of this.
+		 */
+		asm("" : "+rm" (rqs->load_period));
+		rqs->load_period /= 2;
+		rqs->load_avg /= 2;
+	}
+}
+
+static long calc_htfs_shares(struct htfs_rqs *rqs, struct task_group *tg)
+{
+	long load_weight, load, shares;
+
+	load = rqs->load;
+
+	load_weight = atomic_read(&tg->load_weight);
+	load_weight -= rqs->load_contribution;
+	load_weight += load;
+
+	shares = (tg->shares * load);
+	if (load_weight)
+		shares /= load_weight;
+
+	if (shares < MIN_SHARES)
+		shares = MIN_SHARES;
+	if (shares > tg->shares)
+		shares = tg->shares;
+
+	return shares;
+}
+
+static void update_entity_shares_tick(struct htfs_rqs *rqs)
+{
+	if (rqs->load_unacc_exec_time > sysctl_sched_shares_window) {
+		update_htfs_load(rqs, 0);
+		update_htfs_shares(rqs);
+	}
+}
+
+#else
+static inline void update_htfs_load_contribution(struct htfs_rqs *rqs,
+					    int global_update)
+{
+	struct task_group *tg = rqs->tg;
+	long load_avg;
+
+	load_avg = rqs->load_avg;
+	load_avg -= rqs->load_contribution;
+
+	if (global_update || abs(load_avg) > rqs->load_contribution / 8) {
+		atomic_add(load_avg, &tg->load_weight);
+		rqs->load_contribution += load_avg;
+	}
+}
+
+// FIXME is weight_delta somewher != 0?
+static inline long calc_htfs_shares(struct htfs_rqs *rqs, struct task_group *tg)
+{
+	long load_weight, load, shares;
+
+	load = rqs->weight;
+
+	load_weight = atomic_read(&tg->load_weight);
+	load_weight -= rqs->load_contribution;
+	load_weight += load;
+
+	shares = (tg->shares * load);
+	if (load_weight)
+		shares /= load_weight;
+
+	if (shares < MIN_SHARES)
+		shares = MIN_SHARES;
+	if (shares > tg->shares)
+		shares = tg->shares;
+
+	return shares;
+}
+static void update_entity_shares_tick(struct htfs_rqs *rqs)
+{
+
+}
+#endif
+
+# else /* CONFIG_SMP */
+
+static inline long calc_htfs_shares(struct htfs_rqs *rqs, struct task_group *tg)
+{
+	return tg->shares;
+}
+static void update_entity_shares_tick(struct cfs_rq *cfs_rq)
+{
+}
+
+# endif /* CONFIG_SMP */
+static inline void reweight_entity(struct htfs_rqs *rqs, struct sched_entity *se,
+			    unsigned long weight)
+{
+	if (se->on_rq) {
+		// everything is based on bweight... so the bweight will be modified
+		// on next reenqueue
+		rqs_se_update_weight(rqs, weight - se->load.weight);
+	}
+	update_load_set(&se->load, weight);
+}
+
+static inline void update_htfs_shares(struct htfs_rqs *rqs)
+{
+	struct task_group *tg;
+	struct sched_entity *se;
+	long shares;
+
+	tg = rqs->tg;
+	se = tg->se[cpu_of(rq_of_rqs(rqs))];
+	if (!se)
+		return;
+#ifndef CONFIG_SMP
+	if (likely(se->load.weight == tg->shares))
+		return;
+#endif
+	shares = calc_htfs_shares(rqs, tg);
+
+	reweight_entity(rqs_of_se(se), se, shares);
+}
+#else /* CONFIG_FAIR_GROUP_SCHED */
+
+static inline void update_htfs_shares(struct htfs_rqs *rqs)
+{
+}
+
+#endif /* CONFIG_FAIR_GROUP_SCHED */
+
+
+/******************************************************************************
+ * SMP operations not in the interface. Used by code in sched_fair.c
+ */
+
+#ifdef CONFIG_SMP
+
+/*
+ * pull_task - move a task from a remote runqueue to the local runqueue.
+ * Both runqueues must be locked.
+ */
+static inline void pull_task(struct rq *src_rq, struct task_struct *p,
+		      struct rq *this_rq, int this_cpu)
+{
+	// TODO: update hierarchy to reflect the vruntime state of the task
+	deactivate_task(src_rq, p, 0);
+	set_task_cpu(p, this_cpu);
+	activate_task(this_rq, p, ENQUEUE_PRESERVE_INTERACTIVITY);
+	check_preempt_curr(this_rq, p, 0);
+}
+
+/*
+ * can_migrate_task - may task p from runqueue rq be migrated to this_cpu?
+ */
+static
+int can_migrate_task(struct task_struct *p, struct rq *rq, int this_cpu,
+		     struct sched_domain *sd, enum cpu_idle_type idle,
+		     int *all_pinned)
+{
+	int tsk_cache_hot = 0;
+	/*
+	 * We do not migrate tasks that are:
+	 * 1) running (obviously), or
+	 * 2) cannot be migrated to this CPU due to cpus_allowed, or
+	 * 3) are cache-hot on their current CPU.
+	 */
+	if (!cpumask_test_cpu(this_cpu, &p->cpus_allowed)) {
+		schedstat_inc(p, se.statistics.nr_failed_migrations_affine);
+		return 0;
+	}
+	*all_pinned = 0;
+
+	if (task_running(rq, p)) {
+		schedstat_inc(p, se.statistics.nr_failed_migrations_running);
+		return 0;
+	}
+
+	/*
+	 * Aggressive migration if:
+	 * 1) task is cache cold, or
+	 * 2) too many balance attempts have failed.
+	 */
+
+	tsk_cache_hot = task_hot(p, rq->clock_task, sd);
+	if (!tsk_cache_hot ||
+		sd->nr_balance_failed > sd->cache_nice_tries) {
+#ifdef CONFIG_SCHEDSTATS
+		if (tsk_cache_hot) {
+			schedstat_inc(sd, lb_hot_gained[idle]);
+			schedstat_inc(p, se.statistics.nr_forced_migrations);
+		}
+#endif
+		return 1;
+	}
+
+	if (tsk_cache_hot) {
+		schedstat_inc(p, se.statistics.nr_failed_migrations_hot);
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * move_one_task tries to move exactly one task from busiest to this_rq, as
+ * part of active balancing operations within "domain".
+ * Returns 1 if successful and 0 otherwise.
+ *
+ * Called with both runqueues locked.
+ */
+static inline int
+move_one_task(struct rq *this_rq, int this_cpu, struct rq *busiest,
+	      struct sched_domain *sd, enum cpu_idle_type idle)
+{
+	struct task_struct *p, *n;
+	struct htfs_rqs *rqs;
+	int pinned = 0;
+
+	for_each_leaf_htfs_rqs(busiest, rqs) {
+		list_for_each_entry_safe(p, n, &rqs->tasks, se.group_node) {
+
+			if (!can_migrate_task(p, busiest, this_cpu,
+						sd, idle, &pinned))
+				continue;
+
+			pull_task(busiest, p, this_rq, this_cpu);
+			/*
+			 * Right now, this is only the second place pull_task()
+			 * is called, so we can safely collect pull_task()
+			 * stats here rather than inside pull_task().
+			 */
+			schedstat_inc(sd, lb_gained[idle]);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static unsigned long
+balance_tasks(struct rq *this_rq, int this_cpu, struct rq *busiest,
+	      unsigned long max_load_move, struct sched_domain *sd,
+	      enum cpu_idle_type idle, int *all_pinned,
+	      int *this_best_prio, struct htfs_rqs *busiest_rqs)
+{
+	int loops = 0, pulled = 0;
+	long rem_load_move = max_load_move;
+	struct task_struct *p, *n;
+
+	if (max_load_move == 0)
+		goto out;
+
+	list_for_each_entry_safe(p, n, &busiest_rqs->tasks, se.group_node) {
+		if (loops++ > sysctl_sched_nr_migrate)
+			break;
+#ifdef HTFS_LOAD_AVG
+		if ((p->se.load_avg >> 1) > rem_load_move ||
+		    !can_migrate_task(p, busiest, this_cpu, sd, idle,
+				      all_pinned))
+			continue;
+#else
+		if ((p->se.load.weight >> 1) > rem_load_move ||
+		    !can_migrate_task(p, busiest, this_cpu, sd, idle,
+				      all_pinned))
+			continue;
+#endif
+
+		pull_task(busiest, p, this_rq, this_cpu);
+		pulled++;
+#ifdef HTFS_LOAD_AVG
+		rem_load_move -= p->se.load_avg;
+#else
+		rem_load_move -= p->se.load.weight;
+#endif
+
+#ifdef CONFIG_PREEMPT
+		/*
+		 * NEWIDLE balancing is a source of latency, so preemptible
+		 * kernels will stop after the first task is pulled to minimize
+		 * the critical section.
+		 */
+		if (idle == CPU_NEWLY_IDLE)
+			break;
+#endif
+
+		/*
+		 * We only want to steal up to the prescribed amount of
+		 * weighted load.
+		 */
+		if (rem_load_move <= 0)
+			break;
+
+		if (p->prio < *this_best_prio)
+			*this_best_prio = p->prio;
+	}
+out:
+	/*
+	 * Right now, this is one of only two places pull_task() is called,
+	 * so we can safely collect pull_task() stats here rather than
+	 * inside pull_task().
+	 */
+	schedstat_add(sd, lb_gained[idle], pulled);
+
+	return max_load_move - rem_load_move;
+}
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+/*
+ * update tg->load_weight by folding this cpu's load_avg
+ */
+static int update_shares_cpu(struct task_group *tg, int cpu)
+{
+	struct htfs_rqs *rqs;
+	unsigned long flags;
+	struct rq *rq;
+
+	if (!tg->se[cpu])
+		return 0;
+
+	rq = cpu_rq(cpu);
+	rqs = tg->htfs_rqs[cpu];
+
+	raw_spin_lock_irqsave(&rq->lock, flags);
+
+	update_rq_clock(rq);
+#ifdef HTFS_OLD_BALANCING
+	update_htfs_load(rqs, 1);
+#else
+	update_htfs_load_contribution(rqs, 1);
+#endif
+
+	/*
+	 * We need to update shares after updating tg->load_weight in
+	 * order to adjust the weight of groups with long running tasks.
+	 */
+	update_htfs_shares(rqs);
+
+	raw_spin_unlock_irqrestore(&rq->lock, flags);
+
+	return 0;
+}
+
+static void update_shares(int cpu)
+{
+	struct htfs_rqs *rqs;
+	struct rq *rq = cpu_rq(cpu);
+
+	rcu_read_lock();
+	for_each_leaf_htfs_rqs(rq, rqs)
+		update_shares_cpu(rqs->tg, cpu);
+	rcu_read_unlock();
+}
+
+/*
+ * Compute the cpu's hierarchical load factor for each task group.
+ * This needs to be done in a top-down fashion because the load of a child
+ * group is a fraction of its parents load.
+ */
+static int tg_load_down(struct task_group *tg, void *data)
+{
+	unsigned long load;
+	long cpu = (long)data;
+
+	if (!tg->parent) {
+		load = cpu_rq(cpu)->load.weight;
+	} else {
+		load = tg->parent->htfs_rqs[cpu]->h_load;
+		load *= tg->se[cpu]->load.weight;
+		load /= tg->parent->htfs_rqs[cpu]->weight + 1;
+	}
+
+	tg->htfs_rqs[cpu]->h_load = load;
+
+	return 0;
+}
+
+static void update_h_load(long cpu)
+{
+	walk_tg_tree(tg_load_down, tg_nop, (void *)cpu);
+}
+
+static inline unsigned long
+load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
+		  unsigned long max_load_move,
+		  struct sched_domain *sd, enum cpu_idle_type idle,
+		  int *all_pinned, int *this_best_prio)
+{
+	long rem_load_move = max_load_move;
+	int busiest_cpu = cpu_of(busiest);
+	struct task_group *tg;
+
+	rcu_read_lock();
+	update_h_load(busiest_cpu);
+
+	list_for_each_entry_rcu(tg, &task_groups, list) {
+		struct htfs_rqs *busiest_rqs = tg->htfs_rqs[busiest_cpu];
+		unsigned long busiest_h_load = busiest_rqs->h_load;
+		unsigned long busiest_weight = busiest_rqs->weight;
+		u64 rem_load, moved_load;
+
+		/*
+		 * empty group
+		 */
+		if (&busiest_rqs->tasks == busiest_rqs->tasks.next)
+			continue;
+
+		rem_load = (u64)rem_load_move * busiest_weight;
+		rem_load = div_u64(rem_load, busiest_h_load + 1);
+
+		moved_load = balance_tasks(this_rq, this_cpu, busiest,
+				rem_load, sd, idle, all_pinned, this_best_prio,
+				busiest_rqs);
+
+		if (!moved_load)
+			continue;
+
+		moved_load *= busiest_h_load;
+		moved_load = div_u64(moved_load, busiest_weight + 1);
+
+		rem_load_move -= moved_load;
+		if (rem_load_move < 0)
+			break;
+	}
+	rcu_read_unlock();
+
+	return max_load_move - rem_load_move;
+}
+#else
+static inline void update_shares(int cpu)
+{
+}
+
+static inline unsigned long
+load_balance_fair(struct rq *this_rq, int this_cpu, struct rq *busiest,
+		  unsigned long max_load_move,
+		  struct sched_domain *sd, enum cpu_idle_type idle,
+		  int *all_pinned, int *this_best_prio)
+{
+	return balance_tasks(this_rq, this_cpu, busiest,
+			max_load_move, sd, idle, all_pinned,
+			this_best_prio, &busiest->htfs_rqs);
+}
+#endif
+#endif
+/******************************************************************************
+ * interface task operations
+ */
+
+/*
+ * New task to enqueue on the runqueue
+ */
+static void enqueue_task_htfs(struct rq *rq, struct task_struct *p, int flags)
+{
+	struct htfs_rqs *rqs;
+	struct sched_entity *se = &p->se;
+	int all_inter = 1;
+	if (unlikely(se->load.inv_weight == 0))
+		se->load.inv_weight = calc_inv_weight(se->load.weight);
+	if (flags & (ENQUEUE_WAKEUP | ENQUEUE_WAKING)) {
+		for_each_sched_entity(se) {
+			if (se->on_rq)
+				break;
+			rqs = rqs_of_se(se);
+			se_wakeup_set_vruntime(rqs, se);
+			se->htfs_state = 0;
+			rqs_add(rqs, se);
+			if (all_inter && !se_is_on_interq(se))
+				all_inter = 0;
+		}
+	} else if (flags & ENQUEUE_PRESERVE_INTERACTIVITY) {
+		for_each_sched_entity(se) {
+			if (se->on_rq)
+				break;
+			rqs = rqs_of_se(se);
+			se->vruntime = rqs->vtime;
+			se->htfs_state = 0;
+			rqs_add(rqs, se);
+			if (all_inter && !se_is_on_interq(se))
+				all_inter = 0;
+		}
+	} else {
+		for_each_sched_entity(se) {
+			if (se->on_rq)
+				break;
+			rqs = rqs_of_se(se);
+			se->vruntime = rqs->vtime - (((u64)se->load.inv_weight
+				<< HTFS_STATIC_TIMESLICE_SHIFT)
+				>> (32 - HTFS_VTIME_ACCURACY));
+			se->htfs_state = 0;
+			se->bw_ind = se_find_bw_ind(se) - 1;
+#ifdef HTFS_LOAD_AVG
+			se->load_avg = se->load.weight >> 1;
+#endif
+			se_inter_init(rqs, se);
+			rqs_add(rqs, se);
+			if (all_inter && !se_is_on_interq(se))
+				all_inter = 0;
+		}
+	}
+	if (unlikely(all_inter && sched_feat(WAKEUP_PULL_INTERQ))) {
+		// all entities could be enqueed on the interactive queue...
+		// so we try to move all entities above this to the interactive
+		// queues
+		for_each_sched_entity(se) {
+			rqs = rqs_of_se(se);
+
+			if (!se_is_on_interq(se)) {
+				if (!rqs_se_move_interq(rqs, se))
+					break;
+			}
+#ifdef HTFS_OLD_BALANCING
+			update_htfs_load(rqs, 0);
+#else
+			update_htfs_load_contribution(rqs, 0);
+#endif
+			update_htfs_shares(rqs);
+		}
+	}
+	for_each_sched_entity(se) {
+		rqs = rqs_of_se(se);
+#ifdef HTFS_OLD_BALANCING
+		update_htfs_load(rqs, 0);
+#else
+		update_htfs_load_contribution(rqs, 0);
+#endif
+		update_htfs_shares(rqs);
+	}
+
+}
+
+/*
+ * Remove a task from the runqueue
+ */
+static void dequeue_task_htfs(struct rq *rq, struct task_struct *p, int flags)
+{
+	struct sched_entity *se = &p->se;
+	struct htfs_rqs *rqs;
+	if (rq->continue_run == p) {
+		rq->continue_run = NULL;
+	}
+	for_each_sched_entity(se) {
+		rqs = rqs_of_se(se);
+		rqs_del(rqs, se);
+		if (rqs->nr_running) {
+			if (unlikely(!rqs->interq.bweight && sched_feat(WAKEUP_PULL_INTERQ)))
+				goto interq_empty;
+			else
+				break;
+		}
+	}
+	if (0) {
+		// Lets remove the entities in the above hierarchy from
+		// the interq if there is no real interactive task anymore
+		for_each_sched_entity(se) {
+			rqs = rqs_of_se(se);
+			
+			if (se_is_on_interq(se)) {
+				if (!rqs_se_move_normalq(rqs, se))
+					return;
+			} else {
+				break;
+			}
+
+			if (rqs->interq.bweight)
+				break;
+interq_empty:
+#ifdef HTFS_OLD_BALANCING
+			update_htfs_load(rqs, 0);
+#else
+			update_htfs_load_contribution(rqs, 0);
+#endif
+			update_htfs_shares(rqs);
+		}
+	}
+	for_each_sched_entity(se) {
+		rqs = rqs_of_se(se);
+
+#ifdef HTFS_OLD_BALANCING
+		update_htfs_load(rqs, 0);
+#else
+		update_htfs_load_contribution(rqs, 0);
+#endif
+		update_htfs_shares(rqs);
+	}
+}
+
+static struct task_struct *pick_next_task_htfs(struct rq *rq)
+{
+	struct htfs_rqs *rqs = &rq->htfs_rqs;
+	struct sched_entity *se;
+	u64 slice;
+	int inter_entity = 0;
+	if (unlikely(rqs->nr_running == 0)) {
+		return NULL;
+	}
+	if (rq->continue_run) {
+		struct task_struct *to_run = rq->continue_run;
+		rq->continue_run = NULL;
+		return to_run;
+	}
+	if (rq->slice_remain < sched_inter_slice) {
+		rq->slice_remain = rq->slice;
+		slice = rq->slice;
+		do {
+			se = rqs_pick_next_full_slice(rq, rqs, &inter_entity);
+			se_start_exec(se, rq);
+			if (unlikely(inter_entity))
+				goto changed_to_inter;
+#ifdef CONFIG_FAIR_GROUP_SCHED
+			rqs = se->my_q;
+#else
+			break;
+#endif
+		} while(rqs);
+	} else {
+		// We have obviously a fraction of a complete timeslice remaining
+		// Now we are giving the remaining to other interactive tasks
+		do {
+			se = rqs_pick_next_inter_slice(rq, rqs, &inter_entity);
+			se_start_exec(se, rq);
+changed_to_inter:
+#ifdef CONFIG_FAIR_GROUP_SCHED
+			rqs = se->my_q;
+#else
+			break;
+#endif
+		} while(rqs);
+		if (inter_entity)
+			slice = sched_inter_slice;
+		else
+			slice = rq->slice_remain;
+	}
+	rq->slice_granted = slice;
+#ifdef CONFIG_SCHED_HRTICK
+	if (hrtick_enabled(rq))
+		hrtick_start(rq, slice);
+#endif
+	return task_of(se);
+}
+
+#define HTFS_SAME_CALL_DIFF (1UL << 5)
+#define HTFS_SMALL_DIFF (1UL << 8)
+#define HTFS_MAX_CONTINUES 20
+
+static void put_prev_task_htfs(struct rq *rq, struct task_struct *prev)
+{
+	struct htfs_rqs *rqs;
+	struct sched_entity *se = &prev->se;
+	s64 min_remaining = rq->slice_granted;
+	s64 remain = 0;
+	u64 call_diff = rq->clock - rq->last_call;
+	rq->last_call = rq->clock;
+	if (likely(sched_feat(PROB_RERUN))) {
+		if (rq->force_sched) {
+			rq->force_sched = 0;
+			goto resched;
+		}
+		for_each_sched_entity(se) {
+			if (!se->on_rq) {
+				rq->call_time_diff = 0;
+				return;
+			}
+			remain = se_update_runtime(se, rq);
+			if (min_remaining > remain)
+				min_remaining = remain;
+		}
+		if (min_remaining <= 0) {
+			goto resched;
+		}
+		if (unlikely(rq->continues >= HTFS_MAX_CONTINUES)) {
+			goto resched;
+		} else if (unlikely(abs((s64)call_diff - rq->call_time_diff)
+				< HTFS_SAME_CALL_DIFF)) {
+			goto resched;
+		} else if (unlikely(call_diff < HTFS_SMALL_DIFF)) {
+			goto resched;
+		}
+		goto continue_run;
+	}
+resched:
+	rq->call_time_diff = 0;
+	rq->continues = 0;
+	se = &prev->se;
+	for_each_sched_entity(se) {
+		rqs = rqs_of_se(se);
+		rqs_update_load_avg(rqs);
+		rqs_reenqueue(rqs, se);
+	}
+	return;
+
+continue_run:
+	rq->call_time_diff = call_diff;
+	rq->continue_run = prev;
+	++rq->continues;
+#ifdef CONFIG_SCHED_HRTICK
+	if (hrtick_enabled(rq))
+		hrtick_start(rq, min_remaining);
+#endif
+	return;
+}
+
+static void yield_task_htfs(struct rq *rq)
+{
+	// TODO: perhaps push the interactivity more?
+}
+
+static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int flags)
+{
+	// TODO... interrupt only long running tasks and so on...
+	// specify a special task for next run from interq?
+	struct task_struct *curr = rq->curr;
+	struct sched_entity *se = &curr->se, *pse = &p->se;
+	s64 remaining = se_update_runtime(se, rq);
+
+	if (unlikely(se == pse))
+		return;
+
+	/*
+	 * The currently running task is obviously a interactive task
+	 */
+	if (rq->slice_granted == sched_inter_slice)
+		return;
+	/*
+	 * don't preempt if the remaining slice is smaller than the interactive
+	 * timeslice
+	 */
+	if (remaining < sched_inter_slice)
+		return;
+	/*
+	 * We can come here with TIF_NEED_RESCHED already set from new task
+	 * wake up path.
+	 */
+	if (test_tsk_need_resched(curr))
+		return;
+
+	/*
+	 * Batch and idle tasks do not preempt (their preemption is driven by
+	 * the tick):
+	 */
+	if (unlikely(p->policy != SCHED_NORMAL))
+		return;
+
+	/* Idle tasks are by definition preempted by everybody. */
+	if (unlikely(curr->policy == SCHED_IDLE))
+		goto preempt;
+
+	if (!sched_feat(WAKEUP_PREEMPT))
+		return;
+
+preempt:
+	for_each_sched_entity(se) {
+		se->htfs_state |= HTFS_PREEMPTED;
+	}
+	rq->force_sched = 1;
+	resched_task(curr);
+}
+
+static void set_curr_task_htfs(struct rq *rq)
+{
+	// nothing to do because all calls to this function are after the call
+	// of dequeue_task...
+	// further running shouldn't make any problems
+}
+
+
+static void slice_dec(struct rq *rq)
+{
+	if (rq->slice_shift != sysctl_sched_inter_slice_shift) {
+		--rq->slice_shift;
+		rq->slice = (1UL << rq->slice_shift);
+	}
+	rq->slice_change_last = rq->clock;
+}
+
+static void slice_inc(struct rq *rq)
+{
+	if (rq->slice_shift != sysctl_sched_slice_max_shift) {
+		++rq->slice_shift;
+		rq->slice = (1UL << rq->slice_shift);
+	}
+	rq->slice_change_last = rq->clock;
+}
+
+#define HTFS_SLICE_SHRINK_THR 1
+#define HTFS_SLICE_SHRINK_DEC_INT 10000000UL
+#define HTFS_SLICE_INC_AFTER 100000000UL
+
+static void task_tick_htfs(struct rq *rq, struct task_struct *p, int queued)
+{
+	struct sched_entity *se = &p->se;
+	struct htfs_rqs *rqs = &rq->htfs_rqs;
+	s64 min_remaining = rqs->rq->slice_granted;
+	if (likely(sched_feat(DYNAMIC_TIMESLICE))) {
+		if (rq->slice_shrink > HTFS_SLICE_SHRINK_THR) {
+			rq->slice_shrink = 0;
+			rq->slice_shrink_last_dec = rq->clock;
+			slice_dec(rq);
+		} else if ((s64) (rq->clock - rq->slice_shrink_last_dec) >
+				HTFS_SLICE_SHRINK_DEC_INT) {
+			if (!rq->slice_shrink && rq->clock - rq->slice_change_last
+					> HTFS_SLICE_INC_AFTER) {
+				slice_inc(rq);
+			}
+			rq->slice_shrink >>= 1;
+			rq->slice_shrink_last_dec = rq->clock;
+		}
+	}
+/*	if (++rqs->dbg_counter == 25) {
+		rqs->dbg_counter = 0;
+		rqs_dump(rqs, 0);
+	}*/
+	//TODO don't reschedule with only one task active
+	for_each_sched_entity(se) {
+		update_entity_shares_tick(rqs_of_se(se));
+	}
+#ifdef CONFIG_SCHED_HRTICK
+	if (queued) {
+		rq->force_sched = 1;
+		resched_task(rq->curr);
+		return;
+	}
+	if (!sched_feat(DOUBLE_TICK) &&
+			hrtimer_active(&rq->hrtick_timer))
+		return;
+#endif
+	se = &p->se;
+	for_each_sched_entity(se) {
+		s64 remaining = se_update_runtime(se, rq);
+		min_remaining = min(min_remaining, remaining);
+	}
+	if (min_remaining <= 0) {
+		rq->force_sched = 1;
+		resched_task(rq->curr);
+	}
+}
+
+static void switched_to_htfs(struct rq *this_rq, struct task_struct *task,
+			     int running)
+{
+	if (running) {
+		this_rq->force_sched = 1;
+		resched_task(this_rq->curr);
+	}
+}
+
+static void prio_changed_htfs(struct rq *this_rq, struct task_struct *task,
+			     int oldprio, int running)
+{
+}
+
+static unsigned int get_rr_interval_htfs(struct rq *rq, struct task_struct *task)
+{
+	return NS_TO_JIFFIES(rqs_of_se(&task->se)->rq->slice);
+}
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+static void task_move_group_htfs(struct task_struct *p, int on_rq)
+{
+	p->se.vruntime -= rqs_of_se(&p->se)->vtime;
+	set_task_rq(p, task_cpu(p));
+	p->se.vruntime += rqs_of_se(&p->se)->vtime;
+}
+#endif
+
+/*static void task_fork_fair(struct task_struct *p)
+{
+	int this_cpu = smp_processor_id();
+	struct rq *rq = this_rq();
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&rq->lock, flags);
+
+	rq->force_sched = 1;
+	resched_task(rq->curr);
+
+	if (unlikely(task_cpu(p) != this_cpu)) {
+		rcu_read_lock();
+		__set_task_cpu(p, this_cpu);
+		rcu_read_unlock();
+	}
+
+	raw_spin_unlock_irqrestore(&rq->lock, flags);
+}*/
+
+static const struct sched_class fair_sched_class = {
+	.next			= &idle_sched_class,
+	.enqueue_task		= enqueue_task_htfs,
+	.dequeue_task		= dequeue_task_htfs,
+	.yield_task		= yield_task_htfs,
+
+	.check_preempt_curr	= check_preempt_wakeup,
+
+	.pick_next_task		= pick_next_task_htfs,
+	.put_prev_task		= put_prev_task_htfs,
+
+#ifdef CONFIG_SMP
+	.select_task_rq		= select_task_rq_fair,
+	.rq_online		= rq_online_fair,
+	.rq_offline		= rq_offline_fair,
+
+#endif
+
+	.set_curr_task          = set_curr_task_htfs,
+	.task_tick		= task_tick_htfs,
+//	.task_fork		= task_fork_fair,
+
+	.prio_changed		= prio_changed_htfs,
+	.switched_to		= switched_to_htfs,
+
+	.get_rr_interval	= get_rr_interval_htfs,
+
+#ifdef CONFIG_FAIR_GROUP_SCHED
+	.task_move_group	= task_move_group_htfs,
+#endif
+};
+
+
+#ifdef CONFIG_SCHED_DEBUG
+
+extern void print_htfs_rqs(struct seq_file *m, int cpu, struct htfs_rqs *rqs);
+
+static void print_htfs_stats(struct seq_file *m, int cpu)
+{
+	struct htfs_rqs *rqs;
+
+	rcu_read_lock();
+	for_each_leaf_htfs_rqs(cpu_rq(cpu), rqs)
+		print_htfs_rqs(m, cpu, rqs);
+	rcu_read_unlock();
+}
+#endif
+
+#endif /* CONFIG_SCHED_FAIR_HTFS */
diff --git a/kernel/sched_features.h b/kernel/sched_features.h
index 68e69ac..b0eda12 100644
--- a/kernel/sched_features.h
+++ b/kernel/sched_features.h
@@ -64,3 +64,23 @@ SCHED_FEAT(OWNER_SPIN, 1)
  * Decrement CPU power based on irq activity
  */
 SCHED_FEAT(NONIRQ_POWER, 1)
+
+#ifdef CONFIG_SCHED_FAIR_HTFS
+
+/*
+ * Try to pull all sched entities in the hierarchy on the interactive runqueues
+ * on wakeup
+ */
+SCHED_FEAT(WAKEUP_PULL_INTERQ, 1)
+
+/*
+ * Automatic changing of timeslices
+ */
+SCHED_FEAT(DYNAMIC_TIMESLICE, 1)
+
+/*
+ * Tries to continue running current task (in case a lock is freed on another processor
+ */
+SCHED_FEAT(PROB_RERUN, 1)
+
+#endif
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 443fd20..7ff58a1 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -256,6 +256,7 @@ static struct ctl_table root_table[] = {
 };
 
 #ifdef CONFIG_SCHED_DEBUG
+#ifdef CONFIG_SCHED_FAIR_CFS
 static int min_sched_granularity_ns = 100000;		/* 100 usecs */
 static int max_sched_granularity_ns = NSEC_PER_SEC;	/* 1 second */
 static int min_wakeup_granularity_ns;			/* 0 usecs */
@@ -263,6 +264,7 @@ static int max_wakeup_granularity_ns = NSEC_PER_SEC;	/* 1 second */
 static int min_sched_tunable_scaling = SCHED_TUNABLESCALING_NONE;
 static int max_sched_tunable_scaling = SCHED_TUNABLESCALING_END-1;
 #endif
+#endif
 
 #ifdef CONFIG_COMPACTION
 static int min_extfrag_threshold;
@@ -270,6 +272,7 @@ static int max_extfrag_threshold = 1000;
 #endif
 
 static struct ctl_table kern_table[] = {
+#ifdef CONFIG_SCHED_FAIR_CFS
 	{
 		.procname	= "sched_child_runs_first",
 		.data		= &sysctl_sched_child_runs_first,
@@ -352,6 +355,29 @@ static struct ctl_table kern_table[] = {
 		.extra2		= &one,
 	},
 #endif
+#elif CONFIG_SCHED_FAIR_HTFS
+	{
+		.procname	= "sched_inter_timeslice_shift",
+		.data		= &sysctl_sched_inter_slice_shift,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= sched_proc_update_handler,
+	},
+	{
+		.procname	= "sched_inter_latency",
+		.data		= &sysctl_sched_inter_latency,
+		.maxlen		= sizeof(u64),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+	{
+		.procname	= "sched_timeslice_max_shift",
+		.data		= &sysctl_sched_slice_max_shift,
+		.maxlen		= sizeof(unsigned int),
+		.mode		= 0644,
+		.proc_handler	= proc_dointvec,
+	},
+#endif
 	{
 		.procname	= "sched_rt_period_us",
 		.data		= &sysctl_sched_rt_period,
@@ -366,6 +392,7 @@ static struct ctl_table kern_table[] = {
 		.mode		= 0644,
 		.proc_handler	= sched_rt_handler,
 	},
+#ifdef CONFIG_SCHED_FAIR_CFS
 	{
 		.procname	= "sched_compat_yield",
 		.data		= &sysctl_sched_compat_yield,
@@ -373,6 +400,7 @@ static struct ctl_table kern_table[] = {
 		.mode		= 0644,
 		.proc_handler	= proc_dointvec,
 	},
+#endif
 #ifdef CONFIG_SCHED_AUTOGROUP
 	{
 		.procname	= "sched_autogroup_enabled",
