真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

linuxcfs命令 linux cfg

Linux進程的調(diào)度

上回書說到 Linux進程的由來 和 Linux進程的創(chuàng)建 ,其實在同一時刻只能支持有限個進程或線程同時運行(這取決于CPU核數(shù)量,基本上一個進程對應(yīng)一個CPU),在一個運行的操作系統(tǒng)上可能運行著很多進程,如果運行的進程占據(jù)CPU的時間很長,就有可能導(dǎo)致其他進程餓死。為了解決這種問題,操作系統(tǒng)引入了 進程調(diào)度器 來進行進程的切換,輪流讓各個進程使用CPU資源。

創(chuàng)新互聯(lián)公司專注于連平網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供連平營銷型網(wǎng)站建設(shè),連平網(wǎng)站制作、連平網(wǎng)頁設(shè)計、連平網(wǎng)站官網(wǎng)定制、小程序設(shè)計服務(wù),打造連平網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供連平網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。

1)rq: 進程的運行隊列( runqueue), 每個CPU對應(yīng)一個 ,包含自旋鎖(spinlock)、進程數(shù)量、用于公平調(diào)度的CFS信息結(jié)構(gòu)、當(dāng)前運行的進程描述符等。實際的進程隊列用紅黑樹來維護(通過CFS信息結(jié)構(gòu)來訪問)。

2)cfs_rq: cfs調(diào)度的進程運行隊列信息 ,包含紅黑樹的根結(jié)點、正在運行的進程指針、用于負載均衡的葉子隊列等。

3)sched_entity: 把需要調(diào)度的東西抽象成調(diào)度實體 ,調(diào)度實體可以是進程、進程組、用戶等。這里包含負載權(quán)重值、對應(yīng)紅黑樹結(jié)點、 虛擬運行時vruntime 等。

4)sched_class:把 調(diào)度策略(算法)抽象成調(diào)度類 ,包含一組通用的調(diào)度操作接口。接口和實現(xiàn)是分離,可以根據(jù)調(diào)度接口去實現(xiàn)不同的調(diào)度算法,使一個Linux調(diào)度程序可以有多個不同的調(diào)度策略。

1) 關(guān)閉內(nèi)核搶占 ,初始化部分變量。獲取當(dāng)前CPU的ID號,并賦值給局部變量CPU, 使rq指向CPU對應(yīng)的運行隊列 。 標(biāo)識當(dāng)前CPU發(fā)生任務(wù)切換 ,通知RCU更新狀態(tài),如果當(dāng)前CPU處于rcu_read_lock狀態(tài),當(dāng)前進程將會放入rnp- blkd_tasks阻塞隊列,并呈現(xiàn)在rnp- gp_tasks鏈表中。 關(guān)閉本地中斷 ,獲取所要保護的運行隊列的自旋鎖, 為查找可運行進程做準(zhǔn)備 。

2) 檢查prev的狀態(tài),更新運行隊列 。如果不是可運行狀態(tài),而且在內(nèi)核態(tài)沒被搶占,應(yīng)該從運行隊列中 刪除prev進程 。如果是非阻塞掛起信號,而且狀態(tài)為TASK_INTER-RUPTIBLE,就把該進程的狀態(tài)設(shè)置為TASK_RUNNING,并將它 插入到運行隊列 。

3)task_on_rq_queued(prev) 將pre進程插入到運行隊列的隊尾。

4)pick_next_task 選取將要執(zhí)行的next進程。

5)context_switch(rq, prev, next)進行 進程上下文切換 。

1) 該進程分配的CPU時間片用完。

2) 該進程主動放棄CPU(例如IO操作)。

3) 某一進程搶占CPU獲得執(zhí)行機會。

Linux并沒有使用x86 CPU自帶的任務(wù)切換機制,需要通過手工的方式實現(xiàn)了切換。

