17、CPU 使用率統(tǒng)計(jì)
1、CPU 利用率的基本概念
CPU 使用率其實(shí)就是系統(tǒng)運(yùn)行的程序占用的 CPU 資源,表示機(jī)器在某段時(shí)間程序運(yùn)行的情況,如果這段時(shí)間中,程序一直在占用 CPU 的使用權(quán),那么可以認(rèn)為CPU 的利用率是 100%。 CPU 的利用率越高,說(shuō)明機(jī)器在這個(gè)時(shí)間上運(yùn)行了很多程序,反之較少。利用率的高低與 CPU 強(qiáng)弱有直接關(guān)系,就像一段一模一樣的程序,如果使用運(yùn)算速度很慢的CPU,它可能要運(yùn)行 1000ms,而使用很運(yùn)算速度很快的 CPU 可能只需要 10ms,那么在1000ms 這段時(shí)間中,前者的 CPU 利用率就是 100%,而后者的 CPU 利用率只有 1%,因?yàn)?000ms 內(nèi)前者都在使用 CPU 做運(yùn)算,而后者只使用 10ms 的時(shí)間做運(yùn)算,剩下的時(shí)間CPU 可以做其他事情。
FreeRTOS 是多任務(wù)操作系統(tǒng),對(duì) CPU 都是分時(shí)使用的:比如 A 任務(wù)占用 10ms,然后 B 任務(wù)占用 30ms,然后空閑 60ms,再又是 A 任務(wù)占 10ms, B 任務(wù)占 30ms,空閑 60ms;如果在一段時(shí)間內(nèi)都是如此,那么這段時(shí)間內(nèi)的利用率為 40%,因?yàn)檎麄€(gè)系統(tǒng)中只有 40%的時(shí)間是 CPU 處理數(shù)據(jù)的時(shí)間。
2、CPU 利用率的作用
一個(gè)系統(tǒng)設(shè)計(jì)的好壞,可以使用 CPU 使用率來(lái)衡量,一個(gè)好的系統(tǒng)必然是能完美響應(yīng)急需的處理,并且系統(tǒng)的資源不會(huì)過(guò)于浪費(fèi)(性價(jià)比高)。
舉個(gè)例子,假設(shè)一個(gè)系統(tǒng)的CPU 利用率經(jīng)常在 90%~100%徘徊,那么系統(tǒng)就很少有空閑的時(shí)候,這時(shí)候突然有一些事情急需 CPU 的處理,但是此時(shí) CPU 都很可能被其他任務(wù)在占用了,那么這個(gè)緊急事件就有可能無(wú)法被相應(yīng),即使能被相應(yīng),那么占用 CPU 的任務(wù)又處于等待狀態(tài),這種系統(tǒng)就是不夠完美的,因?yàn)橘Y源處理得太過(guò)于緊迫;反過(guò)來(lái),假如 CPU 的利用率在 1%以下,那么我們就可以認(rèn)為這種產(chǎn)品的資源過(guò)于浪費(fèi),搞一個(gè)那么好的 CPU 去干著沒(méi)啥意義的活(大部分時(shí)間處于空閑狀態(tài))。
作為產(chǎn)品的設(shè)計(jì),既不能讓資源過(guò)于浪費(fèi),也不能讓資源過(guò)于緊迫,這種設(shè)計(jì)才是完美的,在需要的時(shí)候能及時(shí)處理完突發(fā)事件,而且資源也不會(huì)過(guò)剩,性價(jià)比更高。
3、CPU 利用率統(tǒng)計(jì)
FreeRTOS 是一個(gè)很完善很穩(wěn)定的操作系統(tǒng), 當(dāng)然也給我們提供測(cè)量各個(gè)任務(wù)占用CPU 時(shí)間的函數(shù)接口, 我們可以知道系統(tǒng)中的每個(gè)任務(wù)占用 CPU 的時(shí)間, 從而得知系統(tǒng)設(shè)計(jì)的是否合理, 出于性能方面的考慮,有的時(shí)候,我們希望知道 CPU 的使用率為多少,進(jìn)而判斷此 CPU 的負(fù)載情況和對(duì)于當(dāng)前運(yùn)行環(huán)境是否能夠“勝任工作”。 所以,在調(diào)試的時(shí)候很有必要得到當(dāng)前系統(tǒng)的 CPU 利用率相關(guān)信息,但是在產(chǎn)品發(fā)布的時(shí)候,就可以把CPU 利用率統(tǒng)計(jì)這個(gè)功能去掉,因?yàn)槭褂萌魏喂δ艿臅r(shí)候,都是需要消耗系統(tǒng)資源的,F(xiàn)reeRTOS 是使用一個(gè)外部的變量進(jìn)行統(tǒng)計(jì)時(shí)間的,并且消耗一個(gè)高精度的定時(shí)器,其用于定時(shí)的精度是系統(tǒng)時(shí)鐘節(jié)拍的 10-20 倍,比如當(dāng)前系統(tǒng)時(shí)鐘節(jié)拍是 1000HZ,那么定時(shí)器的計(jì)數(shù)節(jié)拍就要是 10000-20000HZ。而且 FreeRTOS 進(jìn)行 CPU 利用率統(tǒng)計(jì)的時(shí)候,也有一定缺陷,因?yàn)樗鼪](méi)有對(duì)進(jìn)行 CPU 利用率統(tǒng)計(jì)時(shí)間的變量做溢出保護(hù), 我們使用的是 32 位變量來(lái)系統(tǒng)運(yùn)行的時(shí)間計(jì)數(shù)值,而按 20000HZ 的中斷頻率計(jì)算,每進(jìn)入一中斷就是 50us,變量加一,最大支持計(jì)數(shù)時(shí)間: 2^32 * 50us / 3600s =59.6 分鐘, 運(yùn)行時(shí)間超過(guò)了 59.6 分鐘后統(tǒng)計(jì)的結(jié)果將不準(zhǔn)確,除此之外整個(gè)系統(tǒng)一直響應(yīng)定時(shí)器 50us 一次的中斷會(huì)比較影響系統(tǒng)的性能。
用 戶 想 要 使 用 使 用 CPU 利 用 率 統(tǒng) 計(jì) 的 話 , 需 要 自 定 義 配 置 一 下 , 首 先 在FreeRTOSConfig.h 配置與系統(tǒng)運(yùn)行時(shí)間和任務(wù)狀態(tài)收集有關(guān)的配置選項(xiàng),并且實(shí)現(xiàn)portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 與portGET_RUN_TIME_COUNTER_VALUE()這兩個(gè)宏定義,具體見(jiàn)下面代碼清單。
/******************************************************************** FreeRTOS 與運(yùn)行時(shí)間和任務(wù)狀態(tài)收集有關(guān)的配置選項(xiàng) **********************************************************************/ //啟用運(yùn)行時(shí)間統(tǒng)計(jì)功能 #define configGENERATE_RUN_TIME_STATS 1 //啟用可視化跟蹤調(diào)試 #define configUSE_TRACE_FACILITY 1 /* 與宏 configUSE_TRACE_FACILITY 同時(shí)為 1 時(shí)會(huì)編譯下面 3 個(gè)函數(shù) * prvWriteNameToBuffer() * vTaskList(), * vTaskGetRunTimeStats() */ #define configUSE_STATS_FORMATTING_FUNCTIONS 1 extern volatile uint32_t CPU_RunTime; #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (CPU_RunTime = 0ul) #define portGET_RUN_TIME_COUNTER_VALUE() CPU_RunTime
然后需要實(shí)現(xiàn)一個(gè)中斷頻率為 20000HZ 定時(shí)器,用于系統(tǒng)運(yùn)行時(shí)間統(tǒng)計(jì),其實(shí)很簡(jiǎn)單,只需將 CPU_RunTime 變量自加即可, 這個(gè)變量是用于記錄系統(tǒng)運(yùn)行時(shí)間的, 中斷服務(wù)函數(shù)具體見(jiàn)下面代碼清單 。
/* 用于統(tǒng)計(jì)運(yùn)行時(shí)間 */ volatile uint32_t CPU_RunTime = 0UL; void BASIC_TIM_IRQHandler (void) { if ( TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET )
{ CPU_RunTime++; TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update); } }
然后我們就可以在任務(wù)中調(diào)用 vTaskGetRunTimeStats()和 vTaskList()函數(shù)獲得任務(wù)的相關(guān)信息與 CPU 使用率的相關(guān)信息,然后打印出來(lái)即可,具體見(jiàn)下面代碼清單。
memset(CPU_RunInfo,0,400); //信息緩沖區(qū)清零 vTaskList((char *)&CPU_RunInfo); //獲取任務(wù)運(yùn)行時(shí)間信息 printf("---------------------------------------------\r\n"); printf("任務(wù)名 任務(wù)狀態(tài) 優(yōu)先級(jí) 剩余棧 任務(wù)序號(hào)\r\n"); printf("%s", CPU_RunInfo); printf("---------------------------------------------\r\n"); memset(CPU_RunInfo,0,400); //信息緩沖區(qū)清零 vTaskGetRunTimeStats((char *)&CPU_RunInfo); printf("任務(wù)名 運(yùn)行計(jì)數(shù) 使用率\r\n"); printf("%s", CPU_RunInfo); printf("---------------------------------------------\r\n\n");

浙公網(wǎng)安備 33010602011771號(hào)