欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

柚子快報(bào)邀請(qǐng)碼778899分享:QNX為什么是安全的操作系統(tǒng)?

柚子快報(bào)邀請(qǐng)碼778899分享:QNX為什么是安全的操作系統(tǒng)?

http://yzkb.51969.com/

來(lái)自微信公眾號(hào):車(chē)端軟件開(kāi)發(fā),大佬講的很好,在此整理補(bǔ)充做個(gè)筆記

目錄

QNX介紹

QNX特點(diǎn)

QNX是嵌入式硬實(shí)時(shí)的微內(nèi)核操作系統(tǒng)

QNX是類(lèi)UNIX操作系統(tǒng)

QNX是功能安全和信息安全的操作系統(tǒng)

QNX其他特性

1. QNX調(diào)度算法及策略

2. QNX IPC通訊機(jī)制

3. QNX 的IDE集成開(kāi)發(fā)環(huán)境

中國(guó)自動(dòng)輔助駕駛領(lǐng)域基礎(chǔ)平臺(tái)軟件所遇到的問(wèn)題

QNX算法移植以及性能優(yōu)化舉例

算法移植

分享常見(jiàn)的QNX性能優(yōu)化項(xiàng)

IPC優(yōu)化

編譯選項(xiàng)優(yōu)化

驅(qū)動(dòng)級(jí)別優(yōu)化

網(wǎng)絡(luò)協(xié)議棧優(yōu)化

系統(tǒng)API優(yōu)化

用戶接口優(yōu)化

QNX提供Momentics?IDE環(huán)境對(duì)算法進(jìn)行性能分析

QNX提供了onboard debug也支持應(yīng)用程序調(diào)用棧的實(shí)時(shí)保存及相應(yīng)的GDB,在調(diào)查一些忙等的現(xiàn)場(chǎng)會(huì)有很大的幫助。

QNX調(diào)度算法

基本調(diào)度算法

調(diào)度策略

先進(jìn)先出(FIFO)

輪詢(xún)(Round Robin)

零星調(diào)度(Sporadic)

什么時(shí)候會(huì)發(fā)生調(diào)度?

中斷與優(yōu)先級(jí)

多CPU上的線程調(diào)度

自適應(yīng)分區(qū)調(diào)度算法

分區(qū)調(diào)度

自適應(yīng)分區(qū)調(diào)度

自適應(yīng)分區(qū)調(diào)度與線程優(yōu)先級(jí)

自適應(yīng)分區(qū)調(diào)度富裕算力分配

“關(guān)鍵線程”與“關(guān)鍵分區(qū)”

關(guān)鍵線程的破產(chǎn)

自適應(yīng)分區(qū)繼承

自適應(yīng)分區(qū)的小結(jié)

QNX介紹

????????QNX成立于1980年,是全世界第一個(gè)類(lèi)UNIX的符合POSIX標(biāo)準(zhǔn)的微內(nèi)核的硬實(shí)時(shí)操作系統(tǒng),在過(guò)去的幾十年中廣泛的應(yīng)用在汽車(chē)、工業(yè)自動(dòng)化、國(guó)防、航空航天、醫(yī)療、核電和通信等領(lǐng)域,提供以嵌入式操作系統(tǒng)為核心的中間件和基礎(chǔ)軟件解決方案。

????????到目前為止,世界上幾乎所有的主機(jī)廠都采用了基于QNX操作系統(tǒng)的軟件技術(shù)。全球top?25家電動(dòng)汽車(chē)廠家,其中24家在使用QNX的軟件操作系統(tǒng),例如,中國(guó)的小鵬汽車(chē)自動(dòng)輔助駕駛系統(tǒng)Xpilot3.0和Xpilot3.5基于QNX通過(guò)TUV萊茵ISO26262 ASIL D功能安全的硬實(shí)操作系統(tǒng),合眾新能源汽車(chē)的哪吒S采用QNX Hypervisor打造其全新科技感智能座艙,并在其全棧自研的TA PILOT 3.0智能駕駛系統(tǒng)中搭載QNX OS for Safety操作系統(tǒng),實(shí)現(xiàn)多種場(chǎng)景下的智能輔助駕駛,又如零跑汽車(chē)在其量產(chǎn)的第三代高端純電SUV—零跑C11和智能純電橋車(chē)C01中均采用了QNX Neutrino實(shí)時(shí)操作系統(tǒng)和QNX Hypervisor,旨在為中國(guó)消費(fèi)者帶來(lái)更個(gè)性化與舒適的駕駛體驗(yàn)。除此之外,高合即將發(fā)布的豪華純電超跑HiPhi Z的自動(dòng)輔助駕駛平臺(tái)使用的是英偉達(dá)Orin-X芯片和 QNX 嵌入式硬實(shí)時(shí)操作系統(tǒng)。

QNX特點(diǎn)

QNX是嵌入式硬實(shí)時(shí)的微內(nèi)核操作系統(tǒng)

有硬實(shí)時(shí)、微內(nèi)核、模塊化、弱耦合、分布式的特點(diǎn),從1980年誕生之初就是基于SOA架構(gòu)設(shè)計(jì),基于Client-Server的模型,具體表現(xiàn)為:

硬實(shí)時(shí):任何切換時(shí)間和中斷時(shí)延速度快,所有的任務(wù)響應(yīng)均為確定性deterministic行為。微內(nèi)核:除調(diào)度、進(jìn)程管理、中斷及操作系統(tǒng)核心的功能外,其余部分都處于用戶態(tài),包括驅(qū)動(dòng)、協(xié)議棧、文件系統(tǒng)及功能模塊等。模塊化:操作系統(tǒng)的各個(gè)功能單元都模塊化設(shè)計(jì),內(nèi)存保護(hù),并且相互隔離,可按照需要?jiǎng)討B(tài)加載或卸載,基于消息機(jī)制通信,按照Client-Server的架構(gòu)設(shè)計(jì)。弱耦合:模塊與模塊之間互不影響,都在獨(dú)立的虛擬地址空間運(yùn)行。分布式:局域網(wǎng)內(nèi)的QNX系統(tǒng)對(duì)于用戶角度可以認(rèn)為是一臺(tái)QNX系統(tǒng),資源可以復(fù)用。

微內(nèi)核則和宏內(nèi)核結(jié)構(gòu)相反,它提倡內(nèi)核中的功能模塊盡可能的少。內(nèi)核只提供最核心的功能,比如任務(wù)調(diào)度,中斷處理等等。其他實(shí)際的模塊功能如進(jìn)程管理、存儲(chǔ)器管理、文件管理……這些則被移出內(nèi)核,變成一個(gè)個(gè)服務(wù)進(jìn)程,和用戶進(jìn)程同等級(jí),只是它們是一種特殊的用戶進(jìn)程。

QNX是類(lèi)UNIX操作系統(tǒng)

????????遵循POSIX的最高級(jí)別PSE54標(biāo)準(zhǔn)(注:POSIX標(biāo)準(zhǔn)有四個(gè)等級(jí)PSE51, PSE52, PSE53和 PSE54, 在RTOS實(shí)時(shí)操作系統(tǒng)的世界里,只有QNX操作系統(tǒng)是PSE54標(biāo)準(zhǔn)的,因?yàn)镼NX誕生之初就是類(lèi)UNIX系統(tǒng)按照POSIX標(biāo)準(zhǔn)編寫(xiě)),因此基于開(kāi)源的應(yīng)用程序以及一些開(kāi)源的中間件都可以無(wú)縫的移植到QNX系統(tǒng)之上。QNX Microkernel和Process Manager組成QNX最小系統(tǒng)Procnto,其他如驅(qū)動(dòng)程序、協(xié)議棧、文件系統(tǒng)、應(yīng)用程序都作為一個(gè)獨(dú)立的模塊運(yùn)行在QNX系統(tǒng)之上。

????????POSIX(Portable Operating System Interface,可移植操作系統(tǒng)接口)是一個(gè)IEEE標(biāo)準(zhǔn),旨在提高各種UNIX操作系統(tǒng)上運(yùn)行的軟件的可移植性和兼容性。它定義了操作系統(tǒng)應(yīng)該為應(yīng)用程序提供的接口標(biāo)準(zhǔn),使得遵循POSIX標(biāo)準(zhǔn)的軟件能夠在不同的操作系統(tǒng)上運(yùn)行,而無(wú)需進(jìn)行大量的修改。

????????POSIX標(biāo)準(zhǔn)有四個(gè)等級(jí):PSE51、PSE52、PSE53和PSE54。這些等級(jí)代表了不同的兼容性和功能級(jí)別,其中PSE54是最高級(jí)別。在RTOS(實(shí)時(shí)操作系統(tǒng))的世界中,QNX操作系統(tǒng)是唯一一個(gè)符合PSE54標(biāo)準(zhǔn)的系統(tǒng)。這是因?yàn)镼NX從誕生之初就是基于類(lèi)UNIX系統(tǒng)并按照POSIX標(biāo)準(zhǔn)編寫(xiě)的,因此它具有高度的兼容性和可移植性。

遵循POSIX最高標(biāo)準(zhǔn)(PSE54)意味著QNX操作系統(tǒng)完全遵循了POSIX定義的所有接口和功能要求。這使得基于開(kāi)源的應(yīng)用程序以及一些開(kāi)源的中間件,只要它們也遵循POSIX標(biāo)準(zhǔn),就可以無(wú)縫地移植到QNX系統(tǒng)之上。換句話說(shuō),這些應(yīng)用程序和中間件無(wú)需進(jìn)行大量的修改或重新編寫(xiě),就可以直接在QNX系統(tǒng)上運(yùn)行,從而大大簡(jiǎn)化了移植過(guò)程并提高了效率。

