在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

實操RT-Thread系統CPU利用率功能添加

RTThread物聯網操作系統 ? 來源:RTThread物聯網操作系統 ? 2020-06-03 11:29 ? 次閱讀

我之前的文章提到了為什么我們需要關注CPU利用率的問題,總結一句話就是,利用率越低,你的系統效率越高、響應越快,實時性越高。但是并沒有具體說該如何計算CPU利用率。 今天,借助國產操作系統RT-Thread,我們開始實操一番。在實操之前,需要簡單了解幾個概念。鉤子函數,即以hook命名的那些函數。那么什么是鉤子函數呢?說白了,就是一個函數指針,只是這個函數比較特殊一點。 特殊在哪?操作系統某些指定位置才會設置鉤子函數,比如程序運行到空閑任務了,為了不修改系統源碼(沒事別修改源碼,很危險的事情,除非你是真大佬),系統會提供一個設置鉤子函數的函數接口給你,當你需要在空閑任務中執行某些功能時,用這個函數設置你的需要功能函數就可以了,等系統運行到空閑任務,他就會幫你調用這個函數了。 這個功能看著是不是有點眼熟,對的,和所謂的回調函數是一個道理(我也不明白為啥叫鉤子函數,可能是因為和系統有關,和通用的回調函數又有點區別,所以就稱之為鉤子函數吧,不過你不要管名稱,只要知道意思就行了)。 除了在空閑任務可以設置鉤子函數,還有可能在任務切換、系統啟動、任務創建等等關鍵的地方設置,當然了,這里的每一個鉤子函數都是一個單獨的函數指針。 前面也說了,設置鉤子函數的目的只有一個,那就是可以讓你在不修改系統源碼的情況下達到私人目的,讓系統的擴展性更強,比如今天說的內容(還有下次介紹的線程CPU使用率問題),如果系統沒有空閑鉤子函數的存在,你只能去修改系統源碼才能達到目的啦。 還有文章所說的線程(task)、任務(thread),其實在RTOS中都是一樣的。在 uCOS、FreeRTOS 中,叫任務,RT-Thread 叫線程,只是叫的名稱不一樣,內容都是差不多的。 然后再大概說說怎么計算的問題。也就是在空閑鉤子函數里面,我們需要干什么事情才能到達CPU計算的目的。 首先,第一步肯定是設置鉤子函數,其次就是鉤子函數該怎么寫的問題。這個網上一搜就出現了(魚鷹也是網上搜的代碼),然后就要分析為什么這么寫。 前面說過,CPU利用率其實是首先計算一段時間內空閑任務執行時間,然后反推其他任務的執行時間。 這里有兩個問題,一段時間是多少?空閑任務的執行時間怎么計算?先說第二個問題。用定時器時間掐?好像不好,因為你不知道什么時候程序就離開了空閑任務跑去執行其他任務了,而即使你可以知道它什么時候離開空閑任務的,那也會增加計算難度,不是好的方式。 那怎么辦?還記得剛學單片機時你是怎么進行軟件延時的嗎?對,就是用這個方法,軟件延時! 只要程序執行到空閑任務了,就用一個變量不停自加。這樣就可以根據變量值來大概計算空閑任務的執行時間。 但是這里又存在一個問題:如果這個變量一直自加,肯定會溢出,該怎么解決。 加大變量的大小,比如原先使用一個字節、兩個字節的,那么如果溢出,就用四個字節、八個字節。 但32位系統最大能支持的也就8個字節了,如果還是溢出了咋辦?再套一個循環,一個循環的數加完了,再加另一數就行了。 但是還有一個問題,如果說自加的時間不做限制,那么再多的變量也不行,而且還會影響CPU計算的實時性,也就不能實時反映CPU利用率了;而如果時間太短,如果剛好有任務的執行時間在這個范圍,那么很可能你計算CPU利用率就直接是100%了。 比如說你一個任務需要執行10毫秒,然后你計算CPU的周期也是10毫秒,那么可能剛好開始計算時跳到了那個任務執行,那么你的變量就沒有自加了,也就會顯示100%利用率了。 這里其實說的是前面的第一個問題,一段時間是多少? 對于這個時間,因為魚鷹看的書籍比較少,所以也沒有理論支撐(如果有道友知道的,不如留言)。 但是肯定既要考慮變量溢出(這個可以通過加循環方式解決),又要考慮實時性,還要考慮其他任務的最大執行時間,否則本來系統沒有問題的,但是因為你追求實時性,導致CPU利用率80%、90%的,那就很尷尬了。 以上討論如果沒有經驗可能比較難理解,所以建議大家在看完后面內容,實操過后,再回頭重新看一遍,這樣才有更深的理解。 現在再看CPU計算公式:

