国产精品天干天干,亚洲毛片在线,日韩gay小鲜肉啪啪18禁,女同Gay自慰喷水

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

一文深入剖析Linux內(nèi)核之內(nèi)核搶占(純干貨~)

2022-06-29 20:02 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

1.前言

環(huán)境:

  • 處理器架構(gòu):arm64內(nèi)核源碼:linux-5.11ubuntu版本:20.04.1代碼閱讀工具:vim+ctags+cscope

  • 我們或許經(jīng)常聽說過內(nèi)核搶占,可是我們是否真正理解它呢?內(nèi)核搶占和搶占式內(nèi)核究竟有什么關(guān)系呢?搶占計(jì)數(shù)器究竟干什么用?... 本文我們就來好好討論下,關(guān)于內(nèi)核搶占的一些技術(shù)細(xì)節(jié),力求讓大家理解內(nèi)核搶占。

  • 注:本文主要關(guān)注CFS調(diào)度類。

2.內(nèi)核搶占和搶占式內(nèi)核

  • 我們經(jīng)常使用uname -a命令能看到“PREEMPT”的字樣,沒錯,我們使用的是搶占式內(nèi)核。

  • 那什么是搶占式內(nèi)核呢? 實(shí)際上,支持內(nèi)核搶占的內(nèi)核叫做搶占式內(nèi)核,不支持內(nèi)核搶占的內(nèi)核叫做不可搶占式內(nèi)核。那么問題又來了,什么是內(nèi)核搶占呢?我們都知道,拿周期性的tick來說:對于用戶任務(wù),當(dāng)每個時鐘中斷到來后都會檢查它的實(shí)際運(yùn)行時間是否超過理想運(yùn)行時間,或者運(yùn)行隊(duì)列中有沒有優(yōu)先級更高的進(jìn)程,一般如果滿足其中一個條件就會設(shè)置重新調(diào)度標(biāo)志,然后在中斷返回用戶態(tài)的前夕發(fā)生調(diào)度,這是所謂的用戶任務(wù)搶占。但是如果處于一個內(nèi)核態(tài)的任務(wù)正在運(yùn)行,這個時候發(fā)生中斷喚醒了一個高優(yōu)先級的任務(wù),那么這個被喚醒的任務(wù)能否被調(diào)度執(zhí)行呢?這個時候就會分兩種情況分析,如果是搶占式內(nèi)核那么高優(yōu)先級任務(wù)就有可能搶占當(dāng)前任務(wù)而調(diào)度執(zhí)行(之所有是有可能是因?yàn)閮烧咛摂M運(yùn)行時間差值要大于搶占粒度才允許搶占),如果是不可搶占式內(nèi)核那么不允許搶占,除非當(dāng)前進(jìn)程執(zhí)行完或者主動發(fā)生調(diào)度高優(yōu)先級進(jìn)程該有機(jī)會被調(diào)度。也就是說,支持內(nèi)核搶占的內(nèi)核不僅允許在用戶態(tài)的任務(wù)可以被搶占,處在內(nèi)核態(tài)的任務(wù)也允許被搶占(請注意這里說的是內(nèi)核態(tài),因?yàn)橛脩艨臻g任務(wù)可以通過系統(tǒng)調(diào)用等進(jìn)入內(nèi)核態(tài)),這樣對于交互性或者低延遲的應(yīng)用場景很友好,如手持設(shè)備和桌面應(yīng)用,響應(yīng)會很快。而對于服務(wù)器來說,它就對吞吐量要求較高,希望獲得更多的cpu時間,而交互性或者低延遲都是次要的,所以被設(shè)計(jì)成不可搶占式內(nèi)核。

  • 下圖給出非搶占式內(nèi)核調(diào)度情況:


  • 下圖給出搶占式內(nèi)核調(diào)度情況:


  • 對比兩個圖可以發(fā)現(xiàn):采用搶占式內(nèi)核調(diào)度的情況下,在中斷中喚醒一個高優(yōu)先級任務(wù)能夠得到很好的響應(yīng)。

  • 關(guān)于搶占式內(nèi)核還是不可搶占式內(nèi)核的選擇在源碼的kernel/Kconfig.preempt有所描述:

上面列舉了兩個編譯選項(xiàng)一個是支持內(nèi)核搶占一個是不支持內(nèi)核搶占,其實(shí)還有PREEMPT_VOLUNTARY和PREEMPT_RT,前者會顯式增加一些搶占點(diǎn),后者用于支持實(shí)時性 。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ?


3.重新調(diào)度標(biāo)志和搶占計(jì)數(shù)器

  • 內(nèi)核有些路徑是不允許調(diào)度的,如原子上下文,那么這個時候如果喚醒一個高優(yōu)先級的任務(wù)或者tick的時候檢查可重新調(diào)度條件滿足,那么高優(yōu)先級的任務(wù)將不能馬上得到執(zhí)行,但是我又要標(biāo)識一下需要重新調(diào)度,那么就需要設(shè)置重新調(diào)度標(biāo)志,當(dāng)返回到可調(diào)度上下文的時候(如開搶占),這個時候就會檢查是否設(shè)置了這個標(biāo)志來決定是否調(diào)用調(diào)度器來選擇下一個任務(wù)來運(yùn)行。

  • 標(biāo)識重新調(diào)度是設(shè)置:

  • 內(nèi)核的某些路徑上設(shè)置了這個標(biāo)志之后,將在最近的調(diào)度點(diǎn)發(fā)生調(diào)度(可能是最近開啟搶占的時候,也可能是最近中斷異常返回的時候)。

  • 當(dāng)前任務(wù)被設(shè)置了重新調(diào)度標(biāo)志,只是表明不久的將來會發(fā)生調(diào)度,并不是馬上發(fā)生調(diào)度,對于用戶任務(wù)來說就是中斷異常返回用戶態(tài)的前夕發(fā)生調(diào)度,而對于處于內(nèi)核態(tài)的任務(wù)來說,想要在內(nèi)核態(tài)搶占當(dāng)前進(jìn)程,僅僅置位重新調(diào)度標(biāo)志還不行,還需要判斷當(dāng)前進(jìn)程的搶占計(jì)數(shù)器是否為0。

  • 所有對于處于內(nèi)核態(tài)的任務(wù)來說,搶占計(jì)數(shù)器對于重新調(diào)度至關(guān)重要,只要搶占計(jì)數(shù)器不為0,無論被喚醒的任務(wù)在緊急都不能獲得調(diào)度器,我們來看看這個搶占計(jì)數(shù)器:

我們來看下對于arm64架構(gòu),搶占計(jì)數(shù)器的定義:

  • 可以發(fā)現(xiàn)它是一個共用體,內(nèi)核某些路徑使用preempt_count,有的是preempt,為何會使用這么奇怪的定義呢?因?yàn)橐粋€成員可以表示兩種狀態(tài):重新調(diào)度標(biāo)志和搶占計(jì)數(shù)器的數(shù)值

  • 當(dāng)需要重新調(diào)度的時候會置位flags的TIF_NEED_RESCHED標(biāo)志,與此同時會將preempt.need_resched清零。當(dāng)檢查thread_info 的preempt_count==0成立時,說明搶占計(jì)數(shù)器的數(shù)值為0且flags的TIF_NEED_RESCHED標(biāo)志被置位,這個時候可以進(jìn)程重新調(diào)度(如中斷返回內(nèi)核態(tài)前夕的檢查)。

  • 下面看下如何設(shè)置重新調(diào)度標(biāo)志:

  • 當(dāng)內(nèi)核的某個路徑設(shè)置重新調(diào)度標(biāo)志(如時鐘中斷tick時),會調(diào)用到resched_curr 來設(shè)置重新調(diào)度標(biāo)志:可以看到除了設(shè)置任務(wù)的flags的TIF_NEED_RESCHED標(biāo)志外,還設(shè)置了preempt.need_resched為0。

  • 如何清除重新調(diào)度標(biāo)志:

  • 可以看到在主調(diào)度器中,除了調(diào)用clear_tsk_need_resched來清除任務(wù)的flags的TIF_NEED_RESCHED標(biāo)志外,會調(diào)用clear_preempt_need_resched來設(shè)置preempt.need_resched為1, 來清除重新調(diào)度。

  • 下面為搶占計(jì)數(shù)器的各個域的表示:

  • 0-7 表示搶占計(jì)數(shù) ,8-15表示軟中斷計(jì)數(shù), 16-19表示硬中斷計(jì)數(shù),20-23表示不可屏蔽中斷計(jì)數(shù)。當(dāng)進(jìn)入不同的上下文時會設(shè)置響應(yīng)的位域,表示在某個上下文中,當(dāng)某個位域被設(shè)置,搶占計(jì)數(shù)器不為0,任務(wù)在內(nèi)核態(tài)就不容許被搶占。

  • 所以,搶占計(jì)數(shù)器有兩個作用:一個是標(biāo)識內(nèi)核路徑在某個原子上下文,一個是用來判斷是否允許任務(wù)在內(nèi)核態(tài)被搶占。

