--- linux-2.6.1-O21/kernel/sched.c 2004-01-20 21:27:11.000000000 +1100 +++ linux-2.6.1-hto1/kernel/sched.c 2004-01-24 23:20:46.871705035 +1100 @@ -208,6 +208,7 @@ struct runqueue { atomic_t *node_nr_running; int prev_node_load[MAX_NUMNODES]; #endif + unsigned long cpu; task_t *migration_thread; struct list_head migration_queue; @@ -221,6 +222,10 @@ static DEFINE_PER_CPU(struct runqueue, r #define task_rq(p) cpu_rq(task_cpu(p)) #define cpu_curr(cpu) (cpu_rq(cpu)->curr) +#define ht_active (cpu_has_ht && smp_num_siblings > 1) +#define ht_siblings(cpu1, cpu2) (ht_active && \ + cpu_sibling_map[(cpu1)] == (cpu2)) + /* * Default context-switch locking: */ @@ -1159,8 +1164,9 @@ can_migrate_task(task_t *tsk, runqueue_t { unsigned long delta = sched_clock() - tsk->timestamp; - if (!idle && (delta <= JIFFIES_TO_NS(cache_decay_ticks))) - return 0; + if (!idle && (delta <= JIFFIES_TO_NS(cache_decay_ticks)) && + !ht_siblings(this_cpu, task_cpu(tsk))) + return 0; if (task_running(rq, tsk)) return 0; if (!cpu_isset(this_cpu, tsk->cpus_allowed)) @@ -1195,15 +1201,23 @@ static void load_balance(runqueue_t *thi imbalance /= 2; /* + * For hyperthread siblings take tasks from the active array + * to get cache-warm tasks since they share caches. + */ + if (ht_siblings(this_cpu, busiest->cpu)) + array = busiest->active; + /* * We first consider expired tasks. Those will likely not be * executed in the near future, and they are most likely to * be cache-cold, thus switching CPUs has the least effect * on them. */ - if (busiest->expired->nr_active) - array = busiest->expired; - else - array = busiest->active; + else { + if (busiest->expired->nr_active) + array = busiest->expired; + else + array = busiest->active; + } new_array: /* Start searching at priority 0: */ @@ -1214,9 +1228,16 @@ skip_bitmap: else idx = find_next_bit(array->bitmap, MAX_PRIO, idx); if (idx >= MAX_PRIO) { - if (array == busiest->expired) { - array = busiest->active; - goto new_array; + if (ht_siblings(this_cpu, busiest->cpu)){ + if (array == busiest->active) { + array = busiest->expired; + goto new_array; + } + } else { + if (array == busiest->expired) { + array = busiest->active; + goto new_array; + } } goto out_unlock; } @@ -1540,6 +1561,20 @@ need_resched: if (!rq->nr_running) { next = rq->idle; rq->expired_timestamp = 0; +#ifdef CONFIG_SMP + if (ht_active) { + /* + * If a HT sibling task is sleeping due to + * priority reasons wake it up now + */ + runqueue_t *htrq; + htrq = cpu_rq(cpu_sibling_map[(rq->cpu)]); + + if (htrq->curr == htrq->idle && + htrq->nr_running) + resched_task(htrq->idle); + } +#endif goto switch_tasks; } } @@ -1560,6 +1595,47 @@ need_resched: queue = array->queue + idx; next = list_entry(queue->next, task_t, run_list); +#ifdef CONFIG_SMP + if (ht_active && next->mm && !rt_task(next)) { + runqueue_t *htrq; + htrq = cpu_rq(cpu_sibling_map[(rq->cpu)]); + task_t *htcurr; + htcurr = htrq->curr; + + if (likely(htcurr->mm && !rt_task(htcurr))){ + /* + * If a user task with >10 dynamic + + * static priority difference from another + * running user task on the hyperthread sibling + * is trying to schedule, delay it to prevent a + * lower priority task from using an unfair + * proportion of the physical cpu resources. + */ + if (next->prio + next->static_prio > + htcurr->prio + htcurr->static_prio + 10) { + next = rq->idle; + goto switch_tasks; + } + + /* + * Reschedule a lower priority task + * on the HT sibling if present. + */ + if (htcurr->prio + htcurr->static_prio > + next->prio + next->static_prio + 10) + resched_task(htcurr); + else + /* + * If a HT sibling task has been put to sleep + * previously for priority reasons wake it up + * now. + */ + if (htcurr == htrq->idle && htrq->nr_running) + resched_task(htcurr); + } + } +#endif + if (next->activated > 0) { unsigned long long delta = now - next->timestamp; @@ -2814,6 +2890,7 @@ void __init sched_init(void) prio_array_t *array; rq = cpu_rq(i); + rq->cpu = (unsigned long)(i); rq->active = rq->arrays; rq->expired = rq->arrays + 1; rq->best_expired_prio = MAX_PRIO;