cpu_usage = (total_count – count)/ total_count × 100 %(滑動查看) cpu_usage: CPU利用率; total_count:單位時間內全速運行下的變量值; count:單位時間內空閑任務自加的變量值。 total_count這個值表現了單片機全速運行下,所能達到的最大值。所謂全速運行,即不響應中斷,也不去執行其他任務,就單純讓它在一個地方持續運行一段時間,這個值可以體現CPU的算力有多大。 比如,51單片機,可能這個值自加10毫秒之后只有100,STM32F1單片機自加能到1000,而STM32F4單片機能到2000,這樣就能體現他們之間的算力差別了。 這個值可以是動態的,也可以是靜態的。靜態有靜態的好處,動態有動態的好處。 所謂的靜態是指,在系統沒有運行任務時,關閉所有的中斷,自加這個值。這樣,這個值比較準確,但是如果一開始這個值計算錯了,那么后面的計算肯定也是有問題的,而且如果系統啟動后長時間既不啟動任務,也不響應中斷,肯定對系統有一定的影響。但是好處是,系統消耗更少,因為他只計算一次。 而動態計算,則是在空閑任務中,當這個值為零時,計算一次,之后只會在空閑任務自加的變量值超過這個數時,才會更新這個值,這樣一來,最終還是能準確反映CPU利用率的。好處是,不需要在開機時關閉所有中斷,當然壞處是,前期可能不是很準,因為可能由于中斷原因導致計算的值較小(中斷處理時消耗了算力)。 廢話太多了一些,直接開始干吧。新建一個文件,拷貝如下代碼:

#include #include #define CPU_USAGE_CALC_TICK 10#define CPU_USAGE_LOOP 100 static rt_uint8_t cpu_usage_major = 0, cpu_usage_minor= 0;static rt_uint32_t total_count = 0; static void cpu_usage_idle_hook(void){ rt_tick_t tick; rt_uint32_t count; volatile rt_uint32_t loop; if (total_count == 0) { /* get total count */ rt_enter_critical(); tick = rt_tick_get(); while(rt_tick_get() - tick < CPU_USAGE_CALC_TICK) { total_count ++; loop = 0; while (loop < CPU_USAGE_LOOP) loop ++; } rt_exit_critical(); } count = 0; /* get CPU usage */ tick = rt_tick_get(); while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK) { count ++; loop = 0; while (loop < CPU_USAGE_LOOP) loop ++; } /* calculate major and minor */ if (count < total_count) { count = total_count - count; cpu_usage_major = (count * 100) / total_count; cpu_usage_minor = ((count * 100) % total_count) * 100 / total_count; } else { total_count = count; /* no CPU usage */ cpu_usage_major = 0; cpu_usage_minor = 0; }} void cpu_usage_get(rt_uint8_t *major, rt_uint8_t *minor){ RT_ASSERT(major != RT_NULL); RT_ASSERT(minor != RT_NULL); *major = cpu_usage_major; *minor = cpu_usage_minor;} void cpu_usage_init(void){ /* set idle thread hook */ rt_thread_idle_sethook(cpu_usage_idle_hook);}以上的代碼網上找的,首先分析這兩個宏,第二個宏就是前面所說的防止變量溢出用的,而第一個值就是CPU計算周期,這個值比較關鍵,后面再說。 ? 首先在系統啟動前設置鉤子函數:

然后,就沒有然后了。 對的,設置完之后就可以了,但為了讓我們能觀察到,可以打印出來。

我們可以觀察效果如何,開始設置計算周期和任務延時函數一樣,10毫秒。 測試結果:

可以看到,因為是動態計算的,所以開始為0,因為系統首先運行其他任務,只有其它任務不運行時,才會開始運行空閑任務,所以CPU利用率為0。 但是即使后面有值了,你也會發現CPU利用率變化很大,0.82%~1.5%。而且你會發現除了開始的0.0%,后面又再次出現了,這又是怎么回事? 通過設置斷點分析,發現,這是因為計算值超出了開始的值,重新設置了:

這就是動態計算的一些問題了,它在一開始的一段時間里,因為無法完全表現算力,只能通過后面不停的修正該值才能達到穩定。 現在修改計算周期 20 毫秒:

發現它的表現更差勁,4.3%~11.61%,而且會周期性出現低利用率的情況。 再改,100毫秒:

可以看到這個比較穩定了,13.71%~14.35%。 那么這個測試代碼實際情況的CPU利用率是多少呢? 我們可以通過前面的筆記《KEIL 下如何準確測量代碼執行時間?》大概計算線程執行時間:

1.59毫秒,10毫秒執行周期,如果只有這個任務執行,大概1.59/10=15.9%(準確計算應該是 1.59/(10 + 1.59) =13.7%)。 和前面的100毫秒類似。 我們先不管前面的結果,先理解一下里面的計算方法。 首先,如果total_count開始為0,那么開始第一次計算。這次計算會關閉調度器。

計算過后,就不再進入。 之后就是動態計算過程:

和第一次計算一樣,都是在一定時間內自加計數器,不同的是,這次不會關閉調度器,也就是說,如果有高優先級任務就緒,那么是可以執行其他任務的。 并且計時時間使用的是系統函數rt_tick_get(),單位為系統調度時間。測試環境中,系統調度時間為 1 毫秒。 有意思的是,在進行最終的計算時,采用了分步計算,首先計算整數,再計算小數。 為什么要這樣做?效率! 這樣的計算方法,可以將浮點運算轉化成整型運算,這在沒有浮點運算單元的單片機中,能大大減少計算時間。 另外,為了防止溢出,還使用了一個循環結構。 理解了以上內容,現在開始進行魚鷹式深度思考:

上面的分步計算是否存在問題?

關調度器只關閉了任務調度,但還是會響應中斷,這能夠體現單片機最大算力嗎?

使用rt_tick_get() 函數進行計時,精度是多少,會影響最終的計時嗎?

有必要使用循環體嗎?如果單位時間內不溢出,是否不用循環體會更好?

前面的CPU使用率為什么會跳動,按理說任務的執行時間應該是確定的,也只有一個任務在運行,不應該跳動才對?

10毫秒的計算和100毫秒的計算差別在哪?

7. 終極問題,如何精確計算CPU使用率? 上面的問題,如果只是粗略計算,其實都可以不用考慮,本著對技術的熱愛,還是聊一聊好了。 1、分步計算,不知道你想到了什么BUG?這個問題其實在以往的筆記都提過,這次再說一次。 當你在獲取CPU使用率時,如果剛好在更新這兩個值,那么可能整數部分是上一次計算的值,而小數部分卻是這次計算的值,那么肯定有問題。 這就涉及到數據完整性獲取的問題。怎么解決。關調度器、關中斷都可以。 但是因為是粗略計算,那么小數部分即使是錯誤的,也沒事。 2、因為只關調度器,所以對于中斷還是會響應,比如說你設定計算周期為100毫秒,那么1毫秒一次的systick中斷肯定會執行,那么在100毫秒中,有100次進入中斷執行,而這些算力在上述算法中是無法體現的。 3、rt_tick_get() 函數精度問題,因為這個是系統的軟件計時器,所以在測試環境中為1毫秒遞增一次,也就是說它的精度在1毫秒。因此,在100毫秒的計算周期里面,有1% 的誤差存在,在10毫秒的計算周期里面,誤差10%! 4、有沒有必要用循環體?在1秒計算一次的情況下,即使不用循環體,也不會導致溢出問題。而且使用了循環體,還會導致精度降低,畢竟樣本少了。比如使用循環體最大值為100,不使用時為10000,哪個精度高? 5、CPU使用率跳動問題。因為是測試,所以只有一個任務在運行,而且任務很簡單。