4.內(nèi)核搶占的調(diào)度時機(jī)

  • 這里調(diào)度時機(jī)我將它細(xì)分為兩種情況,一種是不進(jìn)行調(diào)度的check點(diǎn),一種是真正的搶占點(diǎn)(即是調(diào)用主調(diào)度器進(jìn)行調(diào)度):

check點(diǎn)->

  • tick的時候 : 滿足條件(任務(wù)使用完理想運(yùn)行時間,運(yùn)行時間大于最小搶占粒度且運(yùn)行隊(duì)列有優(yōu)先級更高的任務(wù)) 時,設(shè)置TIF_NEED_RESCHED標(biāo)志,最近的搶占點(diǎn)發(fā)生調(diào)度 。

  • 喚醒搶占 : 滿足條件(喚醒的任務(wù)與當(dāng)前任務(wù)的虛擬運(yùn)行時間差值大于最小喚醒搶占粒度 ,喚醒的任務(wù)虛擬運(yùn)行時間更小) 時, 設(shè)置TIF_NEED_RESCHED標(biāo)志,最近的搶占點(diǎn)發(fā)生調(diào)度。

搶占點(diǎn)->

  • 中斷返回內(nèi)核態(tài) : 滿足條件(重新調(diào)度標(biāo)志置位且搶占計(jì)數(shù)器為0) 時, 搶占式調(diào)度 。

  • 打開搶占的時候 : (如開搶占,開中斷下半部,釋放自旋鎖) 滿足條件(重新調(diào)度標(biāo)志置位且搶占計(jì)數(shù)器為0)時, 搶占式調(diào)度。

  • 開啟軟中斷的時候 : 滿足條件(重新調(diào)度標(biāo)志置位且搶占計(jì)數(shù)器為0)時, 搶占式調(diào)度。

  • 中斷返回內(nèi)核態(tài)是常規(guī)的搶占點(diǎn),一般情況下即使沒有其他中斷產(chǎn)生,周期性的tick中斷也會發(fā)生, 滿足條件(重新調(diào)度標(biāo)志置位且搶占計(jì)數(shù)器為0)時,當(dāng)前任務(wù)就會被搶占。而在一些會發(fā)生多任務(wù)竟態(tài)的臨界區(qū)中,我們需要關(guān)閉內(nèi)核搶占,有的直接調(diào)用preempt_disable, 有的是間接調(diào)用preempt_disable(如申請自旋鎖的臨界區(qū)), 有的則是關(guān)閉軟中斷等,這些都會導(dǎo)致?lián)屨加?jì)數(shù)器不為0,但是在這些臨界區(qū)中如果中斷喚醒了高優(yōu)先級的任務(wù),中斷返回內(nèi)核態(tài)的前夕是不能進(jìn)行調(diào)度的,所以在這些臨界區(qū)結(jié)束的時候會檢查調(diào)度條件是否滿足,如果滿足進(jìn)行搶占式調(diào)度,從而使得被喚醒的任務(wù)被及時的響應(yīng)。一般,一些check點(diǎn)設(shè)置了當(dāng)前任務(wù)的重新調(diào)度標(biāo)志之后,如果搶占計(jì)數(shù)器為0,會在最近的搶占點(diǎn)發(fā)生調(diào)度(就是上面所說的三種情況)。還有需要注意的是:關(guān)搶占的臨界區(qū)中,只是禁止了當(dāng)前任務(wù)所在cpu的內(nèi)核搶占,其他cpu依然可以進(jìn)行內(nèi)核搶占,如果這段臨界區(qū)有可能被其他cpu訪問到,可以直接使用自旋鎖來保護(hù)。