QNX Microkernel和Process Manager組成QNX的最小系統(tǒng)Procnto,為系統(tǒng)提供了基本的內(nèi)核和進(jìn)程管理功能。其他如驅(qū)動(dòng)程序、協(xié)議棧、文件系統(tǒng)、應(yīng)用程序等都作為獨(dú)立的模塊運(yùn)行在QNX系統(tǒng)之上。這種模塊化設(shè)計(jì)使得QNX系統(tǒng)非常靈活和可擴(kuò)展,可以根據(jù)不同的需求添加或刪除模塊。

總的來(lái)說(shuō),POSIX最高標(biāo)準(zhǔn)(PSE54)為QNX操作系統(tǒng)提供了高度的兼容性和可移植性,使得基于POSIX標(biāo)準(zhǔn)的應(yīng)用程序和中間件可以無(wú)縫地移植到QNX系統(tǒng)上。這種特性使得QNX在RTOS領(lǐng)域具有獨(dú)特的優(yōu)勢(shì),能夠滿足各種復(fù)雜的實(shí)時(shí)應(yīng)用需求。

QNX是功能安全和信息安全的操作系統(tǒng)

QNX通過(guò)功能安全TUV萊茵ISO 26262 ASIL D最高等級(jí)道路車(chē)輛最高功能等級(jí)安全認(rèn)證,包括QNX 操作系統(tǒng)、QNX Hypervisor虛擬化和Graphic Monitor圖形監(jiān)控子系統(tǒng)以及QNX IPC通訊機(jī)制black channel,同時(shí)黑莓是網(wǎng)絡(luò)信息安全標(biāo)準(zhǔn)ISO/SAE 21434 委員會(huì)基礎(chǔ)軟件組唯一成員。

QNX其他特性

1. QNX調(diào)度算法及策略

QNX調(diào)度算法有很多種,本質(zhì)上基于優(yōu)先級(jí)搶占式。QNX的線程優(yōu)先級(jí)是一個(gè)0-255的數(shù)字,數(shù)字越大優(yōu)先級(jí)越高。在QNX上有三種基本調(diào)度策略,可以單獨(dú)使用也可以組合使用,包括基于時(shí)間片輪詢(xún)Round Robin、優(yōu)先級(jí)搶占式FIFO和基于時(shí)間Budget的Sporadic算法。同時(shí)QNX還提供APS自適應(yīng)分區(qū)調(diào)度算法,在CPU滿負(fù)荷的場(chǎng)景下保證低優(yōu)先級(jí)的任務(wù)有調(diào)度的機(jī)會(huì),不被“餓死”。

2. QNX IPC通訊機(jī)制

QNX除了支持Native的IPC機(jī)制如Massage passing、Signal等,同時(shí)還提供POSIX標(biāo)準(zhǔn)的IPC例如MessageQ、Piple、Shared Memory等IPC通訊方式,多種IPC方式供用戶在不同的應(yīng)用場(chǎng)景下進(jìn)行選擇。

3. QNX 的IDE集成開(kāi)發(fā)環(huán)境

QNX提供基于Eclipse的Momentics IDE集成開(kāi)發(fā)環(huán)境,供用戶進(jìn)行基于以太網(wǎng)Software GDB的代碼級(jí)的編譯調(diào)試或系統(tǒng)性能分析,可實(shí)時(shí)以圖形化的方式,查看進(jìn)程資源、系統(tǒng)日志、CPU占用情況,內(nèi)存使用情況,進(jìn)程間通信以及Coredump等。

中國(guó)自動(dòng)輔助駕駛領(lǐng)域基礎(chǔ)平臺(tái)軟件所遇到的問(wèn)題

????????近年來(lái)自動(dòng)輔助駕駛領(lǐng)域非?;鸨S多國(guó)內(nèi)外的主機(jī)廠都逐步在量產(chǎn)項(xiàng)目中開(kāi)發(fā)以及發(fā)布L2+的功能,當(dāng)我們回顧這幾年來(lái)快速發(fā)展會(huì)發(fā)現(xiàn),大多數(shù)的自動(dòng)輔助駕駛的人才都來(lái)自于Robotaxi,自動(dòng)駕駛算法初創(chuàng)公司或大學(xué)研究機(jī)構(gòu),特別是算法人才。這就有個(gè)顯著的特點(diǎn),在這些公司里面的大多數(shù)項(xiàng)目,最初都是基于工控機(jī)+英偉達(dá)顯卡(大多數(shù)用英偉達(dá)的GPU,少數(shù)用AMD的)+開(kāi)源的操作系統(tǒng)+來(lái)自于開(kāi)源的算法,其實(shí)和汽車(chē)電子的安全性本身毫無(wú)關(guān)系,唯一的好處就是快,容易盡早演示,盡快融資。

????????這些算法人才加入主機(jī)廠之后,更傾向于用以前最熟悉的開(kāi)發(fā)方式,這樣好盡快的出演示成果,也就是英偉達(dá)的SOC+開(kāi)源的操作系統(tǒng)+來(lái)自于開(kāi)源的算法。另一方面,在自動(dòng)輔助駕駛項(xiàng)目中,一般主機(jī)廠會(huì)把控制器平臺(tái)即硬件和平臺(tái)軟件外包給外部的Tier1來(lái)做,類(lèi)似于一臺(tái)PC電腦,而自己開(kāi)發(fā)應(yīng)用和算法。

????????一般主機(jī)廠也有平臺(tái)組,負(fù)責(zé)部分的驅(qū)動(dòng)及驅(qū)動(dòng)以上的中間件的整合,系統(tǒng)組負(fù)責(zé)系統(tǒng)設(shè)計(jì)統(tǒng)籌,功能安全團(tuán)隊(duì)負(fù)責(zé)整體的功能安全,而算法團(tuán)隊(duì)負(fù)責(zé)算法應(yīng)用的開(kāi)發(fā)和實(shí)現(xiàn),那么問(wèn)題就來(lái)了,除純算法團(tuán)隊(duì)外,一般國(guó)外的主機(jī)廠都會(huì)有一個(gè)成建制的叫算法嵌入式工程實(shí)現(xiàn)的團(tuán)隊(duì),負(fù)責(zé)算法在非工控機(jī)的嵌入式環(huán)境和實(shí)時(shí)操作系統(tǒng)的優(yōu)化實(shí)現(xiàn)落地,這樣的團(tuán)隊(duì)即要懂一點(diǎn)算法架構(gòu),又要懂嵌入式軟件的開(kāi)發(fā)和硬件特性,又要對(duì)操作系統(tǒng)有足夠的理解。

????????而在中國(guó)的許多主機(jī)廠,沒(méi)有看到有這樣一個(gè)團(tuán)隊(duì),甚至這樣的人才存在。因此不少項(xiàng)目由于開(kāi)發(fā)周期緊,人員不具備嵌入式系統(tǒng)開(kāi)發(fā)的經(jīng)驗(yàn),會(huì)采用更接近于robotaxi的方式開(kāi)發(fā),即英偉達(dá)SOC中的處理器(類(lèi)似工控機(jī)),SOC中的GPU(類(lèi)似顯卡)和開(kāi)源操作系統(tǒng)+未經(jīng)優(yōu)化的各種開(kāi)源算法,在滿足基本功能和有限性能的前提下,功能安全團(tuán)隊(duì)的建議通常會(huì)被直接忽略,因?yàn)橐獫M足極短的量產(chǎn)時(shí)間,在國(guó)內(nèi)主機(jī)廠軍備競(jìng)賽中領(lǐng)先才是最重要的,這在歐美的主機(jī)廠是不可想象的。在這一點(diǎn)上,中國(guó)也有許多人才儲(chǔ)備充足并且付責(zé)任的主機(jī)廠做的非常好,特別是有專(zhuān)門(mén)的經(jīng)驗(yàn)豐富的算法工程實(shí)現(xiàn)的團(tuán)隊(duì)負(fù)責(zé)優(yōu)化落地。期待在不久的將來(lái),能夠有更多的主機(jī)廠重視起這個(gè)問(wèn)題,在中國(guó)有更多的行業(yè)人才能夠填補(bǔ)這一空白。

QNX算法移植以及性能優(yōu)化舉例

QNX提供ADAS reference平臺(tái)產(chǎn)品,里面涵蓋了Sensor Framework,networking,open source modules,第三方的SDK以及一些參考設(shè)計(jì),其中sensor Framework提供了ADAS的一些基本庫(kù)。

算法移植

自動(dòng)輔助駕駛以開(kāi)源的算法居多,由于QNX符合POSIX PSE54標(biāo)準(zhǔn),API兼容基本一致,因此各類(lèi)開(kāi)源算法可以很方便的移植到QNX的平臺(tái)上,使用QNX的工具鏈進(jìn)行編譯并運(yùn)行,但是雖然API是一致的,但由于實(shí)時(shí)操作系統(tǒng)的特性,表現(xiàn)的行為會(huì)有所差異,需要對(duì)系統(tǒng)進(jìn)行優(yōu)化調(diào)整。