進程創(chuàng)建后在內(nèi)核的數(shù)據(jù)結(jié)構(gòu)為task_struct , 該結(jié)構(gòu)中有掩碼屬性cpus_allowed,4個核的CPU可以有4位掩碼,如果CPU開啟超線程,有一個8位掩碼,進程可以運行在掩碼位設(shè)置為1的CPU上。

Linux內(nèi)核API提供了兩個系統(tǒng)調(diào)用 ,讓用戶可以修改和查看當(dāng)前的掩碼:

1) sched_setaffinity():用來修改位掩碼。

2) sched_getaffinity():用來查看當(dāng)前的位掩碼。

在下次task被喚醒時,select_task_rq_fair根據(jù)cpu_allowed里的掩碼來確定將其置于哪個CPU的運行隊列,一個進程在某一時刻只能存在于一個CPU的運行隊列里。

在Nginx中,使用了CPU親和度來完成某些場景的工作:

worker_processes? ? ? 4;

worker_cpu_affinity 0001001001001000;

上面這個配置說明了4個工作進程中的每一個和一個CPU核掛鉤。如果這個內(nèi)容寫入Nginx的配置文件中,然后Nginx啟動或者重新加載配置的時候,若worker_process是4,就會啟用4個worker,然后把worker_cpu_affinity后面的4個值當(dāng)作4個cpu affinity mask,分別調(diào)用ngx_setaffinity,然后就把4個worker進程分別綁定到CPU0~3上。

worker_processes? ? ? 2;

worker_cpu_affinity 01011010;

上面這個配置則說明了兩個工作進程中的每一個和2個核掛鉤。

linux內(nèi)核怎么調(diào)度系統(tǒng)

1.調(diào)度器的概述

多任務(wù)操作系統(tǒng)分為非搶占式多任務(wù)和搶占式多任務(wù)。與大多數(shù)現(xiàn)代操作系統(tǒng)一樣,Linux采用的是搶占式多任務(wù)模式。這表示對CPU的占用時間由操作系統(tǒng)決定的,具體為操作系統(tǒng)中的調(diào)度器。調(diào)度器決定了什么時候停止一個進程以便讓其他進程有機會運行,同時挑選出一個其他的進程開始運行。

2.調(diào)度策略

在Linux上調(diào)度策略決定了調(diào)度器是如何選擇一個新進程的時間。調(diào)度策略與進程的類型有關(guān),內(nèi)核現(xiàn)有的調(diào)度策略如下:

#define SCHED_NORMAL ? ? ? ?0#define SCHED_FIFO ? ? ?1#define SCHED_RR ? ? ? ?2#define SCHED_BATCH ? ? 3/* SCHED_ISO: reserved but not implemented yet */#define SCHED_IDLE ? ? ?5

0: 默認的調(diào)度策略,針對的是普通進程。

1:針對實時進程的先進先出調(diào)度。適合對時間性要求比較高但每次運行時間比較短的進程。

2:針對的是實時進程的時間片輪轉(zhuǎn)調(diào)度。適合每次運行時間比較長得進程。

3:針對批處理進程的調(diào)度,適合那些非交互性且對cpu使用密集的進程。

SCHED_ISO:是內(nèi)核的一個預(yù)留字段,目前還沒有使用

5:適用于優(yōu)先級較低的后臺進程。

注:每個進程的調(diào)度策略保存在進程描述符task_struct中的policy字段

3.調(diào)度器中的機制

內(nèi)核引入調(diào)度類(struct sched_class)說明了調(diào)度器應(yīng)該具有哪些功能。內(nèi)核中每種調(diào)度策略都有該調(diào)度類的一個實例。(比如:基于公平調(diào)度類為:fair_sched_class,基于實時進程的調(diào)度類實例為:rt_sched_class),該實例也是針對每種調(diào)度策略的具體實現(xiàn)。調(diào)度類封裝了不同調(diào)度策略的具體實現(xiàn),屏蔽了各種調(diào)度策略的細節(jié)實現(xiàn)。