4.1 check點(diǎn)

1) 時鐘中斷tick時:

  • 每個時鐘tick到來時,會調(diào)用scheduler_tick來檢查是否需要重新調(diào)度,以下兩個條件有一個發(fā)生都會設(shè)置重新調(diào)度標(biāo)志:

  1. 當(dāng)前任務(wù)的實(shí)際運(yùn)行時間大于理想運(yùn)行時間(保證任務(wù)在一個調(diào)度周期內(nèi)運(yùn)行時間不會超過理想運(yùn)行時間,防止“流氓”任務(wù)一直霸占cpu,通過周期性的時鐘中斷奪回處理器的使用權(quán))。

  2. 當(dāng)前任務(wù)的實(shí)際運(yùn)行時間大于最小調(diào)度粒度,且紅黑樹最左邊的任務(wù)的虛擬運(yùn)行時間和當(dāng)前任務(wù)的虛擬運(yùn)行時間的差值大于理想運(yùn)行時間(紅黑樹中的高優(yōu)先級的任務(wù)可以搶占當(dāng)前任務(wù))。

2)喚醒搶占:

  • 在fork和正常的喚醒路徑上:

fork路徑:

正常喚醒路徑:

  • 無論是創(chuàng)建新任務(wù)或者是喚醒任務(wù)的時候,都有可能新喚醒的任務(wù)搶占當(dāng)前任務(wù),判斷條件如下:喚醒的任務(wù)的虛擬運(yùn)行時間和當(dāng)前任務(wù)的虛擬運(yùn)行時間差值大于最小喚醒搶占粒度轉(zhuǎn)換的虛擬運(yùn)行時間(喚醒的任務(wù)的虛擬運(yùn)行時間更?。?/p>

4.2 搶占點(diǎn)

  • 上面介紹的都是check點(diǎn),只是設(shè)置重新調(diào)度標(biāo)志,并沒有讓搶占的任務(wù)運(yùn)行,真正的搶占點(diǎn)是調(diào)用主調(diào)度器的時候。

1)中斷返回內(nèi)核態(tài)

  • 當(dāng)開啟內(nèi)核搶占的時候,在中斷返回內(nèi)核態(tài)的前夕,會檢查當(dāng)前任務(wù)是否設(shè)置了重新調(diào)度標(biāo)志且搶占計(jì)數(shù)器為0,如果都滿足,進(jìn)行搶占式調(diào)度。

  • 當(dāng)發(fā)生中斷時,會執(zhí)行el1_irq來處理中斷,

  • 672行 來讀取當(dāng)前任務(wù)的thread_info.preempt_count 681行 判斷thread_info.preempt_count是否為0,如果為0 則調(diào)用682 行的arm64_preempt_schedule_irq 進(jìn)行搶占式調(diào)度(上一節(jié)已經(jīng)分析過)。

  • 下面看下?lián)屨际秸{(diào)度:

2)打開搶占的時候

開啟搶占:

釋放自旋鎖:

3) 開啟軟中斷

其實(shí),無論是主動進(jìn)行調(diào)度還是搶占式調(diào)度都會調(diào)用__schedule,而__schedule是屬于關(guān)搶占上下文,在調(diào)度期間不允許被搶占。