QNX有專(zhuān)門(mén)的team來(lái)根據(jù)roadmap以及客戶需求移植一些開(kāi)源軟件,比如ROS/ROS2,比如OpenCV和vSomeIP,我們也會(huì)負(fù)責(zé)后期的維護(hù)。

分享常見(jiàn)的QNX性能優(yōu)化項(xiàng)

IPC優(yōu)化

????????QNX支持絕大部分主流POSIX系統(tǒng)常見(jiàn)的IPC方式,同時(shí)也有其獨(dú)特的原生IPC方式,Message-passing。在自動(dòng)輔助駕駛方案設(shè)計(jì)中,常有公司會(huì)將UDS、DDS做為軟件通信總線的架構(gòu)方案原封不動(dòng)地從Linux照搬到QNX上。從功能上看,這樣的跨平臺(tái)方案可以使得代碼重用并且功能沒(méi)有區(qū)別。但從性能角度考慮,由于QNX獨(dú)特內(nèi)核架構(gòu),這并不是高效的解決方案。不同于Linux的宏內(nèi)核架構(gòu),QNX為了安全性和實(shí)時(shí)性采用了微內(nèi)核架構(gòu),絕大部分的系統(tǒng)服務(wù),比如網(wǎng)絡(luò)協(xié)議棧,它是完全運(yùn)行在內(nèi)核之外以服務(wù)(Resource Manager)的方式運(yùn)行。如果采用UDS(Unix Domain Socket)這用基于網(wǎng)絡(luò)服務(wù)(嚴(yán)格意義上講,UDS并不需要經(jīng)過(guò)網(wǎng)絡(luò)協(xié)議棧,但也是需要經(jīng)過(guò)QNX的網(wǎng)絡(luò)服務(wù)io-pkt支持)的通訊方式,那么所有的數(shù)據(jù)報(bào)都需要經(jīng)過(guò)網(wǎng)絡(luò)服務(wù)中轉(zhuǎn),相比直接通訊多了一次IPC,這就帶來(lái)了系統(tǒng)資源的浪費(fèi)。建議的優(yōu)化方案是采用更高效的IPC方式,一般情況下,中小量的數(shù)據(jù)量傳輸建議使用message-passing,特別大的數(shù)量使用shared memory方式。另外,一些開(kāi)源軟件也會(huì)大量使用FIFO,PIPE等IPC,盡管QNX支持這類(lèi)使用,但是我們也建議改成更高效的message passing方式,以減少單次IPC的開(kāi)銷(xiāo)。

????????IPC(Inter-Process Communication,進(jìn)程間通信)是操作系統(tǒng)中不同進(jìn)程之間共享信息和通信的機(jī)制。在自動(dòng)輔助駕駛方案設(shè)計(jì)中,IPC的性能優(yōu)化對(duì)于確保系統(tǒng)的實(shí)時(shí)性和效率至關(guān)重要。

????????QNX操作系統(tǒng)支持多種主流的POSIX系統(tǒng)常見(jiàn)的IPC方式,如Unix Domain Socket(UDS)、DDS等。同時(shí),它還有自己獨(dú)特的原生IPC方式,即消息傳遞(Message-passing)。在跨平臺(tái)方案設(shè)計(jì)中,盡管將UDS、DDS等從Linux照搬到QNX上可以實(shí)現(xiàn)代碼重用和功能無(wú)差異,但從性能角度來(lái)看,這并不是最優(yōu)的選擇。

????????針對(duì)IPC的優(yōu)化,建議在QNX中采用更高效的通信方式。對(duì)于中小量的數(shù)據(jù)量傳輸,建議使用message-passing方式。Message-passing是QNX原生支持的IPC方式,具有高效、靈活的特點(diǎn),能夠減少單次IPC的開(kāi)銷(xiāo)。對(duì)于特別大的數(shù)據(jù)量傳輸,則建議使用共享內(nèi)存(Shared Memory)方式。共享內(nèi)存允許不同進(jìn)程直接訪問(wèn)同一塊內(nèi)存區(qū)域,從而實(shí)現(xiàn)高效的數(shù)據(jù)共享和通信。

????????此外,盡管QNX支持FIFO、PIPE等IPC方式,但在實(shí)際應(yīng)用中,也建議將這些方式替換為更高效的message passing方式。這樣可以進(jìn)一步減少單次IPC的開(kāi)銷(xiāo),提高系統(tǒng)的整體性能。

編譯選項(xiàng)優(yōu)化

????????QNX采用GCC的框架,出于安全性的考慮,QNX的編譯器版本更新相比沒(méi)有開(kāi)源社區(qū)激進(jìn),相比會(huì)慢一些。比如SDP 7.0采用的是GCC 5.4.0,SPD 7.1采用的GCC 8.3.0,即將推出的SDP Moun會(huì)采用GCC 11.X。有時(shí)候會(huì)發(fā)現(xiàn),運(yùn)行同樣一個(gè)算法庫(kù),QNX性能會(huì)比開(kāi)源低,那很有可能是由于編譯版本或編譯優(yōu)化選項(xiàng)差異的原因。因?yàn)樵贚inux系統(tǒng)上默認(rèn)的ARMv8的編譯優(yōu)化選項(xiàng)是滿級(jí)的,而QNX默認(rèn)不打開(kāi)ARMv8的優(yōu)化選項(xiàng),因此程序編譯時(shí)候需要打開(kāi)相關(guān)編譯選項(xiàng)才能獲得最佳性能,因?yàn)镼NX基于安全性考慮某些編譯選項(xiàng)在默認(rèn)編譯的時(shí)候并沒(méi)有打開(kāi)會(huì)導(dǎo)致性能問(wèn)題。

QNX采用GCC的編譯框架,意味著其源代碼通過(guò)GCC(GNU Compiler Collection)進(jìn)行編譯,生成可執(zhí)行文件。GCC是一個(gè)廣泛使用的開(kāi)源編譯器,支持多種編程語(yǔ)言和平臺(tái)。

驅(qū)動(dòng)級(jí)別優(yōu)化

????????如網(wǎng)絡(luò)/存儲(chǔ)設(shè)備驅(qū)動(dòng),根據(jù)以往的經(jīng)驗(yàn),大部分的性能問(wèn)題的瓶頸在設(shè)備驅(qū)動(dòng)這層。特別是新的硬件、新的驅(qū)動(dòng),要注意根據(jù)QNX系統(tǒng)服務(wù)層做好適配,驅(qū)動(dòng)的好壞,往往是除硬件本身之外最主要的性能影響因素。我們遇到非常多的來(lái)自驅(qū)動(dòng)層面的空等,忙等,最終導(dǎo)致系統(tǒng)機(jī)能的冗余浪費(fèi)。

網(wǎng)絡(luò)協(xié)議棧優(yōu)化

?????????除了網(wǎng)絡(luò)驅(qū)動(dòng)的優(yōu)化,QNX的網(wǎng)絡(luò)協(xié)議棧io-pkt本身也提供了豐富的參數(shù),可以根據(jù)具體使用的應(yīng)用場(chǎng)景來(lái)達(dá)到性能的最優(yōu)化。另外,使用QNX SDP 7.1及后續(xù)版本的用戶,可以使用最新的版本網(wǎng)絡(luò)協(xié)議棧io-sock,它對(duì)多核CPU的利用和大并發(fā)小包數(shù)據(jù)的處理能力有顯著地提升。兩個(gè)協(xié)議棧各有千秋,實(shí)際上大量的案例證明,用戶并沒(méi)有達(dá)到io-pkt的性能瓶頸,socket buffer 不足導(dǎo)致丟包,typed memory pool分配的不夠?qū)е率瞻l(fā)阻塞等等,這些都可以通過(guò)配置以及API層面的優(yōu)化達(dá)到性能提升。

系統(tǒng)API優(yōu)化

????????如memory allocation,memory copy等,QNX提供jemalloc根據(jù)實(shí)際應(yīng)用場(chǎng)景提供額外內(nèi)存泄漏手段,提供更多的功能,jemalloc比default的malloc效率更高,特別是對(duì)于大量線程高并發(fā)調(diào)用的場(chǎng)景。

用戶接口優(yōu)化

????????QNX 提供的底層接口,尤其是一些自有API,是有不少細(xì)微差別的,比如sendmsg()和sendmmsg(), 用戶往往會(huì)比較熟悉前者,用于socket的發(fā)包,但是后者提供了message 隊(duì)列來(lái)實(shí)現(xiàn)不增加IPC的基礎(chǔ)上提高了整體的吞吐率。又比如mmap(),我們提供了一些QNX獨(dú)有的flag來(lái)應(yīng)對(duì)不同的memory mapping 場(chǎng)景,如MAP_ANON與MAP_PHYS的配合,才代表申請(qǐng)物理連續(xù)memory region而MAP_LAZY 更會(huì)延遲內(nèi)存的申請(qǐng)分配。了解并熟悉每個(gè)接口的參數(shù)配置以及相近命名接口的應(yīng)用場(chǎng)景會(huì)對(duì)開(kāi)發(fā)幫助很大。

QNX提供Momentics?IDE環(huán)境對(duì)算法進(jìn)行性能分析

????????如memory leak,application profile等,同時(shí)提供kernel trace進(jìn)行分析,在抓取的時(shí)間段中可以獲得每個(gè)時(shí)間點(diǎn)的事件、中斷響應(yīng),給出優(yōu)化建議。我們也支持自定義的kernel 事件,來(lái)讓用戶可以精確的了解代碼片段的運(yùn)行情況。