調(diào)度器核心函數(shù)schedule()只需要調(diào)用調(diào)度類中的接口,完成進程的調(diào)度,完全不需要考慮調(diào)度策略的具體實現(xiàn)。調(diào)度類連接了調(diào)度函數(shù)和具體的調(diào)度策略。

武特師兄關(guān)于sche_class和sche_entity的解釋,一語中的。

調(diào)度類就是代表的各種調(diào)度策略,調(diào)度實體就是調(diào)度單位,這個實體通常是一個進程,但是自從引入了cgroup后,這個調(diào)度實體可能就不是一個進程了,而是一個組

4.schedule()函數(shù)

linux 支持兩種類型的進程調(diào)度,實時進程和普通進程。實時進程采用SCHED_FIFO 和SCHED_RR調(diào)度策略,普通進程采用SCHED_NORMAL策略。

preempt_disable():禁止內(nèi)核搶占

cpu_rq():獲取當(dāng)前cpu對應(yīng)的就緒隊列。

prev = rq-curr;獲取當(dāng)前進程的描述符prev

switch_count = prev-nivcsw;獲取當(dāng)前進程的切換次數(shù)。

update_rq_clock() :更新就緒隊列上的時鐘

clear_tsk_need_resched()清楚當(dāng)前進程prev的重新調(diào)度標(biāo)志。

deactive_task():將當(dāng)前進程從就緒隊列中刪除。

put_prev_task() :將當(dāng)前進程重新放入就緒隊列

pick_next_task():在就緒隊列中挑選下一個將被執(zhí)行的進程。

context_switch():進行prev和next兩個進程的切換。具體的切換代碼與體系架構(gòu)有關(guān),在switch_to()中通過一段匯編代碼實現(xiàn)。

post_schedule():進行進程切換后的后期處理工作。

5.pick_next_task函數(shù)

選擇下一個將要被執(zhí)行的進程無疑是一個很重要的過程,我們來看一下內(nèi)核中代碼的實現(xiàn)

對以下這段代碼說明:

1.當(dāng)rq中的運行隊列的個數(shù)(nr_running)和cfs中的nr_runing相等的時候,表示現(xiàn)在所有的都是普通進程,這時候就會調(diào)用cfs算法中的pick_next_task(其實是pick_next_task_fair函數(shù)),當(dāng)不相等的時候,則調(diào)用sched_class_highest(這是一個宏,指向的是實時進程),這下面的這個for()循環(huán)中,首先是會在實時進程中選取要調(diào)度的程序(p = class-pick_next_task(rq);)。如果沒有選取到,會執(zhí)行class=class-next;在class這個鏈表中有三種類型(fair,idle,rt).也就是說會調(diào)用到下一個調(diào)度類。

static inline struct task_struct *pick_next_task(struct rq *rq){ ? ?const struct sched_class *class; ? ?struct task_struct *p; ? ?/*

* Optimization: we know that if all tasks are in

* the fair class we can call that function directly:

*///基于公平調(diào)度的普通進程

if (likely(rq-nr_running == rq-cfs.nr_running)) {

?p = fair_sched_class.pick_next_task(rq); ? ? ? ?if (likely(p)) ? ? ? ? ? ?return p;

}//基于實時調(diào)度的實時進程

class = sched_class_highest; ? ?for ( ; ; ) {

?p = class-pick_next_task(rq); ?//實時進程的類

?if (p) ? ? ? ? ? ?return p; ? ? ? ?/*

? * Will never be NULL as the idle class always

? * returns a non-NULL p:

? */

?class = class-next; ?//rt-next = fair; ?fair-next = idle

}

}

在這段代碼中體現(xiàn)了Linux所支持的兩種類型的進程,實時進程和普通進程。回顧下:實時進程可以采用SCHED_FIFO 和SCHED_RR調(diào)度策略,普通進程采用SCHED_NORMAL調(diào)度策略。

