如何調(diào)整事件隊(duì)列和事件池的大小?
我們只有一個(gè)目標(biāo),為了最小化這個(gè)內(nèi)存。最小化帶來的風(fēng)險(xiǎn),隊(duì)列溢出或者內(nèi)存池被耗光,斷言失敗,這兩種情況被歸為第一類故障,同為第一類故障的還有堆棧溢出。
在開發(fā)初期使用超大型的事件隊(duì)列和內(nèi)存池,讓你的開發(fā)更具有靈活性,調(diào)整事件隊(duì)列和事件池放在開發(fā)的末尾。這并不意味著在設(shè)計(jì)過程中,完全不在乎隊(duì)列和內(nèi)存池。
在設(shè)計(jì)的時(shí)候一定要遵從一般性規(guī)則,什么是一般性規(guī)則,舉個(gè)類比你就明白了:在我們的單片機(jī)的啟動(dòng)代碼中需要定義一個(gè)堆棧,經(jīng)典的0x400,如何避免棧溢出?
答:一般性規(guī)則,避免函數(shù)的深度嵌套和大的自動(dòng)變量。
在我們QF中,同樣定義了一個(gè)定量的事件隊(duì)列和內(nèi)存池,如何避免他們溢出?
答:一般性規(guī)則,避免不必要的事件產(chǎn)生或把較長的RTC步驟分解。
關(guān)于事件隊(duì)列你需要理解一個(gè)事實(shí):平均事件產(chǎn)生速率 不能超過 平均事件消耗速率,假如這一個(gè)規(guī)則被打破,再大的隊(duì)列也會(huì)被撐爆,只是時(shí)間問題。但是偶爾產(chǎn)生率可以超過消耗速率,但不能持續(xù)很長時(shí)間類似我們CPU的超頻功能。
傳統(tǒng)的確認(rèn)事件隊(duì)列或內(nèi)存池使用量有兩種方式,第一種較為簡單就是通過運(yùn)行時(shí)觀察系統(tǒng)動(dòng)態(tài)實(shí)時(shí)開銷來評(píng)估需要多少的內(nèi)存,像QF在事件隊(duì)列中提供nMin(數(shù)據(jù)成員)。
靜態(tài)內(nèi)存分析是我們提高軟件設(shè)計(jì)能力的核心,動(dòng)態(tài)分析往往作為輔助驗(yàn)證。
一下幾種情況可以當(dāng)做小故事來思考,幫你理解靜態(tài)分析的核心:(出自QP原書實(shí)例):考慮某個(gè) QF 應(yīng)用程序運(yùn)行在某個(gè)可搶占的,基于優(yōu)先級(jí)的內(nèi)核上 。假設(shè)最高優(yōu)先級(jí) 的活動(dòng)對(duì)象僅接受其他活動(dòng)對(duì)象的事件(但是不結(jié)束從 ISR 發(fā)出的事件)。每當(dāng)任何低優(yōu)先級(jí)的活動(dòng)對(duì)象發(fā)送或發(fā)行某個(gè)事件給最高優(yōu)先級(jí)的對(duì)象,內(nèi)核立即把 CPU賦給接收者。內(nèi)核做這個(gè)上下文切換是因?yàn)椋谶@一刻,接收者是最高優(yōu)先級(jí)的預(yù)報(bào)運(yùn)行的線程。最高優(yōu)先級(jí)的活動(dòng)對(duì)象醒過來,并運(yùn)行到結(jié)束, 消耗任何發(fā)送給它的事件。因此,最高優(yōu)先級(jí)的活動(dòng)對(duì)象實(shí)際不需要對(duì)事件排隊(duì)(它的事件隊(duì)列的最大 深度為 1 ) 當(dāng)最高優(yōu)先級(jí)的活動(dòng)對(duì)象接受從 ISR 來的事件時(shí),更多的事件會(huì)為了它排隊(duì)。
在最常見的安排中, 某個(gè) ISR 每次活動(dòng)時(shí)僅產(chǎn)生一個(gè)事件。另外,實(shí)時(shí)要求的底線通常是,最高優(yōu)先級(jí)的活動(dòng)對(duì)象必須在下個(gè)中斷前消耗完事件。這種情況下,活動(dòng)對(duì)象的事件隊(duì)列可以增長到最多 2 個(gè)事件:一個(gè)用于任務(wù),另一個(gè)用于某個(gè) ISR 。你可以把這個(gè)分析遞歸的擴(kuò)展到較低優(yōu)先級(jí)的活動(dòng)對(duì)象。被排隊(duì)的事件的最大數(shù)量是,在給定的底線內(nèi),所有可以為這個(gè)活動(dòng)對(duì)象產(chǎn)生事件的較高優(yōu)先級(jí)線程和 ISR 產(chǎn)生的所有事件的總和。底線時(shí)這個(gè)活動(dòng)對(duì)象的最長的 RTC步驟,包括所有可能的來自較高優(yōu)先級(jí)線程和 ISR 的搶占。例如,在 DPP應(yīng)用程序中,所有 Philosoper活動(dòng)對(duì)象執(zhí)行非常少的處理(它們有短的 RTC步驟)。如果 CPU可以在一個(gè)時(shí)鐘節(jié)拍內(nèi)完成這些 RTC步驟, Philosopher 隊(duì)列的最大長度將是 3 個(gè)事件:一個(gè)用于系統(tǒng)時(shí)鐘ISR ,其它 2 個(gè)用于活動(dòng)對(duì)象 Table ( Table 有時(shí)候在一個(gè) RTC步驟內(nèi)發(fā)行 2 個(gè)事件)。
對(duì)事件隊(duì)列進(jìn)行靜態(tài)分析的經(jīng)驗(yàn)參考如下:
1. 事件隊(duì)列的大小取決于活動(dòng)對(duì)象的優(yōu)先級(jí)。一般的,優(yōu)先級(jí)越高,必需的事件隊(duì)列越短。特別的,系統(tǒng)里最高優(yōu)先級(jí)活動(dòng)對(duì)象立即消耗所有被其他活動(dòng)對(duì)象發(fā)現(xiàn)的所有事件,僅需要對(duì)那些被 ISR 發(fā)行的事件進(jìn)行排隊(duì)。
2. 隊(duì)列尺寸取決于最長的 RTC步驟持續(xù)的時(shí)間,包括所欲可能的(最差情況下的)來自較高優(yōu)先級(jí)活動(dòng)對(duì)象或 ISR 的搶占。處理越快,必需的事件隊(duì)列越短。為了最小化隊(duì)列尺寸, 你應(yīng)該避免非常長的 RTC步驟。理想情況是,某個(gè)給定活動(dòng)對(duì)象的所有 RTC步驟都只需要相同的 CPU周期來完成。
3.任何相關(guān)的事件生產(chǎn)都能增加隊(duì)列的尺寸。例如,有時(shí)候 ISR 或活動(dòng)對(duì)象在一個(gè) RTC步驟內(nèi)生產(chǎn)多個(gè)事件實(shí)例(例如, Table 活動(dòng)對(duì)象偶爾生產(chǎn) 2 個(gè)就餐許可事件)。如果在你的應(yīng)用程序中,最小的隊(duì)列尺寸是關(guān)鍵性要求,你應(yīng)該避免這類爆發(fā)性,例如,通過在許多RTC步驟上分散多個(gè)事件的產(chǎn)生。
簡單的規(guī)則事件池的尺寸取決于你的事件隊(duì)列和活動(dòng)對(duì)象的和,實(shí)際取決于活著的動(dòng)態(tài)事件的數(shù)量,真實(shí)的情況要比這復(fù)雜,只有在實(shí)戰(zhàn)中慢慢理解。關(guān)于內(nèi)存管理的討論到這里就結(jié)束啦,這一篇站在應(yīng)用角度上雖然少圖少代碼,但確實(shí)最重要,內(nèi)功心法太難配圖,先大體有個(gè)了解,當(dāng)在實(shí)際應(yīng)用時(shí)慢慢體會(huì)這些理論。