QNX提供了onboard debug也支持應(yīng)用程序調(diào)用棧的實(shí)時(shí)保存及相應(yīng)的GDB,在調(diào)查一些忙等的現(xiàn)場(chǎng)會(huì)有很大的幫助。

????????最后總結(jié)一下,即便作為ISO26262 ASIL-D安全認(rèn)證的硬實(shí)時(shí)性操作系統(tǒng),QNX在系統(tǒng)性能上也并沒(méi)有落后宏內(nèi)核系統(tǒng)。只要合理地使用和優(yōu)化,它的性能表現(xiàn)同樣非常優(yōu)秀,同時(shí)占用更低系統(tǒng)資源。QNX有著豐富的算法移植和優(yōu)化經(jīng)驗(yàn)?zāi)芙o到用戶,同時(shí)QNX提供一系列的手段和工具去定位算法性能的瓶頸。??

QNX調(diào)度算法

作為一個(gè)硬實(shí)時(shí)操作系統(tǒng),QNX是一個(gè)基于優(yōu)先級(jí)搶占的系統(tǒng)。這也導(dǎo)致其基本調(diào)度算法相對(duì)比較簡(jiǎn)單。因?yàn)椴恍枰駝e的通用操作系統(tǒng)考慮一些復(fù)雜的“公平性”,只需要保證“優(yōu)先級(jí)最高的線程最優(yōu)先得到 CPU”就可以了。

基本調(diào)度算法

調(diào)度算法,是基于優(yōu)先級(jí)的。QNX的線程優(yōu)先級(jí),是一個(gè)0-255的數(shù)字,數(shù)字越大優(yōu)先級(jí)越高。所以,優(yōu)先級(jí)0是內(nèi)核中的idle線程。同時(shí),優(yōu)先級(jí)64是一個(gè)分界嶺。就是說(shuō),優(yōu)先級(jí)1 – 63 是非特權(quán)優(yōu)先級(jí),一般用戶都可以用,而64 – 255必須是有root權(quán)限的線程才以設(shè)。這個(gè)“優(yōu)先級(jí)64”分界線,如果有必要,還可以通過(guò)啟動(dòng)Procnto時(shí)傳 –P 來(lái)改變。

內(nèi)核中的idle線程是Linux系統(tǒng)在初始化時(shí)為每個(gè)CPU創(chuàng)建的一個(gè)線程。idle線程的目的是在不影響性能的前提下,盡可能減少功耗。一般來(lái)說(shuō),idle線程的優(yōu)先級(jí)被設(shè)置為很低,這是因?yàn)樗辉跊](méi)有其他進(jìn)程需要運(yùn)行時(shí)才運(yùn)行,用以降低功耗

調(diào)度算法的對(duì)像是線程,而線程在QNX上,有大約20個(gè)狀態(tài)。(參考 /usr/include/sys/states.h)在這許多狀態(tài)中,跟調(diào)度有關(guān)的,其實(shí)只有 STATE_RUNNING和STATE_READY兩個(gè)狀態(tài)。STATE_RUNNING是線程當(dāng)前正在使用CPU,而STATE_READY是等著被執(zhí)行(被調(diào)度)的線程。其他狀態(tài)的線程,處于某種“阻塞”狀態(tài)中,調(diào)度算法不需要關(guān)注。

所以在調(diào)度算法看來(lái),整個(gè)系統(tǒng)里的線程像這樣:

圖 1 有兩個(gè)CPU的系統(tǒng)里的線程

這是一個(gè)有兩個(gè)CPU的系統(tǒng),所以可以看到有兩個(gè)RUNNING線程;對(duì)于 BLOCK THREAD,它們不參于調(diào)度,所以不需要考慮它們的優(yōu)先級(jí)。

調(diào)度策略

在QNX上實(shí)質(zhì)上只有三種基本調(diào)度策略,“輪詢(xún)”(Round Robin),“先進(jìn)先出”(First in first out)和"零星調(diào)度”(Sporadic) 算法。雖然形式上還有一個(gè)“其他”,但“其他”跟“輪詢(xún)”是一樣的。這些調(diào)度策略,在 /usr/include/sched.h 里有定義。(SCHED_FIFO, SCHED_RR, SCHED_SPORADIC, SCHED_OTHER)

先進(jìn)先出(FIFO)

在FIFO策略中,一個(gè)線程可以一直占用CPU,直到它執(zhí)行完。這意味著如果一個(gè)線程正在做一個(gè)非常長(zhǎng)的數(shù)學(xué)計(jì)算而且沒(méi)有其他更高優(yōu)先級(jí)的線程就緒,這個(gè)線程就會(huì)一直執(zhí)行下去。擁有相同優(yōu)先級(jí)的線程會(huì)怎么樣呢?它們會(huì)一直等待,當(dāng)然更低優(yōu)先級(jí)的線程也得不到執(zhí)行。如果運(yùn)行中的線程退出或者自愿放棄CPU的使用權(quán),此時(shí)內(nèi)核會(huì)尋找其他擁有相同優(yōu)先級(jí)的就緒線程。如果沒(méi)有這樣的線程,內(nèi)核會(huì)繼續(xù)尋找更低優(yōu)先級(jí)的就緒線程。自愿放棄CPU有以下兩種情況。如果線程進(jìn)入sleep,或被信號(hào)量阻塞,此時(shí)更低優(yōu)先級(jí)的線程可以運(yùn)行。另外一個(gè)是一個(gè)系統(tǒng)調(diào)用sched_yield(),僅僅讓渡CPU給相同優(yōu)先級(jí)的線程。如果一個(gè)線程調(diào)用了sched_yield(),而且沒(méi)有相同優(yōu)先級(jí)的線程就緒,此時(shí)會(huì)繼續(xù)執(zhí)行調(diào)用sched_yield()的線程。

輪詢(xún)(Round Robin)

????????Round Robin的調(diào)度策略和FIFO類(lèi)似,但是如果有相同優(yōu)先級(jí)的線程就緒的話,當(dāng)前線程不會(huì)永遠(yuǎn)執(zhí)行下去。當(dāng)前線程只執(zhí)行一個(gè)系統(tǒng)定義好的時(shí)間片的時(shí)長(zhǎng),時(shí)間片的長(zhǎng)度可以使用函數(shù)sched_rr_get_interval()獲取。時(shí)間片的長(zhǎng)度通常是4ms,不過(guò)實(shí)際上是ticksize的4倍,ticksize的值可以通過(guò)ClockPeriod()查詢(xún)。

????????內(nèi)核啟動(dòng)一個(gè)RR線程的時(shí)候會(huì)開(kāi)始計(jì)時(shí),RR線程運(yùn)行一段時(shí)間后分配給它的時(shí)間片將會(huì)用完。此時(shí)內(nèi)核會(huì)檢查是否有相同優(yōu)先級(jí)的線程處于就緒狀態(tài),如果有,內(nèi)核會(huì)讓該線程開(kāi)始執(zhí)行,否則內(nèi)核會(huì)繼續(xù)讓之前的線程執(zhí)行并會(huì)再分配一個(gè)時(shí)間片給該線程。

????????強(qiáng)調(diào)一下,調(diào)度策略只限于在READY隊(duì)列里的線程,優(yōu)線級(jí)最高的線程有不止一個(gè)時(shí),才會(huì)用到。如果線程不再 READY,或是有別的更高優(yōu)先級(jí)的線程 READY了,那就高優(yōu)先級(jí)線程獲取CPU,沒(méi)有什么策略可言。

????????“輪詢(xún)調(diào)度”(Round Robin)跟平時(shí)生活里排隊(duì)的情形差不多,晚到的人排在隊(duì)尾,早到的人排在隊(duì)首,等到叫號(hào)(調(diào)度)的時(shí)候,隊(duì)首的人會(huì)被先叫到 。如下圖所示:

圖 2 論詢(xún)調(diào)度示意

首先在CPU 1上運(yùn)行的線程4,被挪入優(yōu)先級(jí)15的隊(duì)列末尾然后重新搜索可執(zhí)行的最高優(yōu)先級(jí)線程,這里有優(yōu)先級(jí)15隊(duì)列上的線程3和4線程3因?yàn)樵陉?duì)列最前端,它被選擇得到CPU,線程3的狀態(tài)變?yōu)镽UNNING,在CPU1上執(zhí)行

可以預(yù)期,當(dāng)下一次調(diào)度發(fā)生時(shí),線程3會(huì)被挪入優(yōu)先級(jí)15隊(duì)列末尾,而線程4會(huì)被調(diào)度執(zhí)行,這樣線程3和4會(huì)分別得到CPU1.

“先進(jìn)先出”(First in first out)調(diào)度則剛好相反,后來(lái)的人插在隊(duì)首,然后在叫號(hào)的時(shí)候被先叫到??聪聢D:

圖 3 先進(jìn)先出調(diào)度示意

首先在CPU 1上運(yùn)行的線程4,被挪入優(yōu)先級(jí)15的隊(duì)列隊(duì)首 然后重新搜索可執(zhí)行的最高優(yōu)先級(jí)線程,這里有優(yōu)先級(jí)15隊(duì)列上的線程4和3 線程4因?yàn)樵陉?duì)列最前端,它被選擇得到CPU,線程4的狀態(tài)變?yōu)镽UNNING,在CPU1上執(zhí)行