在這里首先說明一個結(jié)構(gòu)體struct rq,這個結(jié)構(gòu)體是調(diào)度器管理可運行狀態(tài)進程的最主要的數(shù)據(jù)結(jié)構(gòu)。每個cpu上都有一個可運行的就緒隊列。剛才在pick_next_task函數(shù)中看到了在選擇下一個將要被執(zhí)行的進程時實際上用的是struct rq上的普通進程的調(diào)度或者實時進程的調(diào)度,那么具體是如何調(diào)度的呢?在實時調(diào)度中,為了實現(xiàn)O(1)的調(diào)度算法,內(nèi)核為每個優(yōu)先級維護一個運行隊列和一個DECLARE_BITMAP,內(nèi)核根據(jù)DECLARE_BITMAP的bit數(shù)值找出非空的最高級優(yōu)先隊列的編號,從而可以從非空的最高級優(yōu)先隊列中取出進程進行運行。

我們來看下內(nèi)核的實現(xiàn)

struct rt_prio_array {

DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */

struct list_head queue[MAX_RT_PRIO];

};

數(shù)組queue[i]里面存放的是優(yōu)先級為i的進程隊列的鏈表頭。在結(jié)構(gòu)體rt_prio_array 中有一個重要的數(shù)據(jù)構(gòu)DECLARE_BITMAP,它在內(nèi)核中的第一如下:

define DECLARE_BITMAP(name,bits) \

unsigned long name[BITS_TO_LONGS(bits)]

5.1對于實時進程的O(1)算法

這個數(shù)據(jù)是用來作為進程隊列queue[MAX_PRIO]的索引位圖。bitmap中的每一位與queue[i]對應(yīng),當(dāng)queue[i]的進程隊列不為空時,Bitmap的相應(yīng)位就為1,否則為0,這樣就只需要通過匯編指令從進程優(yōu)先級由高到低的方向找到第一個為1的位置,則這個位置就是就緒隊列中最高的優(yōu)先級(函數(shù)sched_find_first_bit()就是用來實現(xiàn)該目的的)。那么queue[index]-next就是要找的候選進程。

如果還是不懂,那就來看兩個圖

注:在每個隊列上的任務(wù)一般基于先進先出的原則進行調(diào)度(并且為每個進程分配時間片)

在內(nèi)核中的實現(xiàn)為:

static struct sched_rt_entity *pick_next_rt_entity(struct rq *rq, ? ? ? ? ? ? ? ? ? ? ? ? ? struct rt_rq *rt_rq){ ? ?struct rt_prio_array *array = rt_rq-active; ? ?struct sched_rt_entity *next = NULL; ? ?struct list_head *queue; ? ?int idx;

idx = sched_find_first_bit(array-bitmap); //找到優(yōu)先級最高的位

BUG_ON(idx = MAX_RT_PRIO); ? ?queue = array-queue + idx; //然后找到對應(yīng)的queue的起始地址

next = list_entry(queue-next, struct sched_rt_entity, run_list); ?//按先進先出拿任務(wù)

return next;

}

那么當(dāng)同一優(yōu)先級的任務(wù)比較多的時候,內(nèi)核會根據(jù)

位圖:

將對應(yīng)的位置為1,每次取出最大的被置為1的位,表示優(yōu)先級最高:

5.2 關(guān)于普通進程的CFS算法:

我們知道,普通進程在選取下一個需要被調(diào)度的進程時,是調(diào)用的pick_next_task_fair函數(shù)。在這個函數(shù)中是以調(diào)度實體為單位進行調(diào)度的。其最主要的函數(shù)是:pick_next_entity,在這個函數(shù)中會調(diào)用wakeup_preempt_entity函數(shù),這個函數(shù)的主要作用是根據(jù)進程的虛擬時間以及權(quán)重的結(jié)算進程的粒度,以判斷其是否需要搶占。看一下內(nèi)核是怎么實現(xiàn)的:

wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se)

{

s64 gran, vdiff = curr-vruntime - se-vruntime;//計算兩個虛擬時間差//如果se的虛擬時間比curr還大,說明本該curr執(zhí)行,無需搶占

if (vdiff = 0) ? ? ? ?return -1;

gran = wakeup_gran(curr, se); ? ?if (vdiff gran) ? ? ? ?return 1; ? ?return 0;

}

gran為需要搶占的時間差,只有兩個時間差大于需要搶占的時間差,才需要搶占,這里避免太頻繁的搶占

wakeup_gran(struct sched_entity *curr, struct sched_entity *se)

{

unsigned long gran = sysctl_sched_wakeup_granularity; ? ?if (cfs_rq_of(curr)-curr sched_feat(ADAPTIVE_GRAN))

?gran = adaptive_gran(curr, se);

/*

* Since its curr running now, convert the gran from real-time

* to virtual-time in his units.

*/ ? ?if (sched_feat(ASYM_GRAN)) {

?/*

? * 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);

} else { ? ? ? ?if (unlikely(curr-load.weight != NICE_0_LOAD))

? ? ?gran = calc_delta_fair(gran, curr);

} ? ?return gran;

}

6.調(diào)度中的nice值

首先需要明確的是:nice的值不是進程的優(yōu)先級,他們不是一個概念,但是進程的Nice值會影響到進程的優(yōu)先級的變化。

通過命令ps -el可以看到進程的nice值為NI列。PRI表示的是進程的優(yōu)先級,其實進程的優(yōu)先級只是一個整數(shù),它是調(diào)度器選擇進程運行的基礎(chǔ)。

普通進程有:靜態(tài)優(yōu)先級和動態(tài)優(yōu)先級。

靜態(tài)優(yōu)先級:之所有稱為靜態(tài)優(yōu)先級是因為它不會隨著時間而改變,內(nèi)核不會修改它,只能通過系統(tǒng)調(diào)用nice去修改,靜態(tài)優(yōu)先級用進程描述符中的static_prio來表示。在內(nèi)核中/kernel/sched.c中,nice和靜態(tài)優(yōu)先級的關(guān)系為:

#define NICE_TO_PRIO(nice) ?(MAX_RT_PRIO + (nice) + 20)

#define PRIO_TO_NICE(prio) ?((prio) - MAX_RT_PRIO - 20)

動態(tài)優(yōu)先級:調(diào)度程序通過增加或者減小進程靜態(tài)優(yōu)先級的值來獎勵I(lǐng)O小的進程或者懲罰cpu消耗型的進程。調(diào)整后的優(yōu)先級稱為動態(tài)優(yōu)先級。在進程描述中用prio來表示,通常所說的優(yōu)先級指的是動態(tài)優(yōu)先級。

由上面分析可知,我們可以通過系統(tǒng)調(diào)用nice函數(shù)來改變進程的優(yōu)先級。

#include stdlib.h#include stdio.h#include math.h#include unistd.h#include sys/time.h#define JMAX (400*100000)#define GET_ELAPSED_TIME(tv1,tv2) ( \

(double)( (tv2.tv_sec - tv1.tv_sec) \

? ? ?+ .000001 * (tv2.tv_usec - tv1.tv_usec)))//做一個延遲的計算double do_something (void){ ? ?int j; ? ?double x = 0.0; ? ?struct timeval tv1, tv2;

gettimeofday (tv1, NULL);//獲取時區(qū)

for (j = 0; j JMAX; j++)

?x += 1.0 / (exp ((1 + x * x) / (2 + x * x)));

gettimeofday (tv2, NULL); ? ?return GET_ELAPSED_TIME (tv1, tv2);//求差值}int main (int argc, char *argv[]){ ? ?int niceval = 0, nsched; ? ?/* for kernels less than 2.6.21, this is HZ

for tickless kernels this must be the MHZ rate

e.g, for 2.6 GZ scale = 2600000000 */

long scale = 1000; ? ?long ticks_cpu, ticks_sleep; ? ?pid_t pid;

FILE *fp; ? ?char fname[256]; ? ?double elapsed_time, timeslice, t_cpu, t_sleep; ? ?if (argc 1)

?niceval = atoi (argv[1]);

pid = getpid (); ? ?if (argc 2)

?scale = atoi (argv[2]); ? ?/* give a chance for other tasks to queue up */

sleep (3); ? ?sprintf (fname, "/proc/%d/schedstat", pid);//讀取進程的調(diào)度狀態(tài)

/*

?在schedstat中的數(shù)字是什么意思呢?:

*/

/* ? ?printf ("Fname = %s\n", fname); */

if (!(fp = fopen (fname, "r"))) { ? ? ? ?printf ("Failed to open stat file\n"); ? ? ? ?exit (-1);

} ? ?//nice系統(tǒng)調(diào)用

if (nice (niceval) == -1 niceval != -1) { ? ? ? ?printf ("Failed to set nice to %d\n", niceval); ? ? ? ?exit (-1);

}

elapsed_time = do_something ();//for 循環(huán)執(zhí)行了多長時間

fscanf (fp, "%ld %ld %d", ticks_cpu, ticks_sleep, nsched);//nsched表示調(diào)度的次數(shù)

t_cpu = (float)ticks_cpu / scale;//震動的次數(shù)除以1000,就是時間

t_sleep = (float)ticks_sleep / scale;

timeslice = t_cpu / (double)nsched;//除以調(diào)度的次數(shù),就是每次調(diào)度的時間(時間片)

printf ("\nnice=%3d time=%8g secs pid=%5d"

? ? ?" ?t_cpu=%8g ?t_sleep=%8g ?nsched=%5d"

? ? ?" ?avg timeslice = %8g\n",

? ? ?niceval, elapsed_time, pid, t_cpu, t_sleep, nsched, timeslice);

fclose (fp); ? ?exit (0);

}

說明:?首先說明的是/proc/[pid]/schedstat:在這個文件下放著3個變量,他們分別代表什么意思呢?

第一個:該進程擁有的cpu的時間

第二個:在對列上的等待時間,即睡眠時間

第三個:被調(diào)度的次數(shù)

由結(jié)果可以看出當(dāng)nice的值越小的時候,其睡眠時間越短,則表示其優(yōu)先級升高了。

7.關(guān)于獲取和設(shè)置優(yōu)先級的系統(tǒng)調(diào)用:sched_getscheduler()和sched_setscheduler

#include sched.h#include stdlib.h#include stdio.h#include errno.h#define DEATH(mess) { perror(mess); exit(errno); }void printpolicy (int policy){ ? ?/* SCHED_NORMAL = SCHED_OTHER in user-space */

if (policy == SCHED_OTHER) ? ? ? ?printf ("policy = SCHED_OTHER = %d\n", policy); ? ?if (policy == SCHED_FIFO) ? ? ? ?printf ("policy = SCHED_FIFO = %d\n", policy); ? ?if (policy == SCHED_RR) ? ? ? ?printf ("policy = SCHED_RR = %d\n", policy);

}int main (int argc, char **argv){ ? ?int policy; ? ?struct sched_param p; ? ?/* obtain current scheduling policy for this process */

//獲取進程調(diào)度的策略

policy = sched_getscheduler (0);

printpolicy (policy); ? ?/* reset scheduling policy */

printf ("\nTrying sched_setscheduler...\n");

policy = SCHED_FIFO;

printpolicy (policy);

p.sched_priority = 50; ? ?//設(shè)置優(yōu)先級為50

if (sched_setscheduler (0, policy, p))

?DEATH ("sched_setscheduler:"); ? ?printf ("p.sched_priority = %d\n", p.sched_priority); ? ?exit (0);

}