這個任務的執行時間應該是固定的才對,但即使是使用了后面的高精度計算方式,CPU使用率還是會跳動,這是為什么? 第一,rt_kprintf函數執行時間是不固定的,不固定在哪,比如要顯示的變量開始是1,后面是1000,因此它輸出的字符串不一樣,并且打印時間也不一樣,因為是查詢方式打印,所以差別很大!這就是我為什么推薦DMA打印的原因,未使用前是10%,使用后可能就是1%,甚至更低。 第二點,也是非常容易忽視的一點,插入的中斷執行時間。 系統每隔1毫秒需要進入systick執行一次(或者其他中斷執行時間),如果說任務的執行時間超過1毫秒,那么中間必然會先執行中斷,再執行任務,這樣一來,因為中斷的插入,導致時間不再那么準確了。而當你把打印的時間控制在 1 毫秒以內,那么CPU使用率會變的非常穩定。 第三:延時rt_thread_delay()函數本身的誤差,受到系統精度的影響,這個延時時間其實也不是固定的,會有一定的浮動。 6、10毫秒和100毫秒計算的差別? 如果說你的任務執行時間小于1毫秒,那么在10毫秒和100毫秒的計算差別不是很大,但是如果說計算周期變成了5毫秒,即使任務執行時間小于1毫秒的情況下,計算值也是會在最大和最小之間來回跳動的。而執行時間一旦超過1毫秒,那么10毫秒和100毫秒的計算就有較大的差別。 并且測試的時候,因為系統延時時間是10毫秒,而計算的時候也是10毫秒的周期,所以出現了比較詭異的事情,因為按理說延時10毫秒,任務執行時間2.56毫秒,任務運行周期為12 毫秒(還記得前面所說的延時誤差嗎),CPU 使用率按理應該是 21.3 左右,實際上卻是 6.5% 左右,相差太大了,這就非常奇怪了。而且如果更改執行時間為1.5毫秒時(通過修改代碼修改執行時間),發現計算值又正常了;而即使不修改執行時間,修改計算時間為100毫秒,又正常了,這是怎么回事? 通過深入分析發現,剛好在主任務延時10毫秒的時候,切換到了空閑任務進行空閑時間計算,執行了9.4毫秒的時候,又切回到了主任務,所以計算時,得到了6.5%的計算值。 粗略表示如下所示:

通過這個分析,你應該知道,計算CPU的時候,盡量不要使用和任務延時時間一樣的計算周期,否則會出現莫名其妙的事情;還有一點就是,任務的執行周期 = 任務執行時間 + 系統延時,而前面所介紹的計算方法只是粗略的表示,嚴格來說是有問題的。 7、終極問題,如何提高計算精度?通過以上分析,我們其實已經知道了計算時的一些問題點。首先,計算周期問題,這個可以根據系統來確定,但是千萬要注意前面的提到的問題。如果說500毫秒計算周期可以滿足要求的話,就沒必要使用50毫秒,不然你會發現計算值跳動很大。 其次,時間精度問題,這個問題老生常談了,魚鷹建議是DWT,如果沒有,找一個定時器代替也是可以的。 最后是單位時間算力問題,為了保證精確,可以關閉中斷進行第一次計算,或者用短一點的時間,比如1毫秒得到一個算力,如果計算周期為100毫秒,那這個算力乘以100就行了。當然如果系統時鐘不經常變的話,也可以通過靜態方式先得到單位時間的算力,之后就以它為標準就可以了。這樣就不會有長時間關中斷的情況出現了。 但是計算算力的時候,千萬千萬要注意一點的是,C語言轉化為匯編代碼時,可能一樣的代碼,在不同的地方執行時間是不一樣的(比如前面代碼的第一次計算和后面的計算,看似一樣,但實際上有較大差別,原因就在于執行效率不一樣),這個涉及到寄存器比內存效率更高的問題,所以計算算力時,可以把它封裝成一個函數,這樣,只要優化等級不變,那么函數的執行時間就可以認為是確定的。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • cpu
    cpu
    +關注

    關注

    68

    文章

    10889

    瀏覽量

    212386
  • RT-Thread
    +關注

    關注

    31

    文章

    1300

    瀏覽量

    40264