可以看到,在這個(gè)調(diào)度算法下,如果沒(méi)有別的狀態(tài)發(fā)生,事實(shí)上線程4就會(huì)一直占據(jù)CPU1。

如果在優(yōu)先級(jí)15上的線程3和線程4都是FIFO會(huì)怎樣?按上面的描述,線程3還是始終無(wú)法獲得CPU1,因?yàn)榫€程4每次都會(huì)插在3的前面,再調(diào)度就又是4獲得CPU1。除非線層4進(jìn)入了阻塞狀態(tài)(從而不在READY隊(duì)列里了),那么線程3才能獲得CPU。

零星調(diào)度(Sporadic)

“零星調(diào)度”(Sporadic)算法比較特殊,它比較適合長(zhǎng)時(shí)間占用CPU的線程。它的基本設(shè)計(jì)思想是給一個(gè)線程準(zhǔn)備兩個(gè)優(yōu)先級(jí),“前臺(tái)”優(yōu)先級(jí)比較高,“后臺(tái)”優(yōu)先級(jí)稍微底一點(diǎn)。如果線程在高優(yōu)先級(jí)連續(xù)占用CPU超過(guò)一定時(shí)間后,線程會(huì)被強(qiáng)行降到“后臺(tái)”低優(yōu)先級(jí)上(這時(shí)線程能不能占用CPU取決于系統(tǒng)中有沒(méi)有比“后臺(tái)”優(yōu)先級(jí)高的別的線程了);然后線程在低優(yōu)先級(jí)上經(jīng)過(guò)了一段時(shí)間后,會(huì)重新被調(diào)回高優(yōu)先級(jí)。

圖 4 零星調(diào)度示意

上圖是一個(gè)零星調(diào)度線程的示意。

開(kāi)始的時(shí)候,線程在比較高的(正常)優(yōu)先級(jí) H 上運(yùn)行,一直到把預(yù)先分配給零星調(diào)度的時(shí)間用完(sched_ss_init_budget) 這時(shí),線程會(huì)被自動(dòng)調(diào)整為低優(yōu)先級(jí)L(sched_ss_low_priority);一旦被調(diào)低,線程也可能運(yùn)行(如果優(yōu)先級(jí)L依然是系統(tǒng)里最高優(yōu)先級(jí)的線程),也可能無(wú)法運(yùn)行呆在READY隊(duì)列里(系統(tǒng)里有比L更高的優(yōu)先級(jí)) 不管線程有沒(méi)有執(zhí)行,從最開(kāi)始運(yùn)行時(shí)間點(diǎn)算起,當(dāng)線程“執(zhí)行補(bǔ)充時(shí)間"(sched_ss_repl_period)過(guò)了以后,線程的優(yōu)先級(jí)被重新提到優(yōu)先級(jí)H,并試圖取得CPU來(lái)。

“零星調(diào)度”看上去比較“公平”,但是實(shí)際在用QNX的項(xiàng)目中,這個(gè)調(diào)度算法很少被用戶用到。主要是因?yàn)橐话銇?lái)說(shuō)在QNX上很少有線程能夠“連續(xù)占用CPU”的。而且當(dāng)系統(tǒng)變得復(fù)雜,線程數(shù)成百上千后,這種上下調(diào)優(yōu)先級(jí)的做法,很容易出現(xiàn)別的后遺癥。

什么時(shí)候會(huì)發(fā)生調(diào)度?

????????上面介紹了QNX支持的幾個(gè)調(diào)度算法。那么,什么時(shí)候才會(huì)發(fā)生調(diào)度呢?

????????QNX的設(shè)計(jì)目標(biāo)是一個(gè)硬實(shí)時(shí)操作系統(tǒng),所以,保證最高優(yōu)先級(jí)的線程在第一時(shí)間占據(jù)CPU是很重要的。考慮到線程的狀態(tài)都是在內(nèi)核中進(jìn)行變化的(都是因?yàn)榫€程進(jìn)行了某個(gè)內(nèi)核調(diào)用后變化的),所以QNX在每次從內(nèi)核調(diào)用退出時(shí),都會(huì)進(jìn)行一次線程調(diào)度,以保證最高優(yōu)先級(jí)的線程可以占據(jù)CPU。

????????得益于微內(nèi)核結(jié)構(gòu),QNX的內(nèi)核調(diào)用通常都非常短,或者說(shuō),每一個(gè)內(nèi)核調(diào)用,都能夠比較確定地知道要花多少時(shí)間。而且,因?yàn)槲?nèi)核系統(tǒng)的基本就是進(jìn)程間通信,所以在QNX上,一段程序非常容易進(jìn)入內(nèi)核并進(jìn)行線程狀態(tài)切換,很少能有長(zhǎng)時(shí)間占滿CPU的,在實(shí)際系統(tǒng)上測(cè),現(xiàn)實(shí)上很少能有線程執(zhí)行完整個(gè)時(shí)間片的。

????????舉個(gè)例子,哪怕程序里只寫(xiě)一個(gè) printf("Hello World!\n"); 可是在libc庫(kù)里,最后這個(gè)會(huì)變成一個(gè)IO_WRITE消息,MsgSend() 給控制臺(tái)驅(qū)動(dòng);這時(shí),在MsgSend()這個(gè)內(nèi)核調(diào)用里,會(huì)把printf() 的線程置為阻塞狀態(tài)(REPLY BLOCK),同時(shí)會(huì)把控制臺(tái)驅(qū)動(dòng)的信息接收線程(從RECEIVE BLOCK)改到 READY狀態(tài),并放入 READY 隊(duì)列。當(dāng)退出MsgSend() 內(nèi)核調(diào)用時(shí),線程調(diào)度發(fā)生,通常情況下(如果沒(méi)有別的線程READY 的話)控制臺(tái)驅(qū)動(dòng)的信息接收線程被激活,并占據(jù)CPU.

????????如果用戶寫(xiě)了一個(gè)既不內(nèi)核調(diào)用,也不放棄CPU的線程會(huì)怎么樣?那時(shí)候,時(shí)鐘中斷會(huì)發(fā)生,當(dāng)內(nèi)核記時(shí)到線程占據(jù)了一整個(gè)時(shí)間片(QNX上是4ms)后,內(nèi)核會(huì)強(qiáng)制當(dāng)前線程進(jìn)入 READY,并重新調(diào)度。如果同一優(yōu)先級(jí)只有這一個(gè)線程(這是優(yōu)先級(jí)最高線程),那么調(diào)度后,還是這個(gè)線程獲取CPU。如果同一優(yōu)先級(jí)有別的線程存在,那么根據(jù)調(diào)度算法來(lái)決定哪個(gè)線程獲得CPU。

????????另一種常見(jiàn)情況是,由于某些別的原因?qū)е赂邇?yōu)先級(jí)線程被激活,比如網(wǎng)卡驅(qū)動(dòng)中斷導(dǎo)致高優(yōu)先級(jí)驅(qū)動(dòng)線程READY,所設(shè)時(shí)鐘到達(dá)導(dǎo)致高優(yōu)先級(jí)線程從阻塞狀態(tài)返回READY狀態(tài)了,當(dāng)前線程開(kāi)放互斥鎖之類(lèi)的線程同步對(duì)象,導(dǎo)致別的線程返回READY狀態(tài)了。這些,都會(huì)在從內(nèi)核調(diào)用退出時(shí),進(jìn)行調(diào)度。

中斷與優(yōu)先級(jí)

????????上面提到如果用戶線程長(zhǎng)期占有CPU,時(shí)鐘中斷會(huì)打斷用戶線程。細(xì)心的讀者或許會(huì)有疑問(wèn),那中斷的優(yōu)先級(jí)是多少呢?

????????答案是在QNX這樣的實(shí)時(shí)操作系統(tǒng)里,“硬件中斷”永遠(yuǎn)高于任何線程優(yōu)先級(jí),哪怕你的線程優(yōu)先級(jí)到了255,只要有中斷發(fā)生,都要讓路,CPU會(huì)跳轉(zhuǎn)去執(zhí)行中斷處理程序,執(zhí)行完了再回歸用戶線程。事實(shí)上,能夠快速穩(wěn)定地響應(yīng)中斷處理,是一個(gè)實(shí)時(shí)操作系統(tǒng)的硬指標(biāo)。

????????我們這里說(shuō)的是“硬件中斷”,就是說(shuō),當(dāng)外部設(shè)備,通過(guò)中斷控制器,向CPU發(fā)出中斷請(qǐng)求時(shí),無(wú)論當(dāng)時(shí)CPU上執(zhí)行的線程優(yōu)先級(jí)是什么,都會(huì)先跳轉(zhuǎn)到內(nèi)核的中斷處理程序;中斷處理程序會(huì)去中斷控制器找到具體是哪一個(gè)源發(fā)生了中斷(中斷號(hào)),并據(jù)此,跳轉(zhuǎn)到該中斷號(hào)的中斷處理程序(通常是硬件驅(qū)動(dòng)程序 通過(guò) InterruptAttach() 掛接的函數(shù))。在這個(gè)過(guò)程中,如果當(dāng)前CPU正在處理另一個(gè)中斷,那么這時(shí),會(huì)根據(jù)中斷的優(yōu)先級(jí)來(lái)決定是讓CPU繼續(xù)處理下去(當(dāng)前中斷進(jìn)入等待);或者發(fā)生中斷搶占,新中斷的優(yōu)先級(jí)比舊中斷高,所以跳轉(zhuǎn)新中斷處理。