輸出結(jié)果:

[root@wang schedule]# ./get_schedule_policy policy = SCHED_OTHER = 0

Trying sched_setscheduler...

policy = SCHED_FIFO = 1

p.sched_priority = 50

可以看出進程的優(yōu)先級已經(jīng)被改變。

Linux 進程調(diào)度

Linux的調(diào)度策略區(qū)分實時進程和普通進程,實時進程的調(diào)度策略是SCHED_FIFO和SCHED_RR,普通的,非實時進程的調(diào)度策略是SCHED_NORMAL(SCHED_OTHER)。

實時調(diào)度策略被實時調(diào)度器管理,普通調(diào)度策略被完全公平調(diào)度器來管理。實時進程的優(yōu)先級要高于普通進程(nice越小優(yōu)先級越高)。

SCHED_FIFO實現(xiàn)了一種簡單的先入先出的調(diào)度算法,它不使用時間片,但支持搶占,只有優(yōu)先級更高的SCHED_FIFO或者SCHED_RR進程才能搶占它,否則它會一直執(zhí)行下去,低優(yōu)先級的進程不能搶占它,直到它受阻塞或自己主動釋放處理器。

SCHED_RR是帶有時間片的一種實時輪流調(diào)度算法,當(dāng)SCHED_RR進程耗盡它的時間片時,同一優(yōu)先級的其它實時進程被輪流調(diào)度,時間片只用來重新調(diào)用同一優(yōu)先級的進程,低優(yōu)先級的進程決不能搶占SCHED_RR任務(wù),即使它的時間片耗盡。SCHED_RR是帶時間片的SCHED_FIFO。

