日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux进程调度器-基础

發(fā)布時間:2023/12/20 linux 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux进程调度器-基础 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

背景

  • Read the fucking source code! ?--By 魯迅

  • A picture is worth a thousand words. --By 高爾基

說明:

  • Kernel版本:4.14

  • ARM64處理器,Contex-A53,雙核

  • 使用工具:Source Insight 3.5, Visio

  • 1. 概述

    從這篇文章開始,將開始Linux調度器的系列研究了。本文也會從一些基礎的概念及數(shù)據結構入手,先打造一個粗略的輪廓,后續(xù)的文章將逐漸深入。

    2. 概念

    2.1 進程


    • 從教科書上,我們都能知道:進程是資源分配的最小單位,而線程是CPU調度的的最小單位。

    • 進程不僅包括可執(zhí)行程序的代碼段,還包括一系列的資源,比如:打開的文件、內存、CPU時間、信號量、多個執(zhí)行線程流等等。而線程可以共享進程內的資源空間。

    • 在Linux內核中,進程和線程都使用struct task_struct結構來進行抽象描述。

    • 進程的虛擬地址空間分為用戶虛擬地址空間和內核虛擬地址空間,所有進程共享內核虛擬地址空間,沒有用戶虛擬地址空間的進程稱為內核線程。

    Linux內核使用task_struct結構來抽象,該結構包含了進程的各類信息及所擁有的資源,比如進程的狀態(tài)、打開的文件、地址空間信息、信號資源等等。task_struct結構很復雜,下邊只針對與調度相關的某些字段進行介紹。

    struct task_struct {/* ... *//* 進程狀態(tài) */volatile long state;/* 調度優(yōu)先級相關,策略相關 */int prio;int static_prio;int normal_prio;unsigned int rt_priority;unsigned int policy;/* 調度類,調度實體相關,任務組相關等 */const struct sched_class *sched_class;struct sched_entity se;struct sched_rt_entity rt; #ifdef CONFIG_CGROUP_SCHEDstruct task_group *sched_task_group; #endifstruct sched_dl_entity dl;/* 進程之間的關系相關 *//* Real parent process: */struct task_struct __rcu *real_parent;/* Recipient of SIGCHLD, wait4() reports: */struct task_struct __rcu *parent;/** Children/sibling form the list of natural children:*/struct list_head children;struct list_head sibling;struct task_struct *group_leader;/* ... */ }

    2.2 進程狀態(tài)


    • 上圖中左側為操作系統(tǒng)中通俗的進程三狀態(tài)模型,右側為Linux對應的進程狀態(tài)切換。每一個標志描述了進程的當前狀態(tài),這些狀態(tài)都是互斥的;

    • Linux中的就緒態(tài)和運行態(tài)對應的都是TASK_RUNNING標志位,就緒態(tài)表示進程正處在隊列中,尚未被調度;運行態(tài)則表示進程正在CPU上運行;

    內核中主要的狀態(tài)字段定義如下

    /* Used in tsk->state: */ #define TASK_RUNNING 0x0000 #define TASK_INTERRUPTIBLE 0x0001 #define TASK_UNINTERRUPTIBLE 0x0002/* Used in tsk->exit_state: */ #define EXIT_DEAD 0x0010 #define EXIT_ZOMBIE 0x0020 #define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD)/* Used in tsk->state again: */ #define TASK_PARKED 0x0040 #define TASK_DEAD 0x0080 #define TASK_WAKEKILL 0x0100 #define TASK_WAKING 0x0200 #define TASK_NOLOAD 0x0400 #define TASK_NEW 0x0800 #define TASK_STATE_MAX 0x1000/* Convenience macros for the sake of set_current_state: */ #define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) #define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED) #define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)

    2.3 scheduler 調度器


    • 所謂調度,就是按照某種調度的算法,從進程的就緒隊列中選取進程分配CPU,主要是協(xié)調對CPU等的資源使用。進程調度的目標是最大限度利用CPU時間。

    內核默認提供了5個調度器,Linux內核使用struct sched_class來對調度器進行抽象:

  • Stop調度器, stop_sched_class:優(yōu)先級最高的調度類,可以搶占其他所有進程,不能被其他進程搶占;

  • Deadline調度器, dl_sched_class:使用紅黑樹,把進程按照絕對截止期限進行排序,選擇最小進程進行調度運行;

  • RT調度器, rt_sched_class:實時調度器,為每個優(yōu)先級維護一個隊列;

  • CFS調度器, cfs_sched_class:完全公平調度器,采用完全公平調度算法,引入虛擬運行時間概念;

  • IDLE-Task調度器, idle_sched_class:空閑調度器,每個CPU都會有一個idle線程,當沒有其他進程可以調度時,調度運行idle線程;

  • Linux內核提供了一些調度策略供用戶程序來選擇調度器,其中Stop調度器和IDLE-Task調度器,僅由內核使用,用戶無法進行選擇:

    • SCHED_DEADLINE:限期進程調度策略,使task選擇Deadline調度器來調度運行;

    • SCHED_RR:實時進程調度策略,時間片輪轉,進程用完時間片后加入優(yōu)先級對應運行隊列的尾部,把CPU讓給同優(yōu)先級的其他進程;

    • SCHED_FIFO:實時進程調度策略,先進先出調度沒有時間片,沒有更高優(yōu)先級的情況下,只能等待主動讓出CPU;

    • SCHED_NORMAL:普通進程調度策略,使task選擇CFS調度器來調度運行;

    • SCHED_BATCH:普通進程調度策略,批量處理,使task選擇CFS調度器來調度運行;

    • SCHED_IDLE:普通進程調度策略,使task以最低優(yōu)先級選擇CFS調度器來調度運行;

    2.4 runqueue 運行隊列


    • 每個CPU都有一個運行隊列,每個調度器都作用于運行隊列;

    • 分配給CPU的task,作為調度實體加入到運行隊列中;

    • task首次運行時,如果可能,盡量將它加入到父task所在的運行隊列中(分配給相同的CPU,緩存affinity會更高,性能會有改善);

    Linux內核使用struct rq結構來描述運行隊列,關鍵字段如下:

    /** This is the main, per-CPU runqueue data structure.** Locking rule: those places that want to lock multiple runqueues* (such as the load balancing or the thread migration code), lock* acquire operations must be ordered by ascending &runqueue.*/ struct rq {/* runqueue lock: */raw_spinlock_t lock;/** nr_running and cpu_load should be in the same cacheline because* remote CPUs use both these fields when doing load calculation.*/unsigned int nr_running;/* 三個調度隊列:CFS調度,RT調度,DL調度 */struct cfs_rq cfs;struct rt_rq rt;struct dl_rq dl;/* stop指向遷移內核線程, idle指向空閑內核線程 */struct task_struct *curr, *idle, *stop;/* ... */ }

    2.5 task_group 任務分組


    • 利用任務分組的機制,可以設置或限制任務組對CPU的利用率,比如將某些任務限制在某個區(qū)間內,從而不去影響其他任務的執(zhí)行效率;

    • 引入task_group后,調度器的調度對象不僅僅是進程了,Linux內核抽象出了sched_entity/sched_rt_entity/sched_dl_entity描述調度實體,調度實體可以是進程或task_group;

    • 使用數(shù)據結構struct task_group來描述任務組,任務組在每個CPU上都會維護一個CFS調度實體、CFS運行隊列,RT調度實體,RT運行隊列;

    Linux內核使用struct task_group來描述任務組,關鍵的字段如下:

    /* task group related information */ struct task_group {/* ... *//* 為每個CPU都分配一個CFS調度實體和CFS運行隊列 */ #ifdef CONFIG_FAIR_GROUP_SCHED/* schedulable entities of this group on each cpu */struct sched_entity **se;/* runqueue "owned" by this group on each cpu */struct cfs_rq **cfs_rq;unsigned long shares; #endif/* 為每個CPU都分配一個RT調度實體和RT運行隊列 */ #ifdef CONFIG_RT_GROUP_SCHEDstruct sched_rt_entity **rt_se;struct rt_rq **rt_rq;struct rt_bandwidth rt_bandwidth; #endif/* task_group之間的組織關系 */struct rcu_head rcu;struct list_head list;struct task_group *parent;struct list_head siblings;struct list_head children;/* ... */ };

    3. 調度程序

    調度程序依靠幾個函數(shù)來完成調度工作的,下邊將介紹幾個關鍵的函數(shù)。

  • 主動調度 - schedule()

    • schedule()函數(shù),是進程調度的核心函數(shù),大體的流程如上圖所示。

    • 核心的邏輯:選擇另外一個進程來替換掉當前運行的進程。進程的選擇是通過進程所使用的調度器中的pick_next_task函數(shù)來實現(xiàn)的,不同的調度器實現(xiàn)的方法不一樣;進程的替換是通過context_switch()來完成切換的,具體的細節(jié)后續(xù)的文章再深入分析。

  • 周期調度 - schedule_tick()

    • 時鐘中斷處理程序中,調用schedule_tick()函數(shù);

    • 時鐘中斷是調度器的脈搏,內核依靠周期性的時鐘來處理器CPU的控制權;

    • 時鐘中斷處理程序,檢查當前進程的執(zhí)行時間是否超額,如果超額則設置重新調度標志(_TIF_NEED_RESCHED);

    • 時鐘中斷處理函數(shù)返回時,被中斷的進程如果在用戶模式下運行,需要檢查是否有重新調度標志,設置了則調用schedule()調度;

  • 高精度時鐘調度 - hrtick()

    • 高精度時鐘調度,與周期性調度類似,不同點在于周期調度的精度為ms級別,而高精度調度的精度為ns級別;

    • 高精度時鐘調度,需要有對應的硬件支持;

  • 進程喚醒時調度 - wake_up_process()

    • 喚醒進程時調用wake_up_process()函數(shù),被喚醒的進程可能搶占當前的進程;

    上述講到的幾個函數(shù)都是常用于調度時調用。此外,在創(chuàng)建新進程時,或是在內核搶占時,也會出現(xiàn)一些調度點。

    本文只是粗略的介紹了一個大概,后續(xù)將針對某些模塊進行更加深入的分析,敬請期待。


    推薦閱讀:

    專輯|Linux文章匯總

    專輯|程序人生

    嵌入式Linux

    微信掃描二維碼,關注我的公眾號

    總結

    以上是生活随笔為你收集整理的Linux进程调度器-基础的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。