????????當(dāng)然,實(shí)際應(yīng)用中,特別是微內(nèi)核環(huán)境下,考慮中斷其實(shí)只是中斷設(shè)備給出的一個(gè)通知,對(duì)這中斷的響應(yīng)并不需要真的在中斷處理中進(jìn)行,驅(qū)動(dòng)程序可以選擇在普通線程中處理,QNX上有InterruptAttachEvent() 就是為了這個(gè)設(shè)計(jì)的。通常這里的“事件”會(huì)是一個(gè)“脈沖”,也就是說(shuō),當(dāng)硬件中斷發(fā)生,內(nèi)核檢查到相應(yīng)中斷綁定了事件。這時(shí),不會(huì)跳轉(zhuǎn)到用戶中斷處理程序,而是直接發(fā)出那個(gè)脈沖,以激活一個(gè)外部(驅(qū)動(dòng)器中)線程,在這線程中,做設(shè)備中斷所需要的處理。這樣做,雖然稍微增加了一些中斷延遲,但也帶來(lái)了不少好處。首先,這個(gè)外部線程同普通的用戶線程一樣,所以可以調(diào)用任何庫(kù)函數(shù),而中斷服務(wù)程序因?yàn)閳?zhí)行環(huán)境的不同,有好多限制。其次,因?yàn)槭瞧胀ㄓ脩艟€程,就可以用線程調(diào)度的方法規(guī)定其優(yōu)先級(jí)(脈沖事件是帶優(yōu)先級(jí)的),使不同的設(shè)備中斷處理,跟正常業(yè)務(wù)邏輯更好地一起使用。

????????在QNX這樣的微內(nèi)核環(huán)境下,中斷處理的方式確實(shí)有其獨(dú)特之處。首先,我們要明確中斷本質(zhì)上只是設(shè)備向系統(tǒng)發(fā)出的一種通知,告知系統(tǒng)某個(gè)特定事件已經(jīng)發(fā)生,需要相應(yīng)的處理。但并不意味著中斷處理必須在中斷發(fā)生的即時(shí)上下文中完成。

????????QNX提供的InterruptAttachEvent()機(jī)制允許驅(qū)動(dòng)程序選擇在一個(gè)普通的用戶線程中處理中斷,而不是傳統(tǒng)的在中斷服務(wù)程序中直接處理。這種設(shè)計(jì)思路有幾個(gè)關(guān)鍵的優(yōu)勢(shì)。

首先,當(dāng)硬件中斷發(fā)生時(shí),內(nèi)核會(huì)檢測(cè)到相應(yīng)的中斷,并檢查是否有與該中斷綁定的事件(通常是一個(gè)“脈沖”)。此時(shí),內(nèi)核不會(huì)直接跳轉(zhuǎn)到用戶的中斷處理程序,而是發(fā)出這個(gè)脈沖。這個(gè)脈沖的作用類(lèi)似于一個(gè)信號(hào),用于激活一個(gè)在驅(qū)動(dòng)程序中定義的外部線程。這個(gè)外部線程隨后會(huì)執(zhí)行設(shè)備中斷所需要的處理邏輯。

????????這樣做雖然可能稍微增加了一些中斷的延遲,但帶來(lái)的好處是顯著的。由于這個(gè)外部線程是一個(gè)普通的用戶線程,它擁有與普通用戶線程相同的執(zhí)行環(huán)境和能力。這意味著它可以調(diào)用任何庫(kù)函數(shù),使用任何可用的系統(tǒng)資源,而不會(huì)受到中斷服務(wù)程序通常存在的諸多限制。

????????此外,由于它是一個(gè)普通的用戶線程,我們可以使用線程調(diào)度的方法來(lái)規(guī)定其優(yōu)先級(jí)。這意味著不同的設(shè)備中斷處理可以根據(jù)需要設(shè)置不同的優(yōu)先級(jí),從而更好地與正常的業(yè)務(wù)邏輯協(xié)同工作。例如,對(duì)于實(shí)時(shí)性要求較高的設(shè)備中斷,我們可以將其處理線程的優(yōu)先級(jí)設(shè)置得較高,以確保其得到及時(shí)響應(yīng)。

多CPU上的線程調(diào)度

現(xiàn)在同步多處理器(SMP)已經(jīng)相當(dāng)普及了。在SMP上,也就是說(shuō)當(dāng)有多個(gè)CPU時(shí),我們的調(diào)度算法有什么變化呢?比如一個(gè)有2個(gè)CPU的系統(tǒng),首先肯定,系統(tǒng)上可執(zhí)行線程中的最高優(yōu)先級(jí)線程,一定在2個(gè)CPU上的某一個(gè)上執(zhí)行;那,是不是第二高優(yōu)先級(jí)的線程就在另一個(gè)CPU上執(zhí)行呢?

雖然直覺(jué)上我們覺(jué)得應(yīng)該是這樣的(系統(tǒng)里的第一,第二高優(yōu)先級(jí)的線程占據(jù)CPU1和CPU2),但事實(shí)上,第二高優(yōu)先級(jí)的線程占據(jù)CPU2這件事,并不是必要的。實(shí)時(shí)搶占系統(tǒng)的要求是最高優(yōu)先級(jí)”必須“能夠搶占CPU,但對(duì)第二高優(yōu)先級(jí)并沒(méi)有規(guī)定。拿我們最開(kāi)始的雙CPU圖再看一眼。

圖 5 有兩個(gè)CPU的系統(tǒng)里的線程

線程4以?xún)?yōu)先級(jí)15占據(jù)CPU1這是毫無(wú)疑問(wèn)的,但線程5只有優(yōu)先級(jí)12,為什么它可以占據(jù)CPU2,而線程3明明也有優(yōu)先級(jí)15,但只能排隊(duì)等候,這是不是優(yōu)先級(jí)倒置了?其實(shí)并沒(méi)有,如上所述,系統(tǒng)確實(shí)保證了“最高優(yōu)先級(jí)占據(jù)CPU”的要求,但在CPU2上執(zhí)行什么線程,除了線程本身的優(yōu)先級(jí)以外,還有一些別的因素可以權(quán)衡,其中一個(gè)在SMP上比較重要的,就是“線程躍遷”。

“線程躍遷”指的是一個(gè)線程,一會(huì)兒在CPU1上執(zhí)行,一會(huì)兒在CPU2上執(zhí)行。在SMP系統(tǒng)上,線程躍遷而導(dǎo)致的緩存清除與重置,會(huì)給系統(tǒng)性能帶來(lái)很大的影響。所以在線程調(diào)度時(shí),盡量把線程調(diào)度到上次執(zhí)行時(shí)用的CPU,是SMP調(diào)度算法里比較重要的一環(huán)。上述例子中,很有可能就是線程3上一次是在CPU1上執(zhí)行的,而線程5雖然優(yōu)先級(jí)比較低,很有可能上一次就是在CPU2上執(zhí)行的。

實(shí)際應(yīng)用中,因?yàn)镼NX的易于阻塞的特性,其實(shí)大多數(shù)情況下,還是符合“第一,第二高優(yōu)先級(jí)線程在CPU上執(zhí)行”的。只是,如果你觀察到了上述情形,也不需要擔(dān)心,設(shè)計(jì)上確實(shí)有可能不是第二高優(yōu)先級(jí)的線程在運(yùn)行。

另一個(gè)多處理器上常見(jiàn)的應(yīng)用,是線程綁定。在正常情況下,把可執(zhí)行線程調(diào)度到哪一個(gè)CPU上,是由操作系統(tǒng)完成的。當(dāng)然操作系統(tǒng)會(huì)考慮“線程躍遷”等情形來(lái)做決定。但是,QNX的用戶也可以把線程綁定到某一個(gè)(或者某幾個(gè))CPU上,這樣操作系統(tǒng)在調(diào)度時(shí),會(huì)考慮用戶的要求來(lái)進(jìn)行。綁定是通過(guò)ThreadCtl() 修改線程的 “RUNMASK” 來(lái)進(jìn)行的,如果你有0,1,2,3 總共4個(gè)CPU,那么 0x00000003意味著線程可以在CPU0和CPU1上執(zhí)行,具體例子可以參考ThreadCtl()函數(shù)說(shuō)明。更簡(jiǎn)單的辦法,是通過(guò)QNX特有的 on 命令的 –C 參數(shù)來(lái)指定,這個(gè)指定的 runmask,還會(huì)自動(dòng)繼承。所以你可以簡(jiǎn)單的如下執(zhí)行:

# on –C 0x00000003 Navigation &# on –C 0x00000004 Media &# on –C 0x00000008 System &

這樣來(lái)把不同的系統(tǒng)部署到不同的CPU上。

這樣做的好處當(dāng)然是可以減少比如因?yàn)橄到y(tǒng)繁忙而對(duì)導(dǎo)航帶來(lái)的影響,但不要忘了,另一面,如果所有 Media 線程都處于阻塞狀態(tài),上述綁定也限制了導(dǎo)航線程使用CPU2的可能,CPU2這時(shí)候就會(huì)空轉(zhuǎn)(執(zhí)行內(nèi)核 idle 線程)。

自適應(yīng)分區(qū)調(diào)度算法

