[導讀]這篇筆記有如下內容: 1、為什么需要計算各個線程的CPU使用率? 2、該如何計算線程CPU使用率? 3、FreeRTOS線程計算的弊端?如何打破 FreeRTOS 線程計算方式的時間限制? 4、關鍵代碼介紹。 上次介紹了如何計算整個系統(tǒng)的CPU使用率: 《 單片機里面的CPU使用
3、FreeRTOS線程計算的弊端?如何打破 FreeRTOS 線程計算方式的時間限制?
上次介紹了如何計算整個系統(tǒng)的CPU使用率:
但是卻沒有介紹該如何計算每個線程(任務)的CPU使用率。
首先要問的是,為什么要計算線程的CPU使用率,有啥用?
我們知道系統(tǒng)的CPU使用率關注的是整個系統(tǒng)的使用情況,使用率越低,表示越能更及時的響應外部情況,整個系統(tǒng)的性能也會越好。
但這是從系統(tǒng)整體考量的,并不能反映單個線程的執(zhí)行情況。
比如雖然整體的CPU使用率是30%,但是有一個線程占據了25%的使用率,一個線程使用率是5%,那么你肯定會想,為啥這個線程需要占用這么高的CPU使用率,是不是代碼寫的有問題,是不是代碼可以優(yōu)化一下?
當系統(tǒng)運行時,如果你能實時觀察各個線程的CPU使用率,那么你就能知道平時這個線程的CPU使用情況是怎樣的,為什么后來又高那么多,那么你就可以由此分析出這個線程可能出現了問題,也就可以針對性的進行檢查了。
這點對于合作開發(fā)的項目更是明顯,很多時候因為有些線程的代碼不是自己寫的,所以根本不知道代碼執(zhí)行情況,一旦系統(tǒng)出現問題,那么可能就是互相甩鍋了。
而當計算了線程的CPU使用率,一旦發(fā)現某個線程執(zhí)行異常,那么就能交給負責的人去查看了。
所以說,使用操作系統(tǒng)的項目是非常有必要計算各個線程(任務)的CPU使用率的。
就好比你的電腦,風扇嗡嗡響(CPU高負荷運行),如果只有一個系統(tǒng)CPU使用率,發(fā)現高達90%,但是你卻根本不知道為什么這么高,所以只能重啟。
而一旦有了進程CPU使用率,查看一下哪個進程CPU使用率高,把對應的進程關閉就行了,根本不需要重啟電腦。
那么現在就來看看該如何計算各個線程的CPU使用率。
從前面的筆記,我們其實也可以猜測該如何計算,無非就是獲取
每個線程的執(zhí)行時間罷了。
比如,1秒時間內,空閑任務執(zhí)行700毫秒,任務1執(zhí)行200毫秒,任務2執(zhí)行100毫秒,那么各個任務的CPU使用率分別是 70%、20%、10%。
以前計算系統(tǒng)的CPU使用率的時候,采用了軟件方法計算空閑任務的運行時間,這必然是不夠準確的,所以最好的方式是采用硬件計時。
因為魚鷹采用STM32F103進行測試,所以使用DWT外設進行精確計時,不過麻煩的是,在KEIL
軟件仿真情況下,DWT外設是無法工作的,所以如果要測試的話,必須使用硬件仿真的方式,不過如果真要KEIL軟件仿真的話,也不是沒有辦法,就是使用硬件定時器,這個按下不表。
畢竟,DWT外設的功能在這里說白了也就是個定時器而已。
既然要獲取線程的執(zhí)行時間,關鍵一點就是,我們要知道操作系統(tǒng)什么時候會切換到某一個線程運行,什么時候又會從這個線程切出,到另一個線程執(zhí)行呢?
這個關鍵還是在系統(tǒng)內置的
鉤子函數。上次的筆記魚鷹介紹過空閑鉤子函數,今天介紹另一個鉤子,任務切換鉤子函數。
這個鉤子函數的特點就是,每當系統(tǒng)需要切換到下一個任務時,就會
先執(zhí)行這個函數。這個函數一般有兩個參數,
當前任務和
即將切換的任務。
只要設置任務切換的鉤子函數,并且有時間戳,那么計算一個任務的執(zhí)行時間也就不那么困難了。
比如,操作系統(tǒng)在時刻12345 ms 切換到空閑任務執(zhí)行,突然一個任務就緒,開始準備執(zhí)行,所以在時刻12445切換到那個就緒任務執(zhí)行,那么空閑任務的執(zhí)行時間我們也就可以準確計算出來了。
也就是說,這一次空閑任務執(zhí)行了 100 毫秒。
如果我們要計算單位時間(比如1秒內)空閑任務的執(zhí)行時間,我們只要在每次運行到空閑任務時
累計時間即可。
比如1秒內,空閑任務執(zhí)行了 5 次,分別是 10、200、100、200、50,累計時間為
10 + 200 + 100 + 200 + 50 = 560毫秒
由此,可計算空閑任務的CPU使用率為 56%,從而可計算出系統(tǒng)的CPU使用率是44%。
是的,通過線程的CPU使用率方法,我們其實也可以計算整個系統(tǒng)的CPU使用率。而且這種計算方式比前面所說的計算方法更準確,更科學。
前面采用時間戳進行計算,但是時間戳是會溢出的,那個時候,你的時間計算還是準確的嗎?
現在魚鷹就來說說第三個問題,FreeRTOS線程計算的弊端?如何打破 FreeRTOS 線程計算方式的時間限制?
從網上查找FreeRTOS任務CPU計算相關的資料,可以得到以下信息:
1、需要開一個定時器,這個定時器中斷頻率是操作系統(tǒng)時鐘的十幾倍(為了保證計算精度)。
2、一個64 位的變量在定時器自加更新,一旦變量溢出,時間計算就會出現問題。
第一個問題會導致系統(tǒng)性能下降(中斷頻率太高,一般是微秒級別的),而第二個問題導致在一段時間內(小時級別)線程CPU使用率計算準確,超出時間后,計算會有問題,所以教程中不建議在正式版本加入此功能。
第一個問題其實很好解決,就是使用硬件定時器,不再由CPU去更新時間,這樣不會占用CPU時間,第二個問題其實也非常好解決,就是通過《
延時功能進化論(合集)》的方式解決溢出問題,這里不再展開說其中的奧妙。
總之,魚鷹接下來的實現方式解決了以上兩個痛點,即使無限執(zhí)行下去,也不會影響到計算精度問題,唯一對系統(tǒng)產生的一點影響,只有在任務切換時消耗的一點計算時間(微秒級別)。
那么先上任務切換
鉤子函數關鍵實現代碼(RT-Thread):
void thread_stats_scheduler_hook(struct rt_thread *from, struct rt_thread *to){ static uint32_t schedule_last_time; uint32_t time; time = get_curr_time(); from->user_data += (time - schedule_last_time); schedule_last_time = time;}
如何將這個函數注冊到操作系統(tǒng)中被系統(tǒng)調用呢?
每次任務開始切換時,更新這個時間戳,同時累積時間,這個時間保存在當前任務的user_data里面。
假設系統(tǒng)調度是從任務1切換到任務2,即from為
任務
1,to為
任務
2,此時獲取的時間戳為
T1
。
上一次的時間戳我們已經通過靜態(tài)變量保留了,這里為T0,那么T1-T0就是from任務即
任務
1在本次運行的時間,只要下次運行任務1時繼續(xù)不斷的累積這個時間,那么就可以得到任務1的總運行時間。
當然我們不可能一直累積下去,不然肯定會溢出,所以隔一段時間就需要清零,這個時間其實就是
線程
CPU
計算的周期。
__weakuint32_t get_curr_time() { return DWT->CYCCNT; }
這里可以看到有個注釋,不要使用 rt_tick_get 函數,為啥?
精度太低,有些任務本來執(zhí)行了的,但是因為執(zhí)行時間
小于操作系統(tǒng)的時鐘(比如1毫秒),那么就無法累積時間了,那么即使這個任務運行再多,時間累積也為 0,這肯定是我們不希望看到的。
然后再說一個點,為了簡化代碼(鉤子函數代碼只有短短幾行),魚鷹這樣的實現是有兩個問題的。
1、首次運行計算有誤,因為靜態(tài)變量應該在運行任務之前就初始化的(不應該初始化為 0),而鉤子函數是在任務運行之后才調用的,所以從開機以來的時間被累加到第一個運行任務中了,這肯定是有問題的,不過后面隨著系統(tǒng)的運行,靜態(tài)變量被持續(xù)更新,就不會再出現這個問題了。
2、為了減少修改,魚鷹把線程的use_data當成一個變量使用了,實際上這個變量的功能應該是存儲線程私有變量地址的,但是因為魚鷹懶得修改太多代碼,所以直接拿來用了。正因為如此,所以魚鷹添加線程CPU計算時,只要修改很少的代碼就可以了。
目前我們已經能夠通過鉤子函數獲取各個線程的CPU執(zhí)行時間,現在就看該如何計算了。
為了計算各個線程的CPU使用率,我們需要確定計算周期,這里我們可以設置1秒計算一次。
原理上來說,可以是系統(tǒng)中的任何一個任務,但是為了減少對系統(tǒng)的干擾,可以將計算工作放到優(yōu)先級比較低的任務中進行,比如空閑任務。
void thread_cal_usage(thread_run_info_def *run_info){ static uint32_t total_time_last; uint32_t time, total_time; struct rt_list_node *node; struct rt_list_node *list; struct rt_thread *thread; uint32_t i; rt_enter_critical(); time = get_curr_time(); total_time = time - total_time_last; total_time_last = time; list = &(rt_object_get_information(RT_Object_Class_Thread)->object_list); for(i = 0, node = list->next; (node != list) && i < THREAD_NBR_MAX; node = node->next, i++){ thread = rt_list_entry(node, struct rt_thread, list); run_info[i].name = thread->name; run_info[i].time = thread->user_data; thread->user_data = 0; } rt_exit_critical(); total_time /= 100; if(total_time > 0){ for(uint32_t j = i, i = 0; i < j; i++) { run_info[i].usage = run_info[i].time / total_time; } }}
注釋已經很詳盡了,所以不多做討論。主要說以下幾點:
關調度器是為了防止在獲取各個線程執(zhí)行時間時,因為系統(tǒng)調度而導致執(zhí)行時間被更新,從而導致計算有誤,所以需要關閉調度器。
那么為什么不使用關中斷的方式呢?沒有必要。一旦關中斷,那么中斷就無法響應了,所以在可以關調度器的情況下滿足要求,就不應該關中斷。
2、為什么分兩步計算,為什么不將最終的計算放在第一個循環(huán)中執(zhí)行呢?
節(jié)省時間,為了盡量減少關調度器的時間,能省一點是一點。畢竟只要能獲取到關鍵信息,啥時候計算都一樣。
3、因為線程CPU計算周期是自動計算的,所以,計算周期其實就是該函數的調用周期,即2秒調用一次,那么線程CPU計算周期就是2秒,但是需要注意的是,調用周期必須小于定時器的溢出時間,即當你使用 DWT 時,調用周期應該在 60 秒以下(72 M 系統(tǒng)時鐘),否則計算是有問題的。
現在我們已經算是完成了線程CPU計算問題,但為了使用方便,我們需要把它打印出來,或者把這些信息字符串化:
void thread_stats_print(void){ thread_run_info_def run_info[THREAD_NBR_MAX] = {0}; thread_run_info_def *p_info;
thread_cal_usage(run_info); rt_kprintf("thread\t\t\ttime\t usage\n"); for(uint32_t i = 0; i < THREAD_NBR_MAX; i++) { p_info = &run_info[i]; if(p_info->name != NULL) { if(p_info->usage > 0) { rt_kprintf("%-16s\t%u\t%2u%%\n", p_info->name, (uint32_t)p_info->time, (uint32_t)p_info->usage); } else { rt_kprintf("%-16s\t%u\t<1%%\n", p_info->name, (uint32_t)p_info->time, (uint32_t)p_info->usage); } } else { break; } }}
這里將
線程名、線程執(zhí)行時間、線程使用率都打印出來了,但是需要注意的是,這里的time 時間單位是定時器的單位,而不是微秒、毫秒,比如如果使用 DWT,那么單位就是 1/72 微秒,即如果 time 值為 1000,那么換算到微秒,應該是 1000/72 秒,當然了,你也可以在打印的同時就把時間換算一下,這個自由發(fā)揮就好。
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!
本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯系該專欄作者,如若文章內容侵犯您的權益,請及時聯系本站刪除。
LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。
關鍵字:
驅動電源
在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。
關鍵字:
工業(yè)電機
驅動電源
LED 驅動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...
關鍵字:
驅動電源
照明系統(tǒng)
散熱
根據LED驅動電源的公式,電感內電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。
關鍵字:
LED
設計
驅動電源
電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統(tǒng)中的關鍵元件,其性能直接影響到電動汽車的動力性能和...
關鍵字:
電動汽車
新能源
驅動電源
在現代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質量和效率直接關系到城市的公共安全、居民生活質量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...
關鍵字:
發(fā)光二極管
驅動電源
LED
LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數校正(PFC)、空間受限和可靠性等。
關鍵字:
LED
驅動電源
功率因數校正
在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...
關鍵字:
LED照明技術
電磁干擾
驅動電源
開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現在的LED驅動電源
關鍵字:
LED
驅動電源
開關電源
LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。
關鍵字:
LED
隧道燈
驅動電源
LED驅動電源在LED照明系統(tǒng)中扮演著至關重要的角色。由于LED具有節(jié)能、環(huán)保、長壽命等優(yōu)點,使得LED照明在各個領域得到廣泛應用。然而,LED的電流、電壓特性需要特定的驅動電源才能正常工作。本文將介紹常用的LED驅動電...
關鍵字:
LED驅動電源
led照明
LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電源轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。
關鍵字:
LED
驅動電源
高壓工頻交流
種種跡象都在表明,半導體行業(yè)或已提前進入寒冬時期,越來越多的廠商開始扛不住了……
關鍵字:
LED
半導體
驅動電源
崧盛股份9日發(fā)布投資者關系活動記錄表,就植物照明發(fā)展趨勢、行業(yè)壁壘等問題進行分享。植物照明未來市場需求廣闊崧盛股份指出,植物照明將會走向長期產業(yè)領域。主要原因有三:第一,LED植物照明賦能終端種植更具有經濟價值。由于LE...
關鍵字:
崧盛股份
驅動電源
在當今高度發(fā)展的技術中,電子產品的升級越來越快,LED燈技術也在不斷發(fā)展,這使我們的城市變得豐富多彩。 LED驅動電源將電源轉換為特定的電壓和電流,以驅動LED發(fā)光。通常情況下:LED驅動電源的輸入包括高壓工頻交流電(即...
關鍵字:
LED
驅動電源
高壓直流
人類社會的進步離不開社會上各行各業(yè)的努力,各種各樣的電子產品的更新換代離不開我們的設計者的努力,其實很多人并不會去了解電子產品的組成,比如LED電源。
關鍵字:
LED
驅動電源
低壓直流
隨著科學技術的發(fā)展,LED技術也在不斷發(fā)展,為我們的生活帶來各種便利,為我們提供各種各樣生活信息,造福著我們人類。LED驅動電源實際上是一種電源,但是它是一種特定的電源,用于驅動LED發(fā)射帶有電壓或電流的光。 因此,LE...
關鍵字:
LED
驅動電源
電流
LED燈作為一種新型節(jié)能和無污染光源,由于其特有的發(fā)光照明特性,在現代照明應用中發(fā)揮著革命性的作用。作為 LED 照明產業(yè)鏈中最為核心的部件之一,LED 驅動電源的驅動控制技術所存在的可靠性低、成本高等典型問題一直制約著...
關鍵字:
多路
LED
驅動電源
隨著社會的快速發(fā)展,LED技術也在飛速發(fā)展,為我們的城市的燈光煥發(fā)光彩,讓我們的生活越來越有趣,那么你知道LED需要LED驅動電源嗎?那么你知道什么是LED驅動電源嗎?
關鍵字:
LED
開關電源
驅動電源
早前有新聞稱,Cree在2018年開始宣布轉型高科技半導體領域,并一邊逐漸脫離照明與LED相關業(yè)務,一邊持續(xù)投資半導體。在今日,Cree宣布與SMART Global Holdings, Inc.達成最終協議,擬將LED...
關鍵字:
cree
led照明