我是靠谱客的博主 淡淡心锁,最近开发中收集的这篇文章主要介绍【原创】linux实时操作系统xenomai x86平台基准测试(benchmark),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、前言

benchmark 即基准测试。通常操作系统主要服务于应用程序,其运行也是需要一定cpu资源的,一般来说操作系统提供服务一定要快,否则会影响应用程序的运行效率,尤其是实时操作系统。所以本文针对操作系统来做一些基准测试,看看在低端x86平台上,xenomai提供我们平时常用的服务所需要的时间,清楚地了解该平台上一些xenomai服务的消耗,有时能有利于我们进一步优化程序。

目前大多商业实时操作系统会提供详细benchmark测试,比如VxWorks,目前xenomai没有这类的方式,所以借鉴VxWorks的测试方式,对xenomai进行同样测试,所以文章中的测试项命名可能在Linux开发人员看来有点别扭,切勿见怪,其中一些具体流程可见本博客另外一篇文章xenomai与VxWorks实时性对比(资源抢占上下文切换对比)。

测试环境:

CPU:Intel j1900

内存:4GB DDR3

注:测试数据仅供个人参考,单位us,每项测试次数500万次,编写测试用例使用的接口为Alchemy API,原因主要是Alchemy API比较好编写。

二、 测试数据处理

对于每个基准测试,通过在操作前读取时间戳 t 1 t1 t1,该操作完成后读取时间戳 t 2 t2 t2 t 2 t2 t2 t 1 t1 t1之间的差值就是测该操作的耗时。

1.1 测试注意事项

需要注意的是,由于我们是基准测试,所以 t 1 t1 t1~ t 2 t2 t2这段时间尽量不要被不相关的事务打断,比如处理不相关的中断、非测试范围内的任务抢占等。为此需要考虑如下。

① 执行测试操作的任务优先级必须最高,两个任务间交互的测试类似。

② 必须检测t1-t2之间的非相关中断,并丢弃对应的测试数据,由于我们已将非xenomai的中断隔离到其cpu0,且无其他实时设备中断,除各种异常外,剩下与xenomai相关的就是定时器中断了,所以仅对tick中断处理,如果测试过程中产生了定时器中断,则忽略这组数据,因此需要为xenomai添加一个系统调用来获取中断信息,测试前后通过该系统调用获中断信息,以此判断测试的过程中有没有中断产生。

③ 读取时间戳的操作也是需要执行时间的,所以需要从结果中减去该时间的影响,测量读取时间戳的需要的时间很简单,通过连续两次读取时间戳 a 1 a1 a1, a 2 a2 a2, a 2 − a 1 a2-a1 a2a1就是函数 _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(us)avg(us)max(us)
0.0840.0940.132

2.2 任务切换

2.2.1信号量响应上下文切换时间

bmCtxSempend: 同一cpu上,高优先级任务对空信号量P操作阻塞,到低优先任务激活的时间。

bmCtxSemUnpend: 同一cpu上,低优先级任务对信号量V操作到高优先任务激活的时间。

CtxSmpAffinitySemUnPend: 高低优先级任务运行于不同cpu上,高优先级任务对空信号量P操作阻塞,到低优先任务激活的时间。

CtxSmpNoAffinitySemUnPend: 不设置亲和性,随系统调度,低优先级任务对信号量V操作到高优先任务激活的时间。

min(us)avg(us)max(us)
bmCtxSempend2.1362.1932.641
bmCtxSemUnpend2.3512.3952.977
CtxSmpAffinitySemUnPend0.0000.7522.642
CtxSmpNoAffinitySemUnPend2.3892.4542.797
2.2.2消息队列响应上下文切换时间

bmCtxMsgqPend:同一cpu上,高优先级任务对空消息队列接收数据阻塞,到低优先任务激活的时间。

bmCtxMsgqUnpend:同一cpu上, 低优先级任务写消息队列到高优先任务激活的时间。

CtxSmpAffinityMsgQUnPend:高低优先级任务运行于不同cpu上,高优先级任务对空消息队列接收数据阻塞,到低优先任务激活的时间。

CtxSmpNoAffinityMsgQUnPend:不设置亲和性,随系统调度, 低优先级任务写消息队列到高优先任务激活的时间。

min(us)avg(us)max(us)
bmCtxMsgqPend2.4962.5292.833
bmCtxMsgqUnpend2.8822.9493.374
CtxSmpAffinityMsgQUnPend5.2455.49710.589
CtxSmpNoAffinityMsgQUnPend2.9412.9953.636
2.2.3事件响应上下文切换时间

bmCtxMsgqPend:高优先级任务接收事件阻塞,到低优先任务激活的时间。

bmCtxMsgqUnpend: 低优先级任务发送事件到高优先任务激活的时间。

min(us)avg(us)max(us)
bmCtxEventPend---
bmCtxEventUnpend---
CtxSmpAffinityEventQUnPend---
CtxSmpNoAffinityEventUnPend---
2.2.2.4任务上下文切换时间

bmCtxTaskSwitch:同一cpu上,优先级调度下的任务切换时间。

min(us)avg(us)max(us)
bmCtxTaskSwitch0.7031.6332.594

2.3 信号量(Semaphore)

1. 信号量的创建与删除

bmSemBCreate: 创建一个信号量耗时。

bmSemBDelete: 删除一个信号量耗时。

min(us)avg(us)max(us)
bmSemCreate10.43311.41712.977
bmSemDelete10.27611.43112.317
2. 信号量PV操作

SemGiveNoTask:当没有任务阻塞在信号量上时,对空信号量V操作消耗的时间。

SemGiveTaskInQ:同一CPU上,高优先级任务阻塞在信号量时,低优先级任务释放信号量操作消耗的时间。

SemTakeUnavail:单任务对不可用的信号量P操作消耗的时间。

SemTakeAvail:单任务对可用信号量非阻塞P操作消耗的时间。

bmSemGiveTake:单任务对同一信号量连续一次PV操作消耗的时间。

min(us)avg(us)max(us)
SemGiveNoTask0.0990.1100.132
SemGiveTaskInQ1.8372.0362.281
SemTakeAvail0.0840.0940.108
SemTakeUnavail0.1110.1250.144
SemGiveTake0.1870.1920.198
SemPrioInv6.5316.84211.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(us)avg(us)max(us)
MutexCreate2.8812.9473.205
MutexDelete2.0392.0842.209
MutexGiveNoTask0.0330.0440.066
MutexGiveTaskInQ0.0470.1170.228
MutexTakeAvail0.0840.0940.114
MutexGiveTake0.1180.1220.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(us)avg(us)max(us)
MsgQCreate5.9916.3246.855
MsgQDelete3.7333.8494.046
MsgQRecvAvail0.2400.2790.396
MsgQRecvNoAvail0.2160.2670.349
MsgQSendPend2.4012.6473.902
MsgQSendNoPend1.2231.2621.536
MsgQSendQFull0.2280.2750.408

2.6 定时器(Alarm)

AlarmCreate:创建一个alarm的时间。

AlarmDelStarted:删除一个已经激活的alarm的时间。

AlarmDelNotStarted:删除一个未激活alarm的时间。

AlarmStartQEmpty:任务没有alarm时,start一个alarm需要的时间。

AlarmStartQEmpty:任务在已有一个 alarm的基础上,再start一个alarm需要的时间。

AlarmCancel:stop一个alarm需要的时间。

min(us)avg(us)max(us)
AlarmCreate4.7904.9377.719
AlarmDelStarted3.6373.8044.250
AlarmDelNotStarted3.4203.5234.381
AlarmStartQEmpty1.8602.0793.158
AlarmStartQFull1.8351.8972.101
AlarmCancel1.5961.6802.677

2.7 事件(Event)

EventSendSelf: 任务向自己发送一个Event需要的时间。

EventReceiveAvailable: 接收一个已产生的Event需要的时间。

EventReceiveUnavailable: 非阻塞接收一个未产生的Event需要的时间。

EventTaskSendWanted: 高优先级等待Event时,发送Event需要的时间。

EventTaskSendUnwanted: 无任务等待Event时,发送Event需要的时间。

min(us)avg(us)max(us)
EventSendSelf4.7904.9377.719
EventReceiveAvailable3.6373.8044.250
EventReceiveUnavailable3.4203.5234.381
EventTaskSendWanted1.8602.0793.158
EventTaskSendUnwanted1.8351.8972.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(us)avg(us)max(us)
TaskSpawn(1000万次)150.649153.8591162.041
TaskDelete(1000万次)136.074145.766189.952
TaskInit(1000万次)178.703185.015436.639
TaskActivate1.0521.3362.986
TaskSuspendReady1.4041.4441.681
TaskSuspendPend0.0351.3921.561
TaskSuspendSusp0.1510.1550.321
TaskSuspendDelay1.3561.4011.525
TaskResumeReady0.1460.1550.487
TaskResumePend0.7560.8020.877
TaskResumeSusp0.2040.2480.324
TaskResumeDelay0.1800.2280.300
TaskPrioritySetReady18.92521.00221.855
TaskPrioritySetPend19.04621.01428.296
TaskCpuAffinityGet---
TaskCpuAffinitySet8.3329.54119.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(us)avg(us)max(us)
Cyclic33.58934.40936.471

最后

以上就是淡淡心锁为你收集整理的【原创】linux实时操作系统xenomai x86平台基准测试(benchmark)的全部内容,希望文章能够帮你解决【原创】linux实时操作系统xenomai x86平台基准测试(benchmark)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(72)

评论列表共有 0 条评论

立即
投稿
返回
顶部