本篇文章描述基于Rhealstone的系統實時性的測量基準的框架--R-Rhealstone框架。
在嵌入式軟件設計和集成中,實時多任務操作系統的性能分析是至關重要的,它需要保證應用的時間限制得到滿足,即是運行時間不能超過應用的時間限制。為了選擇滿足用于特定應用的嵌入式系統的一個適當的操作系統,我們需要對操作系統服務進行分析。這些操作系統服務是由形成性能指標的參數確定的,既定的性能指標包括上下文切換時間、任務搶占時間、中斷延遲時間、信號量混洗時間、死鎖解除時間、信息傳輸延遲。
關于實時操作系統對性能指標進行分析,是為了選擇滿足用于特定應用的嵌入式系統的最優的操作系統。
Rhealstone
Rhealstone是系統實時性的測量基準之一,Rhealstone性能基準程序是實時系統的六個關鍵操作的時間量進行操作,這六個關鍵操作是:上下文切換時間、任務搶占時間、中斷延遲時間、信號量混洗時間、死鎖解除時間、信息傳輸延遲。這六項操作作為Rhealstone的六個組件,每個組件被單獨測量。然后將經驗結果合并為單一的測量值,即是Rhealstone值。
測量Rhealstone值方式:
序號 | 說明 |
---|---|
方式 1 | 通用Rhealstone |
方式 2 | 每個組件應用于具體應用程序的特定Rhealstone |
Rhealstone性能基準程的缺點:
序號 | 說明 |
---|---|
缺點 1 | 測量的是平均時間,而不是最壞值 |
缺點 2 | 后的結論是加權平均值,沒有給出確定權值的依據 |
R-Rhealstone框架
設計R-Rhealstone框架的目的:為了能讓對比的系統實時性的測量的一致性,必須保證同一個環境,解除差異性帶來測量干擾,所以R-Rhealstone框架提供了操作系統適配層,統一適配不同操作系統的各個接口,目的可以達到上層調用層次一致。
上下文切換時間
描述:
上下文切換時間也稱任務切換時間(task switching time),定義為系統在兩個獨立的、處于就緒態并且具有相同優先級的任務之間切換所需要的時間。它包括三個部分,即保存當前任務上下文的時間、調度程序選中新任務的時間和恢復新任務上下文的時間。切換所需的時間主要取決于保存任務上下文所用的數據結構以及操作系統采用的調度算法的效率。產生任務切換的原因可以是資源可得,信號量的獲取等。任務切換是任一多任務系統中基本效率的測量點,它是同步的,非搶占的,實時控制軟件實現了一種基于同等優先級任務的時間片輪轉算法。影響任務切換的因素有:主機CPU的結構,指令集以及CPU特性。
任務切換過程增加了應用程序的額外負荷。CPU的內部寄存器越多,額外負荷就越重。任務切換所需要的時間取決于CPU有多少寄存器要入棧。實時內核的性能不應該以每秒鐘能做多少次任務切換來評價,RTOS中通常是1微秒左右。
流程:
原理:創建兩個同等優先級的任務,兩個任務相互切換多次,最后求平均值。
注意:①需要減去多次切換的循環時間(loop_overhead);②需要減去主動讓CPU執行時間(dir_overhead)
時間計算公式:
total_time:多次上下文切換總時間
loop_overhead:多次切換的循環時間
iterations:切換的次數
dir_overhead:調用讓出CPU接口的時間
代碼:
#include"rst.h" #include"rst_ipc.h" #include"rst_btime.h" staticfloatloop_overhead=0.0; staticfloatdir_overhead=0.0; staticfloattelapsed=0.0; staticuint32_tcount1,count2; staticrst_task_idrst_task1=NULL; staticrst_task_idrst_task2=NULL; staticrst_task_attrrst_task1_attr={ .name="task1", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-1, #else .priority=RST_TASK_HIGHEST_PRIORITY+1, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticrst_task_attrrst_task2_attr={ .name="task2", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-1, #else .priority=RST_TASK_HIGHEST_PRIORITY+1, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticvoidrst_task2_func(void*arg); staticvoidrst_task1_func(void*arg) { rst_task_create(&rst_task2,rst_task2_func,NULL,&rst_task2_attr); if(rst_task2==NULL) { RST_LOGE("RST:task2createfailed"); rst_task_delete(NULL); return; } /*Yieldprocessorsosecondtaskcanstartupandrun*/ rst_task_yield(); for(count1=0;count1
任務搶占時間
描述:
搶占時間即系統將控制權從低優先級的任務轉移到高優先級任務所花費的時間。為了對任務進行搶占,系統必須首先識別引起高優先級任務就緒的事件,比較兩個任務的優先級,最后進行任務的切換,所以搶占時間中包括了任務切換時間。
它和任務切換有些類似,但是搶占時間通常花費時間更長。這是因為執行中首先要確認喚醒事件,并評估正在運行的任務和請求運行的任務的優先級高低,然后才決定是否切換任務。實質上,所有的多處理任務可以在執行期間動態分配優先級,所以,搶占時間也是衡量實時性能的重要指標。
流程:
原理:創建兩個任務,任務1優先級比任務2優先級低,兩個任務進行搶占多次,最后求平均值。
注意:①需要減去多次任務搶占的循環時間(loop_overhead);②需要減去掛起任務所需要的時間(dir_overhead)
時間計算公式:
total_time:多次任務搶占總時間
loop_overhead:多次任務搶占的循環時間
iterations:任務搶占的次數
switch_overhead:掛起任務所需要的時間
代碼:
#include"rst.h" #include"rst_ipc.h" #include"rst_btime.h" staticfloatloop_overhead=0.0; staticfloatswitch_overhead=0.0; staticfloattelapsed=0.0; staticuint32_tcount; staticrst_task_idrst_task1=NULL; staticrst_task_idrst_task2=NULL; staticrst_task_attrrst_task1_attr={ .name="task1", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-3, #else .priority=RST_TASK_HIGHEST_PRIORITY+3, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticrst_task_attrrst_task2_attr={ .name="task2", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-1, #else .priority=RST_TASK_HIGHEST_PRIORITY+1, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticvoidrst_task2_func(void*arg); staticvoidrst_task1_func(void*arg) { /*Startuptask2,getpreempted*/ rst_task_create(&rst_task2,rst_task2_func,NULL,&rst_task2_attr); if(rst_task2==NULL) { RST_LOGE("RST:task2createfailed"); rst_task_delete(NULL); return; } switch_overhead=rst_benchmark_time_read(); rst_benchmark_time_init(); /*Benchmarkcode*/ for(count=0;count
中斷延遲時間
描述:
中斷延遲時間是指從接收到中斷信號到操作系統做出響應,并完成進入中斷服務例程所需要的時間。多任務操作系統中,中斷處理首先進入一個中斷服務的總控程序,然后才進入驅動程序的ISR。
中斷延遲時間=最大關中斷時間+硬件開始處理中斷到開始執行中斷服務例程第一條指令之間的時間。
硬件開始處理中斷到開始執行中斷服務例程的第一條指令之間的時間由硬件決定,所以,中斷延遲時間的長短主要取決于最大關中斷的時間。硬實時操作系統的關中斷時間通常是幾微秒,而Linux最壞可達幾毫秒。
流程:
原理:創建一個任務,任務執行主動觸發中斷,執行完中斷服務程序返回,統計其時間。
注意:①需要減去讀取時間接口的耗時時間(timer_overhead);
時間計算公式:
isr_enter_time:多次任務搶占總時間
iterations:任務搶占的次數
timer_overhead:讀取時間接口的耗時時間
代碼:
#include"rst.h" #include"rst_ipc.h" #include"rst_btime.h" staticfloattimer_overhead=0.0; staticfloatisr_enter_time=0.0; staticrst_task_idrst_task1=NULL; staticrst_task_attrrst_task1_attr={ .name="task1", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_LOWEST_PRIORITY+1, #else .priority=RST_TASK_LOWEST_PRIORITY-1, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticvoidrst_isr_handler(void*param) { isr_enter_time=rst_benchmark_time_read(); } staticvoidrst_task1_func(void*arg) { rst_isr_install(RST_ISR_NUM,rst_isr_handler,NULL); /*Benchmarkcode*/ rst_benchmark_time_init(); /*goestoIsr_handler*/ rst_isr_trigger(RST_ISR_NUM); RST_PRINT_TIME( "R-Rhealstone:interruptlatencytime", isr_enter_time, 1,/*OnlyRhealstonethatisn'tanaverage*/ timer_overhead, 0 ); rst_task_delete(NULL); } rst_statusrst_interrupt_latency_init(void) { rst_task_create(&rst_task1,rst_task1_func,NULL,&rst_task1_attr); if(rst_task1==NULL) { RST_LOGE("RST:task1createfailed"); returnRST_ERROR; } rst_benchmark_time_init(); rst_benchmark_time_read(); rst_benchmark_time_init(); timer_overhead=rst_benchmark_time_read(); returnRST_OK; }
信號量混洗時間
描述:
信號量混洗時間(semaphore shuffling time),是指從一個任務釋放信號量到另一個等待該信號量的任務被激活的時間延遲。在RTOS中,通常有許多任務同時競爭某一共享資源,基于信號量的互斥訪問保證了任一時刻只有一個任務能夠訪問公共資源。信號量混洗時間反映了與互斥有關的時間開銷,因此也是衡量RTOS實時性能的一個重要指標。
流程:
原理:創建一個信號量和兩個相同優先級的任務。代碼需要執行兩次,第一次信號量不介入調度,計算任務切換的時間,第二次多次循環,信號量接入調度,信號量在兩個任務中ping-pong執行,計算總時間。
注意:①需要減去任務切換的時間(switch_overhead);
時間計算公式:
telapsed:多次信號量混洗總時間
iterations:信號量混洗的次數
switch_overhead:切換的時間
代碼:
#include"rst.h" #include"rst_ipc.h" #include"rst_btime.h" staticfloatswitch_overhead=0.0; staticfloattelapsed=0.0; staticuint32_tcount=0; staticuint32_tsem_exe=1; staticrst_task_idrst_task1=NULL; staticrst_task_idrst_task2=NULL; staticrst_sem_idrst_sem=NULL; staticrst_task_attrrst_task1_attr={ .name="task1", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-1, #else .priority=RST_TASK_HIGHEST_PRIORITY+1, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticrst_task_attrrst_task2_attr={ .name="task2", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-1, #else .priority=RST_TASK_HIGHEST_PRIORITY+1, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticvoidrst_task2_func(void*arg); staticvoidrst_task1_func(void*arg) { /*Startuptask2,yieldsoitcanrun*/ rst_task_create(&rst_task2,rst_task2_func,NULL,&rst_task2_attr); if(rst_task2==NULL) { RST_LOGE("RST:task2createfailed"); rst_task_delete(NULL); return; } rst_task_yield(); /*Benchmarkcode*/ for(;count
死鎖解除時間
描述:
死鎖解除時間(deadlock breaking time),即系統解開處于死鎖狀態的多個任務所需花費的時間。死鎖解除時間反映了RTOS解決死鎖的算法的效率。
流程:
原理:創建一個信號量和三個任務,優先級排序:任務1 < 任務2 < 任務3。代碼需要執行兩次,第一次信號量不介入調度,計算任務3切換到任務2,任務2切換到任務1得時間(即從高優先級切換到低優先級得時間),第二次多次循環,信號量接入調度,任務3死鎖,任務2喚醒任務1,任務1解除死鎖,通過統計多次,求平均值。
注意:①需要減去任務切換的時間(switch_overhead);
時間計算公式:
telapsed:多次死鎖解除總時間
iterations:死鎖解除的次數
switch_overhead:任務切換的時間
lock_overhead:調用信號量持有接口所需要得時間
代碼:
#include"rst.h" #include"rst_ipc.h" #include"rst_btime.h" staticfloatswitch_overhead=0.0; staticfloatlock_overhead=0.0; staticfloattelapsed=0.0; staticuint32_tcount=0; staticuint32_tsem_exe=1; staticrst_task_idrst_task1=NULL; staticrst_task_idrst_task2=NULL; staticrst_task_idrst_task3=NULL; staticrst_sem_idrst_sem=NULL; staticrst_task_attrrst_task1_attr={ .name="task1", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-1, #else .priority=RST_TASK_HIGHEST_PRIORITY+1, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticrst_task_attrrst_task2_attr={ .name="task2", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-3, #else .priority=RST_TASK_HIGHEST_PRIORITY+3, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticrst_task_attrrst_task3_attr={ .name="task3", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-5, #else .priority=RST_TASK_HIGHEST_PRIORITY+5, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticvoidrst_task1_func(void*arg) { /*AlltaskshavehadtimetostartuponceTA01isrunning*/ /*Benchmarkcode*/ rst_benchmark_time_init(); for(count=0;count
信息傳輸延遲
描述:
信息傳輸延遲(datagram throuShput time),指一個任務通過調用RTOS的消息隊列,把數據傳送到另一個任務去時,每秒可以傳送的字節數。
流程:
原理:創建一個消息隊列和兩個任務,優先級排序:任務1 < 任務2。任務1負責發送數據,任務2負責接收數據,執行多次,求平均值
注意:①需要減去調用消息隊列接收函數的時間(receive_overhead);
時間計算公式:
telapsed:多次信息傳輸總時間
iterations:死鎖解除的次數
loop_overhead:多次循環的時間
receive_overhead:調用消息隊列接收函數的時間
代碼:
#include"rst.h" #include"rst_ipc.h" #include"rst_btime.h" #defineRST_QUEUE_BUFF_SIZE4 staticfloatloop_overhead=0.0; staticfloatreceive_overhead=0.0; staticfloattelapsed=0.0; staticuint32_tcount; staticrst_task_idrst_task1=NULL; staticrst_task_idrst_task2=NULL; staticrst_queue_idrst_queue=NULL; staticintqueue_buff[RST_QUEUE_BUFF_SIZE]={0}; staticrst_task_attrrst_task1_attr={ .name="task1", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-3, #else .priority=RST_TASK_HIGHEST_PRIORITY+3, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticrst_task_attrrst_task2_attr={ .name="task2", #ifRST_BIG_NUM_HIGH_PRIORITY .priority=RST_TASK_HIGHEST_PRIORITY-1, #else .priority=RST_TASK_HIGHEST_PRIORITY+1, #endif .stack_size=RST_TASK_STACK_SIZE, }; staticvoidrst_task2_func(void*arg); staticvoidrst_task1_func(void*arg) { /*Putamessageinthequeuesorecieveoverheadcanbefound.*/ rst_queue_send(rst_queue, (constvoid*)queue_buff, (uint32_t)sizeof(queue_buff), (rst_time_t)RST_WAIT_FOREVER); /*Startupsecondtask,getpreempted*/ rst_task_create(&rst_task2,rst_task2_func,NULL,&rst_task2_attr); if(rst_task2==NULL) { RST_LOGE("RST:task2createfailed"); rst_task_delete(NULL); return; } for(;count
RTOS對比結論
對比環境說明
項 | 說明 |
---|---|
芯片 |
芯片型號:stm32f401 芯片架構:Cortex-M4 主頻:84 MHz |
開發環境 | KEIL 5.x |
工具鏈 | ARMCC |
對比結果說明
對比項 | RT-Thread | LiteOS | FreeRTOS | TobudOS |
---|---|---|---|---|
上下文切換 | 2.594596 us | 6.739740 us | 1.049049 us | 2.343343 |
任務搶占 | 7.360721 us | 7.603206 us | 2.715431 us | 4.523046 us |
中斷延遲 | 2.000000 us | 1.000000 us | 1.000000 us | 1.000000 us |
信號量混洗 | 23.829000 us | 25.588000 us | 19.496000 us | 18.451000 us |
死鎖解除 | 18.108000 us | 18.074000 us | 21.522000 us | 31.606000 us |
信息傳輸延遲 | 7.749499 us | 7.390782 us | 7.298597 us | 3.446894 us |
總結
作者測試過程采用定時器計數器是1us,精度上有所欠缺,策略結果大致對比
中斷延時部分,RT-Thread的中斷是有框架的,而LiteOS和FreeRTOS直接使用STM32的HAL庫,時間差異在框架的耗時
FreeRTOS在本次的對比的優勢比較明顯,除了死鎖解除稍微遜色一點,其他的持平或由于RT-Thread和LiteOS
LiteOS在本次對比表現最差,尤其是上下文切換的耗時是RT-Thread和FreeRTOS的2~3倍。
說明:該框架目前已經適配作為RT-Thread的軟件包,可以通過軟件包體驗其功能
審核編輯:湯梓紅
-
寄存器
+關注
關注
31文章
5336瀏覽量
120231 -
嵌入式系統
+關注
關注
41文章
3587瀏覽量
129436 -
RTOS
+關注
關注
22文章
811瀏覽量
119595 -
實時操作系統
+關注
關注
1文章
197瀏覽量
30753
原文標題:如何選擇RTOS?使用R-Rhealstone框架評估
文章出處:【微信號:風火輪技術團隊,微信公眾號:風火輪技術團隊】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論