從使用者的角度來看,優先順序非常簡單,不過是從-20 ~ 19之間的數字。但是核心內部對這些優先順序的處理相當的複雜。
優先順序核心表示
在使用者空間可以通過系統調用nice更改當前進程的優先順序,對於linux系統來說優先順序的表示範圍是-20~19,值越小表示進程的優先順序越高。至於說為什麼選擇這麼一個詭異的範圍,真相已經淹沒在曆史中了。
在核心中使用一個看起來正常得多的表示方法,從0到139。值越小,優先順序越低。其中0~99是給即時進程使用的,nice值的-20~19正好可以映射到100到139這個範圍內,這也意味著nice只能設定非即時進程的優先順序。即時進程的優先順序一定比普通進程的優先順序高。
計算優先順序
上面說的都是進程的靜態優先順序,有時我們還需要考慮下面三種優先順序:
進程的動態優先順序task_struct->prio, 普通優先順序task_struct->normal_prio,和靜態優先順序task_struct->static_prio。
動態優先順序和普通優先順序是通過靜態優先順序計算出來的:
p->prio = effective_prio(p);
輔助函數effective_prio執行了下列操作:
/* * Calculate the current priority, i.e. the priority * taken into account by the scheduler. This value might * be boosted by RT tasks, or might be boosted by * interactivity modifiers. Will be RT if the task got * RT-boosted. If not then it returns p->normal_prio. */static int effective_prio(struct task_struct *p){ p->normal_prio = normal_prio(p); /* * If we are RT tasks or we were boosted to RT priority, * keep the priority unchanged. Otherwise, update priority * to the normal priority: */ if (!rt_prio(p->prio)) return p->normal_prio; return p->prio;}
這個函數返回動態優先順序,同時在函數內部會修改進程的普通優先順序。
對於普通進程,我們可以看出static_prio,normal_prio和prio是完全相同的。即時進程的優先順序計算方法是不同的,要根據rt_priority計算,由於更高的priority表示更高的優先順序,核心內部的優先順序表示則完全相反,越低的值表示的優先順序越高。
normal_prio非常簡單,僅僅返回了p->static_prio,之所以使用一個函數封裝這個簡單的功能,是因為曆史的原因,在原來的O(1)調度器時,普通優先順序的計算涉及到很多複雜的技巧性工作。
計算負載權重
優先順序固然重要,但是在進程調度時考慮到task-struct->se.load中儲存的負荷權重。
函數set_load_weight負責根據進程類型及其靜態優先順序計算負荷權重。
對於普通進程,核心維護了一個表,從-20~19每個優先順序對應表中一項
static const int prio_to_weight[40] = { /* -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,};
可以看出數組中各個相鄰值之間的乘數因子是1.25, 共有40項,prio_to_weight[0]對應著優先順序100,prio_to_wright[39]對應著優先順序139。而是是進程的負載則是prio_to_weight[0]的2倍。其實我們完全沒必要記住這些奇怪的數字,只要知道即時進程權重更大即可