前面我們提到過(guò),在討論優(yōu)先級(jí)調(diào)度時(shí),只是討論當(dāng)有多個(gè)優(yōu)先級(jí)相同的線程時(shí),系統(tǒng)怎樣取舍。優(yōu)先級(jí)不一樣時(shí),肯定是優(yōu)先級(jí)高的贏。但是“高出多少”并不是一個(gè)考量因素。兩個(gè)線程,一個(gè)優(yōu)先級(jí)10,另一個(gè)優(yōu)先級(jí)11的情況,和一個(gè)10,另一個(gè)40的情況是一樣的。并不會(huì)因?yàn)?0和40差距比較大而有什么不同。

假如我們有紅藍(lán)兩個(gè)線程,它們的優(yōu)先級(jí)一樣,調(diào)度策略是RR,兩個(gè)線程都不阻塞,那么在10時(shí)間片的區(qū)間里,我們看到的就是這樣一個(gè)執(zhí)行結(jié)果:

也就是說(shuō),各占了50%的CPU。但只要把藍(lán)色線程提高哪怕1,執(zhí)行結(jié)果就成了下面這樣。

這種“非黑即白”的情形,是實(shí)時(shí)系統(tǒng)的基本要求(高優(yōu)先級(jí)搶占CPU)。但是當(dāng)然,現(xiàn)實(shí)情況有時(shí)候比較復(fù)雜。比如 “HMI渲染” 是需要經(jīng)常占據(jù)CPU的一個(gè)任務(wù)(這樣畫(huà)面才會(huì)順暢),但“用戶輸入”也是需要響應(yīng)比較快的(不然用戶的點(diǎn)擊就會(huì)沒(méi)有反應(yīng))。如果“用戶輸入”的優(yōu)先級(jí)太高的話,那用戶拖拽時(shí),畫(huà)面就會(huì)卡頓甚至沒(méi)有反應(yīng)?反之,如果”HMI 渲染“的優(yōu)先級(jí)太高,那么有用戶輸入時(shí),因?yàn)樘幚沓绦騼?yōu)先級(jí)低而造成用戶輸入反應(yīng)慢。通常情況下,需要有經(jīng)驗(yàn)的系統(tǒng)工程師不斷調(diào)整這兩個(gè)任務(wù)的優(yōu)先級(jí)(因?yàn)閮?yōu)先級(jí)繼承與傳統(tǒng),一個(gè)任務(wù)可能涉及到多個(gè)線程),來(lái)達(dá)到系統(tǒng)的最優(yōu)。那么,有沒(méi)有別的辦法呢?

分區(qū)調(diào)度

傳統(tǒng)上,有一種“分區(qū)調(diào)度”的方法,今天還有一些Hypervisor采取這個(gè)辦法。這個(gè)想法很簡(jiǎn)單,就是把CPU算力隔成幾個(gè)分區(qū),比如70%,30%這樣,然后把不同線程分到這些分區(qū)里,當(dāng)分區(qū)里的CPU預(yù)算被用完以后,那個(gè)分區(qū)里所有可執(zhí)行線程都會(huì)被”停住“,直到預(yù)算恢復(fù)。

假設(shè)我們把紅線程放入70%紅色分區(qū),藍(lán)線程放入30%藍(lán)色分區(qū),然后以10個(gè)時(shí)間片為預(yù)算滑動(dòng)窗口大小,各線程具體就會(huì)如下圖占據(jù)CPU:

圖 6 分區(qū)調(diào)度算力全滿示意

在前6個(gè)時(shí)間片中,藍(lán)紅分區(qū)分別占據(jù)CPU,注意在第7個(gè)時(shí)間片時(shí),雖然藍(lán)分區(qū)中線程跟紅分區(qū)中線程有相同的優(yōu)先級(jí),雖然調(diào)度策略是輪回,應(yīng)該輪到藍(lán)線程上了,但是因?yàn)樗{(lán)線程已經(jīng)用完了10個(gè)時(shí)間片里的3個(gè),所以系統(tǒng)沒(méi)有執(zhí)行藍(lán)線程,而是繼續(xù)讓紅線程占據(jù)CPU,一直到第8第9和第10個(gè)時(shí)間片結(jié)束。

10個(gè)時(shí)間片結(jié)束后,窗口向右滑動(dòng),這時(shí)我們等于又多了一個(gè)時(shí)間片的預(yù)算,在新的10個(gè)時(shí)間片中,藍(lán)線程只占了兩個(gè)(20%),這樣,新的第11個(gè)時(shí)間片,就分給了藍(lán)分區(qū)。

同理再滑動(dòng)后,第12個(gè)時(shí)間片,分給紅線程;一直到17個(gè)時(shí)間片時(shí),同樣的事情再度發(fā)生,藍(lán)分區(qū)線程又用完了10個(gè)時(shí)間片里的3個(gè),而被迫等待它的預(yù)算重新補(bǔ)充進(jìn)來(lái)。

綜上,在任意一個(gè)滑動(dòng)窗口中,藍(lán)色分區(qū)總是只占30%,而紅色分區(qū)卻占了70%。QNX的自適應(yīng)分區(qū)調(diào)度,跟上面這個(gè)是類(lèi)似的。只是傳統(tǒng)的分區(qū)調(diào)度,有一個(gè)明顯的弱點(diǎn)。

想一下這個(gè)情況,如果紅線程因?yàn)槟承┣闆r被阻塞了,會(huì)發(fā)生什么呢?

圖 7 分區(qū)調(diào)度算力有富余示意

對(duì),藍(lán)線程是唯一可執(zhí)行線程,所以它一直占據(jù)CPU。但是,當(dāng)3個(gè)時(shí)間片輪轉(zhuǎn)之后,因?yàn)樗{(lán)分區(qū)只有30%的時(shí)間預(yù)算,它將不再占據(jù)CPU,而因?yàn)榧t線程無(wú)法執(zhí)行,接下來(lái)的7個(gè)時(shí)間片CPU處于空轉(zhuǎn)狀態(tài)(執(zhí)行Idle線程)。

一直到時(shí)間窗口移動(dòng),那時(shí),因?yàn)樗{(lán)分區(qū)只占用了20%的算力,所以它再次占據(jù)CPU……

所以你也看到了,在傳統(tǒng)的分區(qū)調(diào)度里,當(dāng)一個(gè)分區(qū)的算力有富裕的時(shí)候,CPU就被浪費(fèi)了。

自適應(yīng)分區(qū)調(diào)度

QNX在傳統(tǒng)的分區(qū)調(diào)度上,增加了“自適應(yīng)”的部份。其基本思想是一樣的,給算力加分區(qū),然后把不同的線程分到分區(qū)里。這樣,當(dāng)所有的線程都忙起來(lái)時(shí),你會(huì)發(fā)現(xiàn)情況跟圖7是一樣的。但是當(dāng)分區(qū)算力有富裕時(shí),“自適應(yīng)“允許把多出來(lái)的算力”借“給需要更多算力的分區(qū)。

圖 8 自適就分區(qū)算力有富裕示意

如上,當(dāng)藍(lán)色分區(qū)里的線程消耗完了他自己的分區(qū)預(yù)算后,自適應(yīng)分區(qū)會(huì)把有富裕算力的紅色分區(qū)的預(yù)算,借給藍(lán)色分區(qū),藍(lán)分區(qū)內(nèi)線程得以繼續(xù)在CPU上運(yùn)行。注意,在第8個(gè)時(shí)間片時(shí),紅色分區(qū)需要使用CPU,藍(lán)色分區(qū)立即讓路,把CPU讓給紅色分區(qū)。而當(dāng)紅色分區(qū)里的線程被阻塞住以后,藍(lán)色分區(qū)線程繼續(xù)使用CPU。

自適應(yīng)分區(qū)似乎確實(shí)帶來(lái)了好處,但是也帶來(lái)了一些潛在的問(wèn)題,需要在系統(tǒng)設(shè)計(jì)的時(shí)候做好決定。

自適應(yīng)分區(qū)調(diào)度與線程優(yōu)先級(jí)

你可能會(huì)好奇,在分區(qū)調(diào)度的系統(tǒng)里,線程的優(yōu)先級(jí)代表了什么?

答案取決于各個(gè)分區(qū)對(duì)各自算力的消耗情況。我們假設(shè)藍(lán)色分區(qū)里的線程優(yōu)先級(jí)比較高,紅色的優(yōu)先級(jí)比較低,當(dāng)兩個(gè)分區(qū)都有預(yù)算時(shí),內(nèi)核會(huì)調(diào)度(所有分區(qū)里的)最高優(yōu)先級(jí)線程執(zhí)行。如果系統(tǒng)一直不是很忙,那么不論分區(qū),永遠(yuǎn)是有最高優(yōu)先級(jí)的線程得到CPU,這個(gè),跟一個(gè)標(biāo)準(zhǔn)的實(shí)時(shí)操作系統(tǒng)是一致的。

當(dāng)兩個(gè)分區(qū)中某一個(gè)有預(yù)算時(shí)(意味著那個(gè)分區(qū)中所有的線程都不在執(zhí)行狀態(tài)),那么多出來(lái)的CPU算力會(huì)被分給另一個(gè)分區(qū),另一個(gè)分區(qū)中的最高優(yōu)先級(jí)線程(雖然用完了自己分區(qū)的預(yù)算,但得到了別的分區(qū)的算力),繼續(xù)占據(jù)CPU。這個(gè),也是跟實(shí)時(shí)操作系統(tǒng)是一致的。

比較特殊的情況是,當(dāng)兩個(gè)分區(qū)都沒(méi)有預(yù)算,都需要占據(jù)CPU時(shí),這時(shí),藍(lán)色線程雖然有較高的優(yōu)先級(jí),但因?yàn)榉謪^(qū)算力(30%)被用完,面且沒(méi)有別的算力可以“借”,所以它被留在READY隊(duì)列中,而比它優(yōu)先級(jí)低的紅色線程得以占據(jù)CPU。