Linux的實時調(diào)度算法提供了一種軟實時工作方式,軟實時的含義是盡力調(diào)度進程,盡力使進程在它的限定時間到來前運行,但內(nèi)核不保證總能滿足這些進程的要求,相反,硬實時系統(tǒng)保證在一定的條件下,可以滿足任何調(diào)度的要求。

SCHED_NORMAL使用完全公平調(diào)度算法(CFS),之前的算法直接將nice值對應(yīng)時間片的長度,而在CFS中,nice值只作為進程獲取處理器運行比的權(quán)重,每個進程都有一個權(quán)重,nice優(yōu)先級越高,權(quán)重越大,表示應(yīng)該運行更長的時間。Linux的實現(xiàn)中,每個進程都有一個vruntime字段,vruntime是經(jīng)過量化的進程運行時間,也就是實際運行時間除以權(quán)重,所以每個量化后的vruntime應(yīng)該相等,這就體現(xiàn)了公平性。

CFS當(dāng)然也支持搶占,但與實時調(diào)度算法不同,實時調(diào)度算法是根據(jù)優(yōu)先級進行搶占,CFS是根據(jù)vruntime進行搶占,vruntime小就擁有優(yōu)先被運行的權(quán)利。

為了計算時間片,CFS算法需要為完美多任務(wù)中的無限小調(diào)度周期設(shè)定近似值,這個近似值也稱作目標(biāo)延遲,指每個可運行進程在目標(biāo)延遲內(nèi)都會調(diào)度一次,如果進程數(shù)量太多,則時間粒度太小,所以約定時間片的默認最小粒度是1ms。

進程可以分為I/O消耗型和處理器消耗型,這兩種進程的調(diào)度策略應(yīng)該不同,I/O消耗型應(yīng)該更加實時,給對端的感覺是響應(yīng)很快,同時它一般又不會消耗太多的處理器,因而I/O消耗型需要調(diào)度頻繁。相對來說,處理器消耗型不需要特別實時,應(yīng)該盡量降低它的調(diào)度頻度,延長其運行時間。

參考: linux內(nèi)核分析——CFS(完全公平調(diào)度算法) - 一路向北你好 - 博客園


新聞名稱:linuxcfs命令 linux cfg
URL標(biāo)題:http://www.weahome.cn/article/ddehsjh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部