原文標題:【深度好文】實操RT-Thread系統CPU利用率功能添加

文章出處:【微信號:RTThread,微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    RT-Thread上CAN實踐

    開箱測試RT-Thread官方已完成了對英飛凌XMC7200EVK的移植,通過shell可以看到做好了uart3的console。本文將介紹如何進行RT-ThreadCan移植。接下來我們要完成CAN_FD的驅動移植,并正常啟動RT-T
    的頭像 發表于 11-13 01:03 ?1294次閱讀
    <b class='flag-5'>RT-Thread</b>上CAN實踐

    混合部署 | 在迅為RK3568上同時部署RT-Thread和Linux系統

    系統RT-Thread系統已經同時運行了,其中CPU0、CPU1、CPU2運行Linux
    發表于 11-01 10:31

    混合部署 | 在迅為RK3568上同時部署RT-Thread和Linux系統

    RT-Thread系統已經同時運行了,其中CPU0、CPU1、CPU2運行Linux系統
    發表于 09-18 10:54

    RT-Thread內部機制大揭秘,帶你深入操作系統內核

    一、RT-Thread概述RT-Thread是一款具有顯著優勢的開源嵌入式實時操作系統。它不僅具備輕量級、實時性強的特點,還擁有廣泛的開源社區支持和豐富的應用場景。在輕量級方面,RT-Thre
    的頭像 發表于 08-01 08:11 ?3821次閱讀
    <b class='flag-5'>RT-Thread</b>內部機制大揭秘,帶你深入操作<b class='flag-5'>系統</b>內核

    rt-thread如何解決添加虛擬網卡?

    rt-thread在初始化一個(物理網卡只有一個)網卡之后,還想要再次添加一張虛擬網卡,調用netif_add沒有效果,應該如何解決添加虛擬網卡的問題?求大神幫助
    發表于 07-10 08:18

    RT-Thread 新里程碑達成——GitHub Star 破萬!

    RT-Thread實時操作系統開源項目在GitHub上的star數量突破一萬!截止發文,RT-Thread作為實時操作系統在業界Star數量排名第一!倉庫地址:https://gith
    的頭像 發表于 07-04 08:35 ?502次閱讀
    <b class='flag-5'>RT-Thread</b> 新里程碑達成——GitHub Star 破萬!

    6月6日杭州站RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    嵌入式軟件工程師郭占鑫老師為您講解有關技術知識和實踐經驗。通過本次workshop能深入理解RT-Thread專業版與混合部署的潛力,在RK3568平臺上提升系統實時
    的頭像 發表于 05-28 08:35 ?464次閱讀
    6月6日杭州站<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式!

    5月16日南京站RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    嵌入式軟件工程師郭占鑫老師為您講解有關技術知識和實踐經驗。通過本次workshop能深入理解RT-Thread專業版與混合部署的潛力,在RK3568平臺上提升系統
    的頭像 發表于 05-01 08:35 ?394次閱讀
    5月16日南京站<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式!

    RT-Thread混合部署Workshop北京站來啦!

    嵌入式軟件工程師郭占鑫老師為您講解有關技術知識和實踐經驗。通過本次workshop能深入理解RT-Thread專業版與混合部署的潛力,在RK3568平臺上提升系統
    的頭像 發表于 04-19 08:34 ?458次閱讀
    <b class='flag-5'>RT-Thread</b>混合部署Workshop北京站來啦!

    4月25日北京站RT-Thread線下workshop,探索RT-Thread混合部署新模式

    嵌入式軟件工程師郭占鑫老師為您講解有關技術知識和實踐經驗。通過本次workshop能深入理解RT-Thread專業版與混合部署的潛力,在RK3568平臺上提升系統
    的頭像 發表于 04-16 08:35 ?438次閱讀
    4月25日北京站<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式

    【4月10日-深圳-workshop】RT-Thread帶你探索混合部署新模式

    嵌入式軟件工程師農曉明老師為您講解有關技術知識和實踐經驗。通過本次workshop能深入理解RT-Thread專業版與混合部署的潛力,在RK3568平臺上提升系統
    的頭像 發表于 04-04 08:34 ?364次閱讀
    【4月10日-深圳-workshop】<b class='flag-5'>RT-Thread</b>帶你探索混合部署新模式

    4月10日深圳場RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    4月10日我們將在深圳福田舉辦RT-Thread混合部署線下workshop,在瑞芯微RK3568平臺上實現同時運行RT-Thread和linux,本次workshop邀請到RT-Thread資深嵌入式軟件工程師農曉明老師為您講
    的頭像 發表于 03-27 11:36 ?854次閱讀
    4月10日深圳場<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式!

    4月10日深圳場RT-Thread線下workshop,探索RT-Thread混合部署新模式!

    嵌入式軟件工程師農曉明老師為您講解有關技術知識和實踐經驗。通過本次workshop能深入理解RT-Thread專業版與混合部署的潛力,在RK3568平臺上提升系統
    的頭像 發表于 03-27 08:34 ?548次閱讀
    4月10日深圳場<b class='flag-5'>RT-Thread</b>線下workshop,探索<b class='flag-5'>RT-Thread</b>混合部署新模式!

    RT-Thread混合部署Workshop在上海張江成功舉行

    3月21號我們在上海張江舉辦的RT-Thread混合部署線下workshop圓滿落幕。本次活動由睿賽德科技團隊主辦,旨在為參與者提供全面的技術分享和經驗。
    的頭像 發表于 03-25 10:54 ?502次閱讀

    RT-Thread混合部署Workshop在上海張江成功舉行

    3月21號我們在上海張江舉辦的RT-Thread混合部署線下workshop圓滿落幕。本次活動由睿賽德科技團隊主辦,旨在為參與者提供全面的技術分享和經驗。現場邀請到了RT-Thread
    的頭像 發表于 03-23 08:34 ?379次閱讀
    <b class='flag-5'>RT-Thread</b>混合部署Workshop在上海張江成功舉行
    主站蜘蛛池模板: 婷婷五月天.com| 高清一区二区在线观看| 久久久久免费精品国产小说| 日本免费黄色小视频| 欧美作爱福利免费观看视频| 免费激情网站| 国产一区在线播放| www一级毛片| 天天看片国产| 国产亚洲精品久久久久久牛牛| 国产国拍亚洲精品mv在线观看| 日韩综合nv一区二区在线观看| 人人干视频| 国产精品自在线天天看片| 51xx嘿嘿午夜| 亚洲国产网| 亚洲天堂免费在线| 四虎海外在线永久免费看| 最色成人网| 午夜精品久久久久蜜桃| 日本动漫免费看| 黄频网站免费大全在线观看| 综合视频网| 日韩精品在线第一页| 俄罗斯欧美色黄激情| 色噜噜噜噜噜在线观看网站| 亚洲欧美综合一区| 欧美午夜片| 丁香六月色婷婷| 欧美在线视频7777kkkk| 男人和女人在床做黄的网站| 被cao到合不拢腿腐男男| 上课被同桌强行摸下面小黄文| 六月综合| 天天撸视频| 额去鲁97在线观看视频| 伊人三级| 亚洲精品久久久久久婷婷| 色www 永久免费网站| 日韩啪啪电影| 欧美大片一区|