自適應(yīng)分區(qū)調(diào)度富裕算力分配

我們上面的例子只有兩個(gè)分區(qū),考慮這樣一個(gè)例子。假設(shè)我們現(xiàn)在有A (70%),B (20%),C (10%) 三個(gè)分區(qū),A分區(qū)沒(méi)有可執(zhí)行線程,B分區(qū)有個(gè)優(yōu)先級(jí)為10的線程,C分區(qū)有個(gè)優(yōu)先級(jí)為20的線程。我們知道A分區(qū)的70%會(huì)分配給B和C,但具體是怎么分配的呢?

如上所述,當(dāng)預(yù)算有富裕時(shí),系統(tǒng)挑選所有分區(qū)中,優(yōu)先級(jí)最高的線程執(zhí)行,也就是說(shuō)C分區(qū)中的線程得到運(yùn)行。在一個(gè)窗口以后,你會(huì)發(fā)現(xiàn)A的CPU使用率是0%,B是20%,C則達(dá)到了80%。也就是說(shuō)A所有的富裕算力,都給了C分區(qū)(因?yàn)镃中的線程優(yōu)先級(jí)高)。

也許,在某些時(shí)候,這個(gè)不是你所期望的。也許C中有一些第三方程序你無(wú)法控制,你也不希望他們偷偷提高優(yōu)先級(jí)而占用全部富裕算力。QNX提供了SchedCtl()函數(shù),可以設(shè)SCHED_APS_FREETIME_BY_RATIO 標(biāo)志。設(shè)了這個(gè)標(biāo)志后,富裕算力會(huì)按照各分區(qū)的預(yù)算比例分配給各分區(qū)。上面的例子下,最后的CPU使用率會(huì)變成 A 是0%, B是65%,而C是35%。A分區(qū)富裕的70%算力,按照大約 2: 1的比例,分給了分區(qū)B和C。

“關(guān)鍵線程”與“關(guān)鍵分區(qū)”

在實(shí)際使用中,有一些重要任務(wù),可能需要響應(yīng),不論其所在的分區(qū)還有沒(méi)有算力。比如一個(gè)緊急中斷服務(wù)線程,不管分區(qū)是不是還有預(yù)算,都需要響應(yīng)。為了解決這種情況,在QNX的自適應(yīng)分區(qū)調(diào)度里,除了給分區(qū)分配算力預(yù)算以外,還允許有權(quán)限的用戶為分區(qū)分配“關(guān)鍵響應(yīng)時(shí)間”,并把特定線程定義為“關(guān)鍵線程”。

當(dāng)一個(gè)“關(guān)鍵線程”需要執(zhí)行時(shí),如果線程所在分區(qū)有預(yù)算,它就直接使用所在分區(qū)預(yù)算就好,如同普通線程;如果所在分區(qū)沒(méi)有預(yù)算了,但是別的分區(qū)還有預(yù)算,那么“自適應(yīng)”部份會(huì)把別分區(qū)的預(yù)算拿過(guò)來(lái),并用于關(guān)鍵線程,這個(gè)跟普通的自適應(yīng)分區(qū)調(diào)度一樣。

只有當(dāng)系統(tǒng)里所有分區(qū)都沒(méi)有預(yù)算了,而有一個(gè)關(guān)鍵線程需要運(yùn)行,而且線程所在的分區(qū)已經(jīng)預(yù)先分配了關(guān)鍵響應(yīng)預(yù)算,那么線程允許“突破”分區(qū)的預(yù)算,使用“關(guān)鍵響應(yīng)預(yù)算”來(lái)執(zhí)行。在QNX里,一個(gè)關(guān)鍵線程消耗的時(shí)間,從退出RECEIVE_BLOCK開(kāi)始,到下一次進(jìn)入RECEIVE_BLOCK。而且,關(guān)鍵線程的屬性是可傳遞的,如果關(guān)鍵線程在執(zhí)行中,給別的線程發(fā)送了消息,那個(gè)線程也會(huì)變成關(guān)鍵線程。

總的來(lái)說(shuō),關(guān)鍵線程是用來(lái)保證關(guān)鍵任務(wù)不會(huì)因?yàn)橄到y(tǒng)太忙而無(wú)法取得CPU時(shí)間。即使所有的分區(qū)都被占滿了,至少還有“關(guān)鍵響應(yīng)時(shí)間”可供關(guān)鍵線程來(lái)使用。當(dāng)然,一個(gè)系統(tǒng)里不應(yīng)該有太多的關(guān)鍵線程和關(guān)鍵響應(yīng)時(shí)間。理論上,假設(shè)所有的線程都是關(guān)鍵線程,那么整個(gè)系統(tǒng)其實(shí)就變成了一個(gè)普通的按優(yōu)先級(jí)調(diào)度的實(shí)時(shí)系統(tǒng),所有的分區(qū)和預(yù)算都不起作用了。

在最緊急的情況下,關(guān)鍵線程可以使用“關(guān)鍵響應(yīng)時(shí)間”來(lái)完成它的任務(wù)。如果“關(guān)鍵響應(yīng)時(shí)間”還是不夠,會(huì)怎么樣?這個(gè)是系統(tǒng)設(shè)計(jì)問(wèn)題,在設(shè)計(jì)系統(tǒng)的時(shí)候,你就應(yīng)該為關(guān)鍵線程分配它能夠完成任務(wù)所需要的最大時(shí)間。如果依然發(fā)生“關(guān)鍵響應(yīng)時(shí)間”不夠的狀況(被稱(chēng)為“破產(chǎn)”狀態(tài)),這個(gè)就是一個(gè)設(shè)計(jì)錯(cuò)誤了。

關(guān)鍵線程的破產(chǎn)

如上所述,關(guān)鍵線程的破產(chǎn)是一個(gè)設(shè)計(jì)問(wèn)題?;蛘呔€程完成的任務(wù)并不那么“關(guān)鍵”,或者設(shè)計(jì)時(shí)給出的預(yù)算不夠。這種情況下需要重新審視整個(gè)系統(tǒng)設(shè)計(jì)(因?yàn)橄到y(tǒng)在某些情況下無(wú)法保證關(guān)鍵任務(wù)在預(yù)定時(shí)間內(nèi)完成)。QNX在自適應(yīng)分區(qū)里提供了偵測(cè)到關(guān)鍵線程破產(chǎn)時(shí)的多種響應(yīng)辦法,可以是強(qiáng)行忽視,或者重啟系統(tǒng),或者由自適應(yīng)分區(qū)系統(tǒng)自動(dòng)調(diào)整分區(qū)的預(yù)算。

自適應(yīng)分區(qū)繼承

想像這個(gè)場(chǎng)景,文件系統(tǒng)在System分區(qū)里,但另一個(gè)Others分區(qū)里的第三方應(yīng)用拼命調(diào)用文件系統(tǒng),很有可能造成System分區(qū)的預(yù)算耗盡;這樣,首先可能導(dǎo)致別的應(yīng)用無(wú)法使用文件系統(tǒng);更嚴(yán)重的,可能是System分區(qū)里別的系統(tǒng),比如Audio也無(wú)法正常工作。這個(gè),顯然是自適應(yīng)分區(qū)系統(tǒng)帶來(lái)的安全隱患。

解決辦法,就是跟優(yōu)先級(jí)在消息傳遞上可以繼承一樣,分區(qū)也是可以繼承的。文件系統(tǒng)雖然分配在System系統(tǒng)里,但根據(jù)它響應(yīng)的是誰(shuí)的請(qǐng)求,時(shí)間被記到請(qǐng)求服務(wù)的線程分區(qū)里。這樣,如果一個(gè)第三方應(yīng)用拼命調(diào)用文件系統(tǒng),最多能做的,也只是消耗它自己的分區(qū),當(dāng)他自己分區(qū)的預(yù)算被耗盡時(shí),影響它自己的CPU占用率。

自適應(yīng)分區(qū)的小結(jié)

自適應(yīng)分區(qū)有一些有趣的用法,比如我們常常被要求“系統(tǒng)需要保留30%的算力”。有了自適應(yīng)分區(qū),就可以建一個(gè)有30%預(yù)算的分區(qū),在里面跑一個(gè) for (;;); 這樣的死循環(huán)。這樣,剩下的系統(tǒng)就只有70%的算力了,可以在這個(gè)環(huán)境下檢驗(yàn)一下系統(tǒng)的性能和穩(wěn)定性。

自適應(yīng)分區(qū)的具體操作方法,可以參考QNX的文檔。不同版本的QNX有稍微不同的命令行,但基本設(shè)計(jì)是一樣的。這篇文章只是介紹了自適應(yīng)分區(qū)的基本概念,實(shí)際使用上,還是有許多細(xì)節(jié)需要考慮的,真的要使用,還是需要詳細(xì)參考QNX對(duì)應(yīng)文檔。

柚子快報(bào)邀請(qǐng)碼778899分享:QNX為什么是安全的操作系統(tǒng)?

http://yzkb.51969.com/

好文閱讀

評(píng)論可見(jiàn),查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19541740.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問(wèn)

文章目錄