5.不可搶占內(nèi)核的低延遲處理

  • 下面我們來看下在沒有開啟內(nèi)核搶占的內(nèi)核中如何處理低延遲:

  • 我們會看到在一些比較耗時的處理中如文件系統(tǒng)和內(nèi)存回收的一些路徑會調(diào)用cond_resched,它是干什么用呢:

  • 下面是使用這個宏的例子:在內(nèi)存回收路徑中,會從不活躍的lru鏈表尾部取出一些頁面回收隔離到page_list中,最終會調(diào)用到shrink_page_list:

  • 可以看到對于page_list中的每一個被隔離的候選回收頁,在處理之前都會調(diào)用到cond_resched來主動判斷是否需要重新調(diào)度。

  • 下面我們來看下cond_resched這個宏實(shí)現(xiàn):

  • 我們可以很清楚的看到,搶占式內(nèi)核中(CONFIG_PREEMPTION=y)cond_resched宏的_cond_resched為空,并沒有主動判斷重新調(diào)度的功能,只有非搶占式內(nèi)核才會調(diào)用_cond_resched來執(zhí)行主動檢查可搶占性。

  • 下面我們來看下_cond_resched:

  • 會主動檢查搶占計(jì)數(shù)器是否為0(實(shí)際上搶占計(jì)數(shù)器是否為0且當(dāng)前任務(wù)被設(shè)置了重新調(diào)度標(biāo)志),則進(jìn)行搶占式調(diào)度。

  • 實(shí)際上,對于非搶占式內(nèi)核來說,在內(nèi)核的很多地方,特別是文件系統(tǒng)操作和內(nèi)存管理相關(guān)的一些耗時路徑中,都已經(jīng)被內(nèi)核開發(fā)者識別出來,并使用cond_resched來減小延遲(感興趣的小伙伴可以通過grep和wc -l命令來查看一下)。

6.自愿內(nèi)核搶占

  • 內(nèi)核搶占模型有一種叫做自愿內(nèi)核搶占模型(CONFIG_PREEMPT_VOLUNTARY=y),可以使得內(nèi)核開發(fā)者在進(jìn)行耗時操作的時候,主動檢查是否需要發(fā)生搶占式調(diào)度,這個和上一節(jié)差不多。

使用might_resched:

  • 發(fā)現(xiàn)只有CONFIG_PREEMPT_VOLUNTARY=y時,might_resched才有效,否則為空。

  • 可以驚奇的發(fā)現(xiàn),當(dāng)搜索might_resched在內(nèi)核中使用的使用的時候,并沒有看見有任何地方在使用,猜想是因?yàn)榇蠖鄶?shù)耗時的內(nèi)核路徑,都已經(jīng)使用cond_resched來進(jìn)行檢查是否具備調(diào)度時機(jī)。

7.總結(jié)

  • 本文講解了內(nèi)核搶占的方方面面,非搶占式內(nèi)核主要用于服務(wù)器等對吞吐量要求較高的場景,而搶占式內(nèi)核主要用于嵌入式設(shè)備和桌面等對響應(yīng)要求較高的場景。內(nèi)核搶占的調(diào)度時機(jī)主要從check點(diǎn)和搶占點(diǎn)兩個角度去分析:check點(diǎn)是在合適的時機(jī)(如時鐘中斷tick時或者任務(wù)喚醒的時候)判斷是否需要重新調(diào)度任務(wù),如果需要設(shè)置重新調(diào)度標(biāo)志(need_resched),并沒有馬上進(jìn)行調(diào)度,然后在最近的搶占點(diǎn)發(fā)生調(diào)度;而搶占點(diǎn)是真正調(diào)用主調(diào)度器發(fā)生調(diào)度的時機(jī),一般會在中斷返回內(nèi)核態(tài)或者重新開啟內(nèi)核搶占等情況下發(fā)生。最后,我們又分析了非搶占式內(nèi)核如何進(jìn)行低延遲處理已經(jīng)自愿搶占式內(nèi)核如何實(shí)現(xiàn)自愿式搶占。



一文深入剖析Linux內(nèi)核之內(nèi)核搶占(純干貨~)的評論 (共 條)

分享到微博請遵守國家法律
商洛市| 通渭县| 赣州市| 吉木萨尔县| 沂水县| 平顶山市| 醴陵市| 扎赉特旗| 罗平县| 娄烦县| 金沙县| 晋中市| 汝城县| 扶余县| 西平县| 阿克| 和平县| 工布江达县| 乐陵市| 胶南市| 邓州市| 北川| 历史| 海兴县| 准格尔旗| 阿巴嘎旗| 正安县| 泉州市| 行唐县| 福泉市| 东至县| 华宁县| 东阿县| 贵南县| 张掖市| 定结县| 亳州市| 伊通| 衡阳市| 称多县| 金华市|