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

木多發表於2020-10-25

一、前言

benchmark 即基準測試。通常作業系統主要服務於應用程式,其執行也是需要一定cpu資源的,一般來說作業系統提供服務一定要快,否則會影響應用程式的執行效率,尤其是實時作業系統。所以本文針對作業系統來做一些基準測試,看看在低端x86平臺上,xenomai提供我們平時常用的服務所需要的時間,清楚地瞭解該平臺上一些xenomai服務的消耗,有時能有利於我們進一步優化程式。影響因素有:主機CPU的結構、指令集以及CPU特性、運算速度等。

目前大多商業實時作業系統會提供詳細benchmark測試,比如VxWorks,目前xenomai沒有這類的方式,所以借鑑VxWorks的測試方式,對xenomai進行同樣測試,所以文章中的測試項命名可能在Linux開發人員看來有點彆扭,切勿見怪,其中一些具體流程可見本部落格另外一篇文章xenomai與VxWorks實時性對比(資源搶佔上下文切換對比)

測試環境:

CPU:Intel j1900

記憶體:4GB DDR3

注:測試資料僅供個人參考,單位us,每項測試次數500萬次,編寫測試用例使用的介面為Alchemy API,原因主要是Alchemy API比較好編寫。

二、 測試資料處理

對於每個基準測試,通過在操作前讀取時間戳\(t1\),該操作完成後讀取時間戳\(t2\)\(t2\)\(t1\)之間的差值就是測該操作的耗時。

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為正值),是則為有效值,否則丟棄本次結果跳轉到③

	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

 	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);
	}

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。

/*
       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/wsg1100/

相關文章