Linux调度系统全景指南(中篇)
點(diǎn)擊上方藍(lán)字關(guān)注公眾號,更多經(jīng)典內(nèi)容等著你
| 導(dǎo)語本文主要是講Linux的調(diào)度系統(tǒng), 由于全部內(nèi)容太多,分三部分來講,本篇是中篇(主要講搶占和時(shí)鐘),上篇請看(CPU和中斷):Linux調(diào)度系統(tǒng)全景指南(上篇),調(diào)度可以說是操作系統(tǒng)的靈魂,為了讓CPU資源利用最大化,Linux設(shè)計(jì)了一套非常精細(xì)的調(diào)度系統(tǒng),對大多數(shù)場景都進(jìn)行了很多優(yōu)化,系統(tǒng)擴(kuò)展性強(qiáng),我們可以根據(jù)業(yè)務(wù)模型和業(yè)務(wù)場景的特點(diǎn),有針對性的去進(jìn)行性能優(yōu)化,在保證客戶網(wǎng)絡(luò)帶寬前提下,隔離客戶互相之間的干擾影響,提高CPU利用率,降低單位運(yùn)算成本,提高市場競爭力。歡迎大家相互交流學(xué)習(xí)!
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 目錄
上篇請看(CPU和中斷):Linux調(diào)度系統(tǒng)全景指南(上篇)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?搶占
早期的Linux核心是不可搶占的。它的調(diào)度方法是:一個(gè)進(jìn)程可以通過schedule()函數(shù)自愿地啟動一次調(diào)度。非自愿的強(qiáng)制性調(diào)度只能發(fā)生在每次從系統(tǒng)調(diào)用返回的前夕,以及每次從中斷或異常處理返回到用戶空間的前夕。但是,如果在系統(tǒng)空間發(fā)生中斷或異常是不會引起調(diào)度的。這種方式使內(nèi)核實(shí)現(xiàn)得以簡化。但常存在下面兩個(gè)問題:
如果這樣的中斷發(fā)生在內(nèi)核中,本次中斷返回是不會引起調(diào)度的,而要到最初使CPU從用戶空間進(jìn)入內(nèi)核空間的那次系統(tǒng)調(diào)用或中斷(異常)返回時(shí)才會發(fā)生調(diào)度。
另外一個(gè)問題是優(yōu)先級反轉(zhuǎn)。在Linux中,在核心態(tài)運(yùn)行的任何操作都要優(yōu)先于用戶態(tài)進(jìn)程,這就有可能導(dǎo)致優(yōu)先級反轉(zhuǎn)問題的出現(xiàn)。例如,一個(gè)低優(yōu)先級的用戶進(jìn)程由于執(zhí)行軟/硬中斷等原因而導(dǎo)致一個(gè)高優(yōu)先級的任務(wù)得不到及時(shí)響應(yīng)。
當(dāng)前的Linux內(nèi)核加入了內(nèi)核搶占(preempt)機(jī)制。內(nèi)核搶占指用戶程序在執(zhí)行系統(tǒng)調(diào)用期間可以被搶占,該進(jìn)程暫時(shí)掛起,使新喚醒的高優(yōu)先級進(jìn)程能夠運(yùn)行。這種搶占并非可以在內(nèi)核中任意位置都能安全進(jìn)行,比如在臨界區(qū)中的代碼就不能發(fā)生搶占。臨界區(qū)是指同一時(shí)間內(nèi)不可以有超過一個(gè)進(jìn)程在其中執(zhí)行的指令序列。在Linux內(nèi)核中這些部分需要用自旋鎖保護(hù)。
內(nèi)核搶占要求內(nèi)核中所有可能為一個(gè)以上進(jìn)程共享的變量和數(shù)據(jù)結(jié)構(gòu)就都要通過互斥機(jī)制加以保護(hù),或者說都要放在臨界區(qū)中。在搶占式內(nèi)核中,認(rèn)為如果內(nèi)核不是在一個(gè)中斷處理程序中,并且不在被 spinlock等互斥機(jī)制保護(hù)的臨界代碼中,就認(rèn)為可以"安全"地進(jìn)行進(jìn)程切換。
Linux內(nèi)核將臨界代碼都加了互斥機(jī)制進(jìn)行保護(hù),同時(shí),還在運(yùn)行時(shí)間過長的代碼路徑上插入調(diào)度檢查點(diǎn),打斷過長的執(zhí)行路徑,這樣,任務(wù)可快速切換進(jìn)程狀態(tài),也為內(nèi)核搶占做好了準(zhǔn)備,搶占分為用戶搶占和內(nèi)核搶占,linux搶占發(fā)生的時(shí)機(jī):
?
用戶搶占在以下情況下產(chǎn)生:
從系統(tǒng)調(diào)用返回用戶空間
從中斷處理程序返回用戶空間
內(nèi)核搶占會發(fā)生在:
當(dāng)從中斷處理程序返回內(nèi)核空間的時(shí)候,且當(dāng)時(shí)內(nèi)核具有可搶占性;
當(dāng)內(nèi)核代碼再一次具有可搶占性的時(shí)候(如:spin_unlock時(shí));
如果內(nèi)核中的任務(wù)顯式的調(diào)用schedule();
如果內(nèi)核中的任務(wù)阻塞。
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 時(shí)鐘
? ??
計(jì)算機(jī)最基本的時(shí)間單元是時(shí)鐘周期,例如取指令、執(zhí)行指令、存取內(nèi)存等, CPU執(zhí)行指令需求時(shí)鐘來同步和推進(jìn)。時(shí)間系統(tǒng)是計(jì)算機(jī)系統(tǒng)非常重要的組成部分,所有信息包括系統(tǒng)時(shí)間、進(jìn)程的時(shí)間片、延時(shí)、使用CPU的時(shí)間、各種定時(shí)器,進(jìn)程更新后的時(shí)間片為進(jìn)程調(diào)度提供依據(jù),也就是驅(qū)動進(jìn)程的調(diào)度,任務(wù)調(diào)度與時(shí)鐘的關(guān)系非常密切。
時(shí)鐘芯片
時(shí)鐘芯片主要是提供時(shí)間源, 一般在一個(gè)計(jì)算機(jī)系統(tǒng)中存在三個(gè)時(shí)間發(fā)生器,一個(gè)用于記錄日期時(shí)間的,它就是利用電池進(jìn)行供電的一個(gè)單獨(dú)芯片——RTC,第二個(gè)是PIT(可編程間隔定時(shí)器),第三個(gè)是TSC時(shí)間戳計(jì)數(shù)器,而PIT就是產(chǎn)生IRQ0的定時(shí)器芯片。而進(jìn)行校正的就是利用TSC計(jì)數(shù)器,它在每個(gè)clock-cycle就會自動加一,不需要CPU操作,所以每個(gè)時(shí)鐘中斷產(chǎn)生時(shí)都可以利用一個(gè)全局變量記錄下TSC的值,在下次時(shí)鐘中斷時(shí)再用這個(gè)全局變量校正jieffis的值,這樣就可以記錄精準(zhǔn)的時(shí)間(TSC計(jì)數(shù)器是納秒級的)。
? ??
操作系統(tǒng)對可編程定時(shí)/計(jì)數(shù)器進(jìn)行有關(guān)初始化,然后定時(shí)/計(jì)數(shù)器就對輸入脈沖進(jìn)行計(jì)數(shù)(分頻),產(chǎn)生的三個(gè)輸出脈沖Out0、Out1、Out2各有用途,很多書都介紹了這個(gè)問題,我們只看Out0上的輸出脈沖,這個(gè)脈沖信號接到中斷控制器8259A_1的0號管腳,觸發(fā)一個(gè)周期性的中斷,我們就把這個(gè)中斷叫做時(shí)鐘中斷,時(shí)鐘中斷的周期,也就是脈沖信號的周期,我們叫做“滴答”或“時(shí)標(biāo)”(tick)。時(shí)鐘與 CPU 和系統(tǒng)總線相關(guān)的每一個(gè)操作都是由一個(gè)恒定速率的內(nèi)部時(shí)鐘脈沖來進(jìn)行同步的。機(jī)器指令的基本時(shí)間單位是機(jī)器周期 (machine cycle) 或時(shí)鐘周期 (clock cycle)? 。
時(shí)鐘中斷
“時(shí)鐘中斷”是特別重要的一個(gè)中斷,因?yàn)檎麄€(gè)操作系統(tǒng)的活動都受到它的激勵(lì)。系統(tǒng)利用時(shí)鐘中斷維持系統(tǒng)時(shí)間、促使環(huán)境的切換,以保證所有進(jìn)程共享CPU;利用時(shí)鐘中斷進(jìn)行記帳、監(jiān)督系統(tǒng)工作以及確定未來的調(diào)度優(yōu)先級等工作。可以說,“時(shí)鐘中斷”是整個(gè)操作系統(tǒng)的脈搏。
從本質(zhì)上來說,時(shí)鐘中斷只是一個(gè)周期性的信號,完全是硬件行為,該信號觸發(fā)CPU去執(zhí)行一個(gè)中斷服務(wù)程序,在Linux的0號中斷是一個(gè)時(shí)鐘中斷。在固定的時(shí)間間隔都發(fā)生一次中斷,也就是說,每秒發(fā)生該中斷的頻率都是固定的。該頻率是常量HZ,該值一般是在100 ~ 1000之間。該中斷的作用是為了定時(shí)更新系統(tǒng)日期和時(shí)間,使系統(tǒng)時(shí)間不斷地得到跳轉(zhuǎn)。另外該中斷的中斷處理函數(shù)除了更新系統(tǒng)時(shí)間外,還需要更新本地CPU統(tǒng)計(jì)數(shù)。比如更新任務(wù)的調(diào)度時(shí)間片,若遞減到0,則被調(diào)度出去而放棄CPU使用權(quán)。
時(shí)鐘框架
時(shí)鐘芯片提供節(jié)拍(tick),Linux系統(tǒng)設(shè)計(jì)一套時(shí)鐘軟件系統(tǒng),滿足應(yīng)用對時(shí)間的各種需求:比如時(shí)間片調(diào)度,系統(tǒng)時(shí)間,日期,定時(shí)器,睡眠等:
? ? ? ? ? ? ? ? ? ? ? ? ? ?Linux中的時(shí)間運(yùn)作機(jī)制
Linux時(shí)間系統(tǒng)實(shí)現(xiàn)
? ? ?
內(nèi)核對相關(guān)的時(shí)間硬件設(shè)備進(jìn)行了統(tǒng)一的封裝,定義了主要有下面兩個(gè)結(jié)構(gòu):
時(shí)鐘源設(shè)備(closk source device):抽象那些能夠提供計(jì)時(shí)功能的系統(tǒng)硬件,比如 RTC(Real Time Clock)、TSC(Time Stamp Counter),HPET,ACPI PM-Timer,PIT等。不同時(shí)鐘源提供的精度不一樣,現(xiàn)在pc大都支持高精度模式(high-resolution mode),也支持低精度模式(low-resolution mode)。
時(shí)鐘事件設(shè)備(clock event device):系統(tǒng)中可以觸發(fā) one-shot(單次)或者周期性中斷的設(shè)備都可以作為時(shí)鐘事件設(shè)備。
定時(shí)Timer
這類timer每個(gè)cpu都有一個(gè)獨(dú)立的,稱為local timer。這類timer的中斷一般都是PPI(Private Peripheral Interrupt)類型,即每個(gè)cpu都有獨(dú)立一份中斷。與PPI對應(yīng)的是SPI(Shared Peripheral Interrupt,即多個(gè)cpu共享同一個(gè)中斷。
這類timer一般是32bit寬度count,最重要的它會頻繁的溢出并產(chǎn)生timer到期中斷。
這類timer服務(wù)于tick timer(低精度)或者h(yuǎn)rtimer(高精度)。
低精度模式,local timer工作在PERIODIC模式。即timer以tick時(shí)間(1/HZ)周期性的產(chǎn)生中斷。在tick timer中處理任務(wù)調(diào)度tick、低精度timer、其他時(shí)間更新和統(tǒng)計(jì)profile。在這種模式下,所有利用時(shí)間的進(jìn)行的運(yùn)算,精度都是以tick(1/HZ)為單位的,精度較低。比如HZ=1000,那么tick=1ms。
高精度模式,local timer工作在ONESHOT模式。即系統(tǒng)可以支持hrtimer(high resolution)高精度timer,精度為local timer的計(jì)數(shù)clk達(dá)到ns級別。這種情況下把tick timer也轉(zhuǎn)換成一種hrtimer。
時(shí)間戳Timer
這類timer一個(gè)系統(tǒng)多個(gè)cpu共享一個(gè),稱為global timer。
這類timer一般是32bit/64bit寬度count,一般不會溢出產(chǎn)生中斷,系統(tǒng)實(shí)時(shí)的去讀取count的值來計(jì)算當(dāng)前的時(shí)間戳。
這類timer服務(wù)于clocksource/timekeeper。
timerwheel實(shí)現(xiàn)依賴基于系統(tǒng)tick周期性中斷,高精度時(shí)鐘定時(shí)器不在依賴系統(tǒng)的tick中斷,而是基于事件觸發(fā),內(nèi)核啟動后會進(jìn)行從低精度模式到高精度時(shí)鐘模式的切換,hrtimer模擬的tick中斷將驅(qū)動傳統(tǒng)的低精度定時(shí)器系統(tǒng)(基于時(shí)間輪)和內(nèi)核進(jìn)程調(diào)度。
低精度timer
? ? ? ??
? ? ? ? ? ? ? ? ? ? ? ? ? ?時(shí)間輪算法
? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Linux 時(shí)間輪定時(shí)器
Linux定時(shí)器時(shí)間輪分為5個(gè)級別的輪子(tv1 ~ tv5),如圖3所示。每個(gè)級別的輪子的刻度值(slot)不同,規(guī)律是次級輪子的slot等于上級輪子的slot之和。Linux定時(shí)器slot單位為1jiffy,tv1輪子分256個(gè)刻度,每個(gè)刻度大小為1jiffy。tv2輪子分64個(gè)刻度,每個(gè)刻度大小為256個(gè)jiffy,即tv1整個(gè)輪子所能表達(dá)的范圍。相鄰輪子也只有滿足這個(gè)規(guī)律,才能達(dá)到“低刻度輪子轉(zhuǎn)一圈,高刻度輪子走一格”的效果。tv3,tv4,tv5也都是分為64個(gè)刻度,因此容易算出,最高一級輪子tv5所能表達(dá)的slot范圍達(dá)到了25664646464 = 2^32 jiffies。
基于時(shí)間輪 (Timing-Wheel) 方式實(shí)現(xiàn)的定時(shí)器, timer wheel只能支持ms級別的精度, 雖然大部分時(shí)間里,時(shí)間輪可以實(shí)現(xiàn)O(1)時(shí)間復(fù)雜度,但是當(dāng)有進(jìn)位發(fā)生時(shí),不可預(yù)測的O(N)定時(shí)器級聯(lián)遷移時(shí)間,這對于低分辨率定時(shí)器來說問題不大,可是它大大地影響了定時(shí)器的精度。低分辨率定時(shí)器幾乎是為“超時(shí)”而設(shè)計(jì)的,并為此對它進(jìn)行了大量的優(yōu)化,對于這些以“超時(shí)”未目的而使用定時(shí)器,它們大多數(shù)期望在超時(shí)到來之前獲得正確的結(jié)果,然后刪除定時(shí)器,精確時(shí)間并不是它們主要的目的,例如網(wǎng)絡(luò)通信、設(shè)備IO等等。
高精度定時(shí)器Hrtimer
? ? ? ? ? ? ? ? ? ? ? ? ?
hrtimer采用紅黑樹進(jìn)行高精度定時(shí)器的管理, 通過將高精度時(shí)鐘硬件的下次中斷觸發(fā)時(shí)間設(shè)置為紅黑樹中最早到期的 Timer 的時(shí)間,時(shí)鐘到期后從紅黑樹中得到下一個(gè) Timer 的到期時(shí)間,并設(shè)置硬件,如此循環(huán)反復(fù)。
在高精度時(shí)鐘模式下,操作系統(tǒng)內(nèi)核仍然需要周期性的tick中斷,以便刷新內(nèi)核的一些任務(wù)。前面可以知道, hrtimer是基于事件的,不會周期性出發(fā)tick中斷,所以為了實(shí)現(xiàn)周期性的tick中斷(dynamic tick):系統(tǒng)創(chuàng)建了一個(gè)模擬 tick 時(shí)鐘的特殊 hrtimer,將其超時(shí)時(shí)間設(shè)置為一個(gè)tick時(shí)長,在超時(shí)回來后,完成對應(yīng)的工作,然后再次設(shè)置下一個(gè)tick的超時(shí)時(shí)間,以此達(dá)到周期性tick中斷的需求。引入了dynamic tick,是為了能夠在使用高精度時(shí)鐘的同時(shí)節(jié)約能源,,這樣在產(chǎn)生tickless 情況下,會跳過一些 tick。
?
本期結(jié)束,我們下期再見!
想要獲取linux調(diào)度全景指南精簡版,關(guān)注公眾號回復(fù)“調(diào)度”即可獲取。回復(fù)其他消息,獲取更多內(nèi)容;
? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ? ??
往期推薦
Linux調(diào)度系統(tǒng)全景指南(上篇)
如何成為一名大廠的優(yōu)秀員工?
C++模版的本質(zhì)
C++內(nèi)存管理全景指南
云網(wǎng)絡(luò)丟包故障定位全景指南
? ? ? ? ? ?
掃碼二維碼
獲取更多精彩內(nèi)容
總結(jié)
以上是生活随笔為你收集整理的Linux调度系统全景指南(中篇)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何成为一名大厂的优秀员工?
- 下一篇: Linux调度系统全景指南(下篇)