1. 程式人生 > >【原創】linux實時作業系統xenomai x86平臺基準測試(benchmark)

【原創】linux實時作業系統xenomai x86平臺基準測試(benchmark)

## 一、前言 benchmark 即基準測試。通常作業系統主要服務於應用程式,其執行也是需要一定cpu資源的,一般來說作業系統提供服務一定要快,否則會影響應用程式的執行效率,尤其是實時作業系統。所以本文針對作業系統來做一些基準測試,看看在低端x86平臺上,xenomai提供我們平時常用的服務所需要的時間,清楚地瞭解該平臺上一些xenomai服務的消耗,有時能有利於我們進一步優化程式。影響因素有:主機CPU的結構、指令集以及CPU特性、運算速度等。 目前大多商業實時作業系統會提供詳細benchmark測試,比如VxWorks,目前xenomai沒有這類的方式,所以借鑑VxWorks的測試方式,對xenomai進行同樣測試,所以文章中的測試項命名可能在Linux開發人員看來有點彆扭,切勿見怪,其中一些具體流程可見本部落格另外一篇文章[xenomai與VxWorks實時性對比(資源搶佔上下文切換對比)](https://www.cnblogs.com/wsg1100/p/13415750.html)。 測試環境: CPU:Intel j1900 記憶體:4GB DDR3 >注:**測試資料僅供個人參考**,單位us,每項測試次數500萬次,編寫測試用例使用的介面為Alchemy API,原因主要是Alchemy API比較好編寫。 ## 二、 測試資料處理 對於每個基準測試,通過在操作前讀取時間戳$t1$,該操作完成後讀取時間戳$t2$,$t2$與$t1$之間的差值就是測該操作的耗時。 ![](https://wsg-blogs-pic.oss-cn-beijing.aliyuncs.com/xenomai/test.png) ### 1.1 測試注意事項 需要注意的是,由於我們是基準測試,所以$t1$~$t2$這段時間儘量不要被不相關的事務打斷,比如處理不相關的中斷、非測試範圍內的任務搶佔等。為此需要考慮如下。 ① 執行測試操作的任務優先順序必須最高,兩個任務間互動的測試類似。 ② 必須檢測t1-t2之間的非相關中斷,並丟棄對應的測試資料,由於我們已將非xenomai的中斷隔離到其cpu0,且無其他實時裝置中斷,除各種異常外,剩下與xenomai相關的就是定時器中斷了,所以僅對tick中斷處理,如果測試過程中產生了定時器中斷,則忽略這組資料,因此需要為xenomai新增一個系統呼叫來獲取中斷資訊,測試前後通過該系統呼叫獲中斷資訊,以此判斷測試的過程中有沒有中斷產生。 ③ 讀取時間戳的操作也是需要執行時間的,所以需要從結果中減去該時間的影響,測量讀取時間戳的需要的時間很簡單,通過連續兩次讀取時間戳$a1$,$a2$,$a2-a1$就是函式 `_M_TIMESTAMP()`的執行需要時間。 ### 1.2 資料的處理 得到無誤的操作耗時、測試次數後計算平均值最大值、最小值即可; ### 1.3 測試結構 根據以上,每個測試的流程及程式碼結構如下: ① 讀取起始tick ② 開始測試迴圈 ③ 讀取時間戳a ④ 讀取起始時間戳b ⑤ **被測試的操作** ⑥讀取結束時間戳c ⑦判斷是否是loadrun,是則丟棄本次結果跳轉到③ ⑧讀取tick,判斷本次測試是否位於同一tick內,否則丟棄本次結果跳轉到③ ⑨判讀耗時是都正確(a-b且b-c為正值),是則為有效值,否則丟棄本次結果跳轉到③ ```C unsigned long a; unsigned long b; unsigned long c; ULONG tick; BOOL loadRun = TRUE; /*排除cache對測試的影響,丟棄第一次測試的資料*/ tick = tickGet(); /*確保測試在同一個tick內完成*/ /*迴圈測試iterations次操作並統計結果*/ for (counter = 0; counter < pData->iterations; counter++) { a = _M_TIMESTAMP(); b = _M_TIMESTAMP(); /*起始時間*/ wd = wdCreate ();/*測試的操作*/ c = _M_TIMESTAMP(); /*結束時間*/ /*資料統計處理*/ BM_DATA_RECORD (((c >= b) && (b >= a)), c - b, b - a, counter, tick, loadRun); } ``` ## 二、測試項 明白資料統計處理後剩下的就是其中測試的具體操作了,benchmark 分別對二值訊號量(semB)、計數訊號量(semC)、互斥量(semM)、讀寫訊號量(SemRW)、任務(Task)、訊息佇列(msgq)、事件(event)、 中斷響應(interrupt)、上下文切換(contexswitch)、時鐘抖動(TaskJitter、IntJitter)在各種可能的情況下,測試該操作的耗時。 ### 2.1 時間戳 測試讀時間戳耗時`bmTimestampRead`。 ```C unsigned long a; unsigned long b; ULONG tick; BOOL loadRun = TRUE; \ tick = tickGet(); for (counter = 0; counter < pData->iterations; counter++) { a = _M_TIMESTAMP(); b = _M_TIMESTAMP(); /* validate and record data */ BM_DATA_RECORD ((b > a), b - a, 0, counter, tick, loadRun); } ``` ![](https://wsg-blogs-pic.oss-cn-beijing.aliyuncs.com/xenomai/rdtims.png) | min | avg | max | | :---: | :---: | :---: | | 0.084 | 0.094 | 0.132 | ### 2.2 任務切換 ##### 2.2.1訊號量響應上下文切換時間 bmCtxSempend: 同一cpu上,高優先順序任務對空訊號量P操作阻塞,到低優先任務啟用的時間。 bmCtxSemUnpend: 同一cpu上,低優先順序任務對訊號量V操作到高優先任務啟用的時間。 CtxSmpAffinitySemUnPend: 高低優先順序任務運行於不同cpu上,高優先順序任務對空訊號量P操作阻塞,到低優先任務啟用的時間。 CtxSmpNoAffinitySemUnPend: 不設定親和性,隨系統排程,低優先順序任務對訊號量V操作到高優先任務啟用的時間。 | | min | avg | max | | ------------------------- | ----- | ----- | ----- | | bmCtxSempend | 2.136 | 2.193 | 2.641 | | bmCtxSemUnpend | 2.351 | 2.395 | 2.977 | | CtxSmpAffinitySemUnPend | 0.000 | 0.752 | 2.642 | | CtxSmpNoAffinitySemUnPend | 2.389 | 2.454 | 2.797 | ##### 2.2.2訊息佇列響應上下文切換時間 bmCtxMsgqPend:同一cpu上,高優先順序任務對空訊息佇列接收資料阻塞,到低優先任務啟用的時間。 bmCtxMsgqUnpend:同一cpu上, 低優先順序任務寫訊息佇列到高優先任務啟用的時間。 CtxSmpAffinityMsgQUnPend:高低優先順序任務運行於不同cpu上,高優先順序任務對空訊息佇列接收資料阻塞,到低優先任務啟用的時間。 CtxSmpNoAffinityMsgQUnPend:不設定親和性,隨系統排程, 低優先順序任務寫訊息佇列到高優先任務啟用的時間。 | | min | avg | max | | -------------------------- | ----- | ----- | ------ | | bmCtxMsgqPend | 2.496 | 2.529 | 2.833 | | bmCtxMsgqUnpend | 2.882 | 2.949 | 3.374 | | CtxSmpAffinityMsgQUnPend | 5.245 | 5.497 | 10.589 | | CtxSmpNoAffinityMsgQUnPend | 2.941 | 2.995 | 3.636 | ##### 2.2.3事件響應上下文切換時間 bmCtxMsgqPend:高優先順序任務接收事件阻塞,到低優先任務啟用的時間。 bmCtxMsgqUnpend: 低優先順序任務傳送事件到高優先任務啟用的時間。 | | min | avg | max | | --------------------------- | ---- | ---- | ---- | | bmCtxEventPend | - | - | - | | bmCtxEventUnpend | - | - | - | | CtxSmpAffinityEventQUnPend | - | - | - | | CtxSmpNoAffinityEventUnPend | - | - | - | ##### 2.2.2.4任務上下文切換時間 bmCtxTaskSwitch:同一cpu上,優先順序排程下的任務切換時間。 | | min | avg | max | | --------------- | ----- | ----- | ----- | | bmCtxTaskSwitch | 0.703 | 1.633 | 2.594 | ### 2.3 訊號量(Semaphore) ##### 1. 訊號量的建立與刪除 bmSemBCreate: 建立一個訊號量耗時。 bmSemBDelete: 刪除一個訊號量耗時。 | | min | avg | max | | ----------- | ------ | ------ | ------ | | bmSemCreate | 10.433 | 11.417 | 12.977 | | bmSemDelete | 10.276 | 11.431 | 12.317 | ##### 2. 訊號量PV操作 SemGiveNoTask:當沒有任務阻塞在訊號量上時,對空訊號量V操作消耗的時間。 SemGiveTaskInQ:同一CPU上,高優先順序任務阻塞在訊號量時,低優先順序任務釋放訊號量操作消耗的時間。 SemTakeUnavail:單任務對不可用的訊號量P操作消耗的時間。 SemTakeAvail:單任務對可用訊號量非阻塞P操作消耗的時間。 bmSemGiveTake:單任務對同一訊號量連續一次PV操作消耗的時間。 | | min | avg | max | | -------------- | ----- | ----- | ------ | | SemGiveNoTask | 0.099 | 0.110 | 0.132 | | SemGiveTaskInQ | 1.837 | 2.036 | 2.281 | | SemTakeAvail | 0.084 | 0.094 | 0.108 | | SemTakeUnavail | 0.111 | 0.125 | 0.144 | | SemGiveTake | 0.187 | 0.192 | 0.198 | | SemPrioInv | 6.531 | 6.842 | 11.968 | ### 2.4 互斥量(Mutex) ##### 2.4.1 互斥量的建立與刪除 MutexCreate:建立一個互斥量耗時。 MutexDelete:刪除一個互斥量耗時。 ##### 2.4.2 互斥量PV操作 MutexGiveNoTask:當沒有任務阻塞在mutex上時,釋放mutex操作消耗的時間。 MutexGiveTaskInQ:同一CPU上,高優先順序任務阻塞在mutex時,低優先順序任務釋放mutex操作消耗的時間。 MutexTakeUnavail:當沒有mutex可用時,對mutex請求操作的耗時。 MutexTakeAvail:在mutex可用時,請求mutex消耗的時間。 MutexGiveTake:單任務對mutex連續請求釋放消耗的時間。 | | min | avg | max | | ---------------- | ----- | ----- | ----- | | MutexCreate | 2.881 | 2.947 | 3.205 | | MutexDelete | 2.039 | 2.084 | 2.209 | | MutexGiveNoTask | 0.033 | 0.044 | 0.066 | | MutexGiveTaskInQ | 0.047 | 0.117 | 0.228 | | MutexTakeAvail | 0.084 | 0.094 | 0.114 | | MutexGiveTake | 0.118 | 0.122 | 0.148 | ### 2.5 訊息佇列(Message Queue) ##### 2.5.1 建立與刪除 MsgQCreate:建立一個MsgQ需要的時間。 MsgQDelete:刪除一個MsgQ需要的時間。 ##### 2.5.2 資料收發 MsgQRecvAvail:當MsgQ內有資料時,接收1Byte資料需要的時間。 MsgQRecvNoAvail:當MsgQ沒有資料時,非阻塞接收1Byte資料需要的時間。 MsgQSendPend:高優先順序等待資料時,傳送1Byte資料需要的時間。 MsgQSendNoPend:沒有任務等待資料時,傳送1Byte資料需要的時間。 MsgQSendQFull:當MsgQ滿時,非阻塞傳送1Byte資料需要的時間。 | | min | avg | max | | --------------- | ----- | ----- | ----- | | MsgQCreate | 5.991 | 6.324 | 6.855 | | MsgQDelete | 3.733 | 3.849 | 4.046 | | MsgQRecvAvail | 0.240 | 0.279 | 0.396 | | MsgQRecvNoAvail | 0.216 | 0.267 | 0.349 | | MsgQSendPend | 2.401 | 2.647 | 3.902 | | MsgQSendNoPend | 1.223 | 1.262 | 1.536 | | MsgQSendQFull | 0.228 | 0.275 | 0.408 | ### 2.6 定時器(Alarm) AlarmCreate:建立一個alarm的時間。 AlarmDelStarted:刪除一個已經啟用的alarm的時間。 AlarmDelNotStarted:刪除一個未啟用alarm的時間。 AlarmStartQEmpty:任務沒有alarm時,start一個alarm需要的時間。 AlarmStartQEmpty:任務在已有一個 alarm的基礎上,再start一個alarm需要的時間。 AlarmCancel:stop一個alarm需要的時間。 | | min | avg | max | | ------------------ | ----- | ----- | ----- | | AlarmCreate | 4.790 | 4.937 | 7.719 | | AlarmDelStarted | 3.637 | 3.804 | 4.250 | | AlarmDelNotStarted | 3.420 | 3.523 | 4.381 | | AlarmStartQEmpty | 1.860 | 2.079 | 3.158 | | AlarmStartQFull | 1.835 | 1.897 | 2.101 | | AlarmCancel | 1.596 | 1.680 | 2.677 | ### 2.7 事件(Event) EventSendSelf: 任務向自己傳送一個Event需要的時間。 EventReceiveAvailable: 接收一個已產生的Event需要的時間。 EventReceiveUnavailable: 非阻塞接收一個未產生的Event需要的時間。 EventTaskSendWanted: 高優先順序等待Event時,傳送Event需要的時間。 EventTaskSendUnwanted: 無任務等待Event時,傳送Event需要的時間。 | | min | avg | max | | ----------------------- | ----- | ----- | ----- | | EventSendSelf | 4.790 | 4.937 | 7.719 | | EventReceiveAvailable | 3.637 | 3.804 | 4.250 | | EventReceiveUnavailable | 3.420 | 3.523 | 4.381 | | EventTaskSendWanted | 1.860 | 2.079 | 3.158 | | EventTaskSendUnwanted | 1.835 | 1.897 | 2.101 | ### 2.8 任務(Task) ##### 2.8.1 任務建立啟用 TaskSpawn: 建立並激活一個任務需要的時間。 TaskDelete:刪除一個任務需要的時間。 TaskInit:建立一個任務需要的時間。 TaskActivate:啟用新建立的任務需要的時間。 ##### 2.8.2 任務排程控制 TaskSuspendReady:對一個已經處於ready狀態的任務suspend操作需要的時間。 TaskSuspendPend:對一個等待資源處於pend狀態的任務進行suspend操作需要的時間。 TaskSuspendSusp:對剛建立的處於Suspend任務 執行Suspend操作需要的時間。 TaskSuspendDelay:對一個處於sleep任務進行suspend操作需要的時間。 TaskResumeReady:對一個處於Ready狀態的任務進行Resume操作需要的時間。 TaskResumePend:對一個等待資源處於pend狀態的任務進行Resume操作需要的時間。 TaskResumeSusp:對一個處於Suspend狀態的任務進行Resume操作需要的時間。 TaskResumeDelay:對一個處於sleep任務進行Resume操作需要的時間。 TaskPrioritySetReady:對一個處於Ready狀態任務修改優先順序操作需要的時間。 TaskPrioritySetPend:對一個處於pend狀態任務修改優先順序操作需要的時間。 bmTaskCpuAffinityGet:獲取任務的親和性需要的時間。 bmTaskCpuAffinitySet:設定任務的親和性需要的時間。 | | min | avg | max | | -------------------- | ------- | ------- | -------- | | TaskSpawn(1000萬次) | 150.649 | 153.859 | 1162.041 | | TaskDelete(1000萬次) | 136.074 | 145.766 | 189.952 | | TaskInit(1000萬次) | 178.703 | 185.015 | 436.639 | | TaskActivate | 1.052 | 1.336 | 2.986 | | TaskSuspendReady | 1.404 | 1.444 | 1.681 | | TaskSuspendPend | 0.035 | 1.392 | 1.561 | | TaskSuspendSusp | 0.151 | 0.155 | 0.321 | | TaskSuspendDelay | 1.356 | 1.401 | 1.525 | | TaskResumeReady | 0.146 | 0.155 | 0.487 | | TaskResumePend | 0.756 | 0.802 | 0.877 | | TaskResumeSusp | 0.204 | 0.248 | 0.324 | | TaskResumeDelay | 0.180 | 0.228 | 0.300 | | TaskPrioritySetReady | 18.925 | 21.002 | 21.855 | | TaskPrioritySetPend | 19.046 | 21.014 | 28.296 | | TaskCpuAffinityGet | - | - | - | | TaskCpuAffinitySet | 8.332 | 9.541 | 19.808 | Cyclic:如下操作的流程迴圈一次的耗時,圖中M表示mutex,B表示Semaphore。 ```C /* Higher Priority Lower Priority Task1 Task2 =============== ============== semTake(M) semGive(M) | V semGive(B) semTake(B) | V semTake(B) \ \ \-------------> semTake(M) semGive(B) / / semTake(M) <-------------/ \ \ \------------->
semGive(M) / / semGive(M) <-------------/ | V taskSuspend() <-------------/ \ \ \-------------> taskResume() / / msgQSend() <-------------/ msgQReceive() | V msgQReceive() \ \ \-------------> msgQSend() / / taskDelay(0) <-------------/ | V eventReceive() \ \ \-------------> eventSend() / / repeat... <-------------/ */ ``` | | min | avg | max | | ------ | ------ | ------ | ------ | | Cyclic | 33.589 | 34.409 | 36.471 | 版權宣告:本文為本文為博主原創文章,轉載請註明出處。如有問題,歡迎指正。部落格地址:https://www.cnblogs.com/