2011年8月7日 星期日

Process Scheduling - 4

一般行程的優先順序的值是 100 (highest priority) 至 139 (lowest priority),行程一開始時會被賦予初始的優先順序,
稱為 static priority;之後在執行的期間,排程器會藉由動態增減的方式來調整優先順序,此為 dynamic priority。

real-time 行程的優先順序則是 1 (highest priority) 至 99 (lowest priority),又稱為 real-time priority。

Static priority
用來決定行程的 CPU 使用時間(base time quantum),優先順序愈高(數字愈小),執行時間也就愈長。
行程的 static priority 是繼承其父行程而來,也可以藉由設定 nice 值來做修改。


Dynamic priority
作為排程器挑選行程來執行的優先順序,dynamic priority 會在行程執行期間隨 bonus 值調整。
bonus 是一個 0 至 10 的數值;小於 5 時,表示對行程的優先權做調降;大於 5 時,則是做調升。

下表列出與行程的優先權相關的參數:


定義於 include/linux/sched.h

/*
* Priority of a process goes from 0..MAX_PRIO-1, valid RT
* priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL tasks are
* in the range MAX_RT_PRIO..MAX_PRIO-1. Priority values
* are inverted: lower p->prio value means higher priority.
*
* The MAX_USER_RT_PRIO value allows the actual maximum
* RT priority to be separate from the value exported to
* user-space. This allows kernel threads to set their
* priority to a value higher than any user task. Note:
* MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
*/

#define MAX_USER_RT_PRIO  100
#define MAX_RT_PRIO      MAX_USER_RT_PRIO

#define MAX_PRIO       (MAX_RT_PRIO + 40)

#define rt_task(p)        (unlikely((p)->prio < MAX_RT_PRIO))



定義於 kernel/sched.c

/*
* Convert user-nice values [ -20 ... 0 ... 19 ]
* to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
* and back.
*/
#define NICE_TO_PRIO(nice) (MAX_RT_PRIO + (nice) + 20)
#define PRIO_TO_NICE(prio) ((prio) - MAX_RT_PRIO - 20)
#define TASK_NICE(p)    PRIO_TO_NICE((p)->static_prio)

/*
* 'User priority' is the nice value converted to something we
* can work with better when scaling various scheduler parameters,
* it's a [ 0 ... 39 ] range.
*/
#define USER_PRIO(p)    ((p)-MAX_RT_PRIO)
#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio)
#define MAX_USER_PRIO  (USER_PRIO(MAX_PRIO))

/*
* task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
* to time slice values: [800ms ... 100ms ... 5ms]
*
* The higher a thread's priority, the bigger timeslices
* it gets during one round of execution. But even the lowest
* priority thread gets MIN_TIMESLICE worth of execution time.
*/

#define SCALE_PRIO(x, prio) \
 max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)

static unsigned int task_timeslice(task_t *p)
{
 if (p->static_prio < NICE_TO_PRIO(0))
  return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);
 else
  return SCALE_PRIO(DEF_TIMESLICE, p->static_prio);
}

/*
* effective_prio - return the priority that is based on the static
* priority but is modified by bonuses/penalties.
*
* We scale the actual sleep average [0 .... MAX_SLEEP_AVG]
* into the -5 ... 0 ... +5 bonus/penalty range.
*
* We use 25% of the full 0...39 priority range so that:
*
* 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs.
* 2) nice -20 CPU hogs do not get preempted by nice 0 tasks.
*
* Both properties are important to certain workloads.
*/
static int effective_prio(task_t *p)
{
 int bonus, prio;

 if (rt_task(p))
  return p->prio;

 bonus = CURRENT_BONUS(p) - MAX_BONUS / 2;

 prio = p->static_prio - bonus;
 if (prio < MAX_RT_PRIO)
  prio = MAX_RT_PRIO;
 if (prio > MAX_PRIO-1)
  prio = MAX_PRIO-1;
 return prio;
}

/**
* task_prio - return the priority value of a given task.
* @p: the task in question.
*
* This is the priority value as seen by users in /proc.
* RT tasks are offset by -200. Normal tasks are centered
* around 0, value goes from -16 to +15.
*/
int task_prio(const task_t *p)
{
 return p->prio - MAX_RT_PRIO;
}

/**
* task_nice - return the nice value of a given task.
* @p: the task in question.
*/
int task_nice(const task_t *p)
{
 return TASK_NICE(p);
}