linux实时操作系统xenomai x86平台基准测试(benchmark)

简介: 本文是关于Xenomai实时操作系统的基准测试,旨在评估其在低端x86平台上的性能。测试模仿了VxWorks的方法,关注CPU结构、指令集等因素对系统服务耗时的影响。测试项目包括信号量、互斥量、消息队列、任务切换等,通过比较操作前后的时戳来测量耗时,并排除中断和上下文切换的干扰。测试结果显示了各项操作的最小、平均和最大耗时,为程序优化提供参考。注意,所有数据基于特定硬件环境,测试用例使用Alchemy API编写。

[TOC]

一、前言

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/

目录
相关文章
|
18天前
|
监控 Oracle 关系型数据库
Linux平台Oracle开机自启动设置
【11月更文挑战第8天】在 Linux 平台设置 Oracle 开机自启动有多种方法,本文以 CentOS 为例,介绍了两种常见方法:使用 `rc.local` 文件(较简单但不推荐用于生产环境)和使用 `systemd` 服务(推荐)。具体步骤包括编写启动脚本、赋予执行权限、配置 `rc.local` 或创建 `systemd` 服务单元文件,并设置开机自启动。通过 `systemd` 方式可以更好地与系统启动过程集成,更规范和可靠。
|
25天前
|
安全 Linux 虚拟化
|
12天前
|
人工智能 供应链 安全
AI辅助安全测试案例某电商-供应链平台平台安全漏洞
【11月更文挑战第13天】该案例介绍了一家电商供应链平台如何利用AI技术进行全面的安全测试,包括网络、应用和数据安全层面,发现了多个潜在漏洞,并采取了有效的修复措施,提升了平台的整体安全性。
|
19天前
|
Oracle Ubuntu 关系型数据库
Linux平台Oracle开机自启动设置
【11月更文挑战第7天】本文介绍了 Linux 系统中服务管理机制,并详细说明了如何在使用 systemd 和 System V 的系统上设置 Oracle 数据库的开机自启动。包括创建服务单元文件、编辑启动脚本、设置开机自启动和启动服务的具体步骤。最后建议重启系统验证设置是否成功。
|
22天前
|
监控 安全 测试技术
构建高效的精准测试平台:设计与实现指南
在软件开发过程中,精准测试是确保产品质量和性能的关键环节。一个精准的测试平台能够自动化测试流程,提高测试效率,缩短测试周期,并提供准确的测试结果。本文将分享如何设计和实现一个精准测试平台,从需求分析到技术选型,再到具体的实现步骤。
91 1
|
2月前
|
人工智能 监控 测试技术
云应用开发平台测试
云应用开发平台测试
63 2
|
2月前
|
NoSQL Ubuntu Linux
Linux平台安装MongoDB
10月更文挑战第11天
45 5
|
2月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
97 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
22天前
|
监控 安全 测试技术
构建高效精准测试平台:设计与实现全攻略
在软件开发过程中,精准测试是确保产品质量的关键环节。一个高效、精准的测试平台能够自动化测试流程,提高测试覆盖率,缩短测试周期。本文将分享如何设计和实现一个精准测试平台,从需求分析到技术选型,再到具体的实现步骤。
48 0
|
2月前
|
前端开发 JavaScript 应用服务中间件
linux安装nginx和前端部署vue项目(实际测试react项目也可以)
本文是一篇详细的教程,介绍了如何在Linux系统上安装和配置nginx,以及如何将打包好的前端项目(如Vue或React)上传和部署到服务器上,包括了常见的错误处理方法。
430 0
linux安装nginx和前端部署vue项目(实际测试react项目也可以)