0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何选择RTOS?使用R-Rhealstone框架评估

Rice嵌入式开发技术分享 来源:Rice嵌入式 作者:Rice嵌入式 2024-02-20 13:54 次阅读

文章描述基于Rhealstone的系统实时性的测量基准的框架--R-Rhealstone框架。

嵌入式软件设计和集成中,实时多任务操作系统的性能分析是至关重要的,它需要保证应用的时间限制得到满足,即是运行时间不能超过应用的时间限制。为了选择满足用于特定应用的嵌入式系统的一个适当的操作系统,我们需要对操作系统服务进行分析。这些操作系统服务是由形成性能指标的参数确定的,既定的性能指标包括上下文切换时间、任务抢占时间、中断延迟时间、信号量混洗时间、死锁解除时间、信息传输延迟。

关于实时操作系统对性能指标进行分析,是为了选择满足用于特定应用的嵌入式系统的最优的操作系统。

Rhealstone

Rhealstone是系统实时性的测量基准之一,Rhealstone性能基准程序是实时系统的六个关键操作的时间量进行操作,这六个关键操作是:上下文切换时间、任务抢占时间、中断延迟时间、信号量混洗时间、死锁解除时间、信息传输延迟。这六项操作作为Rhealstone的六个组件,每个组件被单独测量。然后将经验结果合并为单一的测量值,即是Rhealstone值。

测量Rhealstone值方式:

序号 说明
方式 1 通用Rhealstone
方式 2 每个组件应用于具体应用程序的特定Rhealstone

Rhealstone性能基准程的缺点:

序号 说明
缺点 1 测量的是平均时间,而不是最坏值
缺点 2 后的结论是加权平均值,没有给出确定权值的依据

R-Rhealstone框架

设计R-Rhealstone框架的目的:为了能让对比的系统实时性的测量的一致性,必须保证同一个环境,解除差异性带来测量干扰,所以R-Rhealstone框架提供了操作系统适配层,统一适配不同操作系统的各个接口,目的可以达到上层调用层次一致。

76c32840-b599-11ee-9b10-92fbcf53809c.png

上下文切换时间

描述:

上下文切换时间也称任务切换时间(task switching time),定义为系统在两个独立的、处于就绪态并且具有相同优先级的任务之间切换所需要的时间。它包括三个部分,即保存当前任务上下文的时间、调度程序选中新任务的时间和恢复新任务上下文的时间。切换所需的时间主要取决于保存任务上下文所用的数据结构以及操作系统采用的调度算法的效率。产生任务切换的原因可以是资源可得,信号量的获取等。任务切换是任一多任务系统中基本效率的测量点,它是同步的,非抢占的,实时控制软件实现了一种基于同等优先级任务的时间片轮转算法。影响任务切换的因素有:主机CPU的结构,指令集以及CPU特性。

任务切换过程增加了应用程序的额外负荷。CPU的内部寄存器越多,额外负荷就越重。任务切换所需要的时间取决于CPU有多少寄存器要入栈。实时内核的性能不应该以每秒钟能做多少次任务切换来评价,RTOS中通常是1微秒左右。

流程:

原理:创建两个同等优先级的任务,两个任务相互切换多次,最后求平均值。

注意:①需要减去多次切换的循环时间(loop_overhead);②需要减去主动让CPU执行时间(dir_overhead)

时间计算公式:

total_time:多次上下文切换总时间

loop_overhead:多次切换的循环时间

iterations:切换的次数

dir_overhead:调用让出CPU接口的时间

76c6da1c-b599-11ee-9b10-92fbcf53809c.png

代码:

#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< RST_BENCHMARKS_COUNT; count1++)
    {
        rst_task_yield();
    }
    rst_task_delete(NULL);
}

static void rst_task2_func(void *arg)
{
    /* All overhead accounted for now, we can begin benchmark */
    rst_benchmark_time_init();

    for(count2 = 0; count2 < RST_BENCHMARKS_COUNT; count2++)
    {
        rst_task_yield();
    }

    telapsed = rst_benchmark_time_read();

    RST_PRINT_TIME(
        "R-Rhealstone: task switch time", 
        telapsed,                       /* Total time of all benchmarks */
        (RST_BENCHMARKS_COUNT * 2) - 1, /* ( BENCHMARKS * 2 ) - 1 total benchmarks */
        loop_overhead,                  /* Overhead of loop */
        dir_overhead                    /* Overhead of rst_task_yield directive */
    );
    rst_task_delete(NULL);
}

rst_status rst_task_switch_init(void)
{
    /* find overhead of routine (no task switches) */
    rst_benchmark_time_init();
    for(count1 = 0; count1 < RST_BENCHMARKS_COUNT; count1 ++)
    {
    }
    for(count1 = 0; count1 < RST_BENCHMARKS_COUNT; count1 ++)
    {
    }
    loop_overhead = rst_benchmark_time_read();

    /* find overhead of rtems_task_wake_after call (no task switches) */
    rst_benchmark_time_init();
    rst_task_yield();
    dir_overhead = rst_benchmark_time_read();;

    rst_task_create(&rst_task1, rst_task1_func, NULL, &rst_task1_attr);
    if(rst_task1 == NULL)
    {
        RST_LOGE("RST: task1 create failed");
        return RST_ERROR;
    }

    return RST_OK;
}

任务抢占时间

描述:

抢占时间即系统将控制权从低优先级的任务转移到高优先级任务所花费的时间。为了对任务进行抢占,系统必须首先识别引起高优先级任务就绪的事件,比较两个任务的优先级,最后进行任务的切换,所以抢占时间中包括了任务切换时间。

它和任务切换有些类似,但是抢占时间通常花费时间更长。这是因为执行中首先要确认唤醒事件,并评估正在运行的任务和请求运行的任务的优先级高低,然后才决定是否切换任务。实质上,所有的多处理任务可以在执行期间动态分配优先级,所以,抢占时间也是衡量实时性能的重要指标。

流程:

原理:创建两个任务,任务1优先级比任务2优先级低,两个任务进行抢占多次,最后求平均值。

注意:①需要减去多次任务抢占的循环时间(loop_overhead);②需要减去挂起任务所需要的时间(dir_overhead)

时间计算公式:

total_time:多次任务抢占总时间

loop_overhead:多次任务抢占的循环时间

iterations:任务抢占的次数

switch_overhead:挂起任务所需要的时间

76caa1b0-b599-11ee-9b10-92fbcf53809c.png

代码:

#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< RST_BENCHMARKS_COUNT; count++)
    {
        rst_task_resume(rst_task2);     /* Awaken task2, preemption occurs */
    }
    rst_task_delete(NULL);
}

static void rst_task2_func(void *arg)
{
    /* Find overhead of task switch back to task1 (not a preemption) */
    rst_benchmark_time_init();
    rst_task_suspend(rst_task2);

    /* Benchmark code */
    for(; count < RST_BENCHMARKS_COUNT - 1;)
    {
        rst_task_suspend(rst_task2);
    }

    telapsed = rst_benchmark_time_read();

    RST_PRINT_TIME(
        "R-Rhealstone: task preempt time", 
        telapsed,                       /* Total time of all benchmarks */
        RST_BENCHMARKS_COUNT - 1,       /* BENCHMARKS - 1 total benchmarks */
        loop_overhead,                  /* Overhead of loop */
        switch_overhead                 /* Overhead of task switch back to task1 */
    );
    rst_task_delete(NULL);
}

rst_status rst_task_preempt_init(void)
{
    /* Find loop overhead */
    rst_benchmark_time_init();
    for(count = 0; count < ((RST_BENCHMARKS_COUNT * 2) - 1); count++)
    {
    }
    loop_overhead = rst_benchmark_time_read();

    rst_task_create(&rst_task1, rst_task1_func, NULL, &rst_task1_attr);
    if(rst_task1 == NULL)
    {
        RST_LOGE("RST: task1 create failed");
        return RST_ERROR;
    }

    return RST_OK;
}

中断延迟时间

描述:

中断延迟时间是指从接收到中断信号到操作系统做出响应,并完成进入中断服务例程所需要的时间。多任务操作系统中,中断处理首先进入一个中断服务的总控程序,然后才进入驱动程序的ISR。

中断延迟时间=最大关中断时间+硬件开始处理中断到开始执行中断服务例程第一条指令之间的时间。

硬件开始处理中断到开始执行中断服务例程的第一条指令之间的时间由硬件决定,所以,中断延迟时间的长短主要取决于最大关中断的时间。硬实时操作系统的关中断时间通常是几微秒,而Linux最坏可达几毫秒。

流程:

原理:创建一个任务,任务执行主动触发中断,执行完中断服务程序返回,统计其时间。

注意:①需要减去读取时间接口的耗时时间(timer_overhead);

时间计算公式:

isr_enter_time:多次任务抢占总时间

iterations:任务抢占的次数

timer_overhead:读取时间接口的耗时时间

76d91538-b599-11ee-9b10-92fbcf53809c.png

代码:

#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:切换的时间

76dc72dc-b599-11ee-9b10-92fbcf53809c.png

代码:

#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< RST_BENCHMARKS_COUNT; ) {
        if ( sem_exe == 1 )
        {
            rst_sem_lock(rst_sem, (rst_time_t)RST_WAIT_FOREVER);
            rst_task_yield();
            rst_sem_unlock(rst_sem);
            rst_task_yield();
        }
    }
    rst_task_delete(NULL);
}

static void rst_task2_func(void *arg)
{
    /* Benchmark code */
    rst_benchmark_time_init();
    for(count = 0; count < RST_BENCHMARKS_COUNT; count++)
    {
        if(sem_exe == 1)
        {
            rst_sem_lock(rst_sem, (rst_time_t)RST_WAIT_FOREVER);
            rst_task_yield();
            rst_sem_unlock(rst_sem);
            rst_task_yield();
        }
    }
    telapsed = rst_benchmark_time_read();

    if(sem_exe == 0)
    {
        switch_overhead = telapsed;
    }
    else
    {
        RST_PRINT_TIME(
            "R-Rhealstone: senaphore shuffle time", 
            telapsed,                       /* Total time of all benchmarks */
            (RST_BENCHMARKS_COUNT * 2),     /* Total number of times deadlock broken*/
            switch_overhead,                /* Overhead of loop and task switches */
            0
        );
    }
    rst_task_delete(NULL);
}

rst_status rst_semaphore_shuffle_init(void)
{
    rst_sem = rst_sem_create(1);
    if(rst_sem == NULL)
    {
        RST_LOGE("RST: sem create failed");
        return RST_ERROR;
    }

__RESTART:
    sem_exe = !sem_exe;

    /* Get time of benchmark with no semaphore shuffling */
    rst_task_create(&rst_task1, rst_task1_func, NULL, &rst_task1_attr);
    if(rst_task1 == NULL)
    {
        RST_LOGE("RST: task1 create failed");
        rst_sem_delete(rst_sem);
        return RST_ERROR;
    }

    /* Get time of benchmark with semaphore shuffling */
    if(sem_exe == 0)
    {
        goto __RESTART;
    }

    return RST_OK;
}

死锁解除时间

描述:

死锁解除时间(deadlock breaking time),即系统解开处于死锁状态的多个任务所需花费的时间。死锁解除时间反映了RTOS解决死锁的算法的效率。

流程:

原理:创建一个信号量和三个任务,优先级排序:任务1 < 任务2 < 任务3。代码需要执行两次,第一次信号量不介入调度,计算任务3切换到任务2,任务2切换到任务1得时间(即从高优先级切换到低优先级得时间),第二次多次循环,信号量接入调度,任务3死锁,任务2唤醒任务1,任务1解除死锁,通过统计多次,求平均值。

注意:①需要减去任务切换的时间(switch_overhead);

时间计算公式:

telapsed:多次死锁解除总时间

iterations:死锁解除的次数

switch_overhead:任务切换的时间

lock_overhead:调用信号量持有接口所需要得时间

76e87b9a-b599-11ee-9b10-92fbcf53809c.png

代码:

#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< RST_BENCHMARKS_COUNT; count++)
    {
        if(sem_exe == 1)
        {
            /* Block on call */
            rst_sem_lock(rst_sem, (rst_time_t)RST_WAIT_FOREVER);

            /* Release semaphore immediately after obtaining it */
            rst_sem_unlock(rst_sem);
        }
        /* Suspend self, go to task2 */
        rst_task_suspend(rst_task1);
    }
    telapsed = rst_benchmark_time_read();

    if(sem_exe == 0)
    {
        switch_overhead = telapsed;
    }
    else
    {
        RST_PRINT_TIME(
            "R-Rhealstone: deadlock break time", 
            telapsed,                       /* Total time of all benchmarks */
            RST_BENCHMARKS_COUNT,           /* Total number of times deadlock broken*/
            switch_overhead,                /* Overhead of loop and task switches */
            lock_overhead
        );
    }
    rst_task_delete(NULL);
}

static void rst_task2_func(void *arg)
{
    /* Start up task1, get preempted */
    rst_task_create(&rst_task1, rst_task1_func, NULL, &rst_task1_attr);
    if(rst_task1 == NULL)
    {
        RST_LOGE("RST: task1 create failed");
        rst_task_delete(NULL);
        return;
    }

    /* Benchmark code */
    for( ; count < RST_BENCHMARKS_COUNT; )
    {
        /* Suspend self, go to task1 */
        rst_task_suspend(rst_task2);

        /* Wake up task1, get preempted */
        rst_task_resume(rst_task1);
    }
    rst_task_delete(NULL);
}

static void rst_task3_func(void *arg)
{
    if(sem_exe == 1)
    {
        /* Low priority task holds mutex */
        rst_sem_lock(rst_sem, (rst_time_t)RST_WAIT_FOREVER);
    }

    /* Start up task2, get preempted */
    rst_task_create(&rst_task2, rst_task2_func, NULL, &rst_task2_attr);
    if(rst_task2 == NULL)
    {
        RST_LOGE("RST: task2 create failed");
        rst_task_delete(NULL);
        return;
    }

    for( ; count < RST_BENCHMARKS_COUNT; )
    {
        if(sem_exe == 1)
        {
            /* Preempted by task1 upon release */
            rst_sem_unlock(rst_sem);

            /* Prepare for next Benchmark */
            rst_sem_lock(rst_sem, (rst_time_t)RST_WAIT_FOREVER);
        }
        /* Wake up task2, get preempted */
        rst_task_resume(rst_task2);
    }
    rst_task_delete(NULL);
}

rst_status rst_deadlock_break_init(void)
{
    rst_sem = rst_sem_create(1);
    if(rst_sem == NULL)
    {
        RST_LOGE("RST: sem create failed");
        return RST_ERROR;
    }

    /* find overhead of obtaining semaphore */
    rst_benchmark_time_init();
    rst_sem_lock(rst_sem, (rst_time_t)RST_WAIT_FOREVER);
    lock_overhead = rst_benchmark_time_read();
    rst_sem_unlock(rst_sem);

__RESTART:
    sem_exe = !sem_exe;

    /* Get time of benchmark with no semaphores involved, i.e. find overhead */
    rst_task_create(&rst_task3, rst_task3_func, NULL, &rst_task3_attr);
    if(rst_task3 == NULL)
    {
        RST_LOGE("RST: task3 create failed");
        rst_sem_delete(rst_sem);
        return RST_ERROR;
    }

    /* Get time of benchmark with semaphores */
    if(sem_exe == 0)
    {
        goto __RESTART;
    }

    rst_sem_delete(rst_sem);
    return RST_OK;
}

信息传输延迟

描述:

信息传输延迟(datagram throuShput time),指一个任务通过调用RTOS的消息队列,把数据传送到另一个任务去时,每秒可以传送的字节数。

流程:

原理:创建一个消息队列和两个任务,优先级排序:任务1 < 任务2。任务1负责发送数据,任务2负责接收数据,执行多次,求平均值

注意:①需要减去调用消息队列接收函数的时间(receive_overhead);

时间计算公式:

telapsed:多次信息传输总时间

iterations:死锁解除的次数

loop_overhead:多次循环的时间

receive_overhead:调用消息队列接收函数的时间

76ec1034-b599-11ee-9b10-92fbcf53809c.png

代码:

#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< RST_BENCHMARKS_COUNT; count++)
    {
        rst_queue_send(rst_queue, 
                       (const void *)queue_buff, 
                       (uint32_t)sizeof(queue_buff), 
                       (rst_time_t)RST_WAIT_FOREVER);
    }
    rst_task_delete(NULL);
}

static void rst_task2_func(void *arg)
{
    /* find recieve overhead - no preempt or task switch */
    rst_benchmark_time_init();
    rst_queue_recv(rst_queue, (void *)queue_buff, 
                   (uint32_t)sizeof(queue_buff));
    receive_overhead = rst_benchmark_time_read();

    /* Benchmark code */
    rst_benchmark_time_init();
    for(count = 0; count < RST_BENCHMARKS_COUNT - 1; count++)
    {
        rst_queue_recv(rst_queue, (void *)queue_buff, 
                       (uint32_t)sizeof(queue_buff));
    }
    telapsed = rst_benchmark_time_read();

    RST_PRINT_TIME(
        "R-Rhealstone: message latency time", 
        telapsed,                       /* Total time of all benchmarks */
        RST_BENCHMARKS_COUNT - 1,       /* BENCHMARKS - 1 total benchmarks */
        loop_overhead,                  /* Overhead of loop */
        receive_overhead                /* Overhead of recieve call and task switch */
    );
    rst_task_delete(NULL);
}

rst_status rst_message_latency_init(void)
{
    rst_queue = rst_queue_create(sizeof(queue_buff), 1);
    if(rst_queue == NULL)
    {
        RST_LOGE("RST: queue create failed");
        return RST_ERROR;
    }

    rst_benchmark_time_init();
    for(count = 0; count < (RST_BENCHMARKS_COUNT - 1); count++)
    {
    }
    loop_overhead = rst_benchmark_time_read();

    rst_task_create(&rst_task1, rst_task1_func, NULL, &rst_task1_attr);
    if(rst_task1 == NULL)
    {
        RST_LOGE("RST: task1 create failed");
        rst_queue_delete(rst_queue);
        return RST_ERROR;
    }

    return RST_OK;
}

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倍。

开源链接

链接路径:https://github.com/RiceChen0/r-rhealstone.git

说明:该框架目前已经适配作为RT-Thread的软件包,可以通过软件包体验其功能

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    5082

    文章

    19104

    浏览量

    304815
  • 框架
    +关注

    关注

    0

    文章

    403

    浏览量

    17475
  • RTOS
    +关注

    关注

    22

    文章

    811

    浏览量

    119595
收藏 人收藏

    评论

    相关推荐

    R-Rhealstone框架使用教程

    本篇文章描述基于Rhealstone的系统实时性的测量基准的框架--R-Rhealstone框架
    的头像 发表于 01-18 10:54 1533次阅读
    <b class='flag-5'>R-Rhealstone</b><b class='flag-5'>框架</b>使用教程

    请问使用ADA4927-1评估R5、R6、R7、R8、R9、R10的值怎么选择

    请教大家一个问题,在使用ADA4927-1评估板时,R5、R6、R7、R8、R9、
    发表于 10-09 18:03

    嵌入式设计中,如何评估最适合应用的 RTOS

    RTOS 可供开发人员使用,从开源系统到经认证的商业 RTOS。那么,该如何选择 RTOS 并开始使用呢?如何评估最适合应用的
    发表于 07-26 14:15

    该如何选择RTOS?如何去使用RTOS呢?

    选择RTOS需要考虑哪些因素?如何评估最适合应用的RTOS?STMicroelectronics和Renesas是什么?
    发表于 06-28 06:03

    RTOS框架下使用ROSSerial

    STM32以极优的性价比提供了可以运行RTOS的硬件平台,使用RTOS已经不是一件奢侈的事情了,如果能在RTOS框架下使用ROSSerial应该是编写嵌入式控制程序的福音,故做此尝试。
    发表于 03-02 06:47

    选择RTOS时要看哪些参数?

    选择RTOS时,要看哪些参数
    发表于 09-21 07:42

    选择实时操作系统(RTOS)的要点详解

      对许多嵌入式项目来说,系统设计师都倾向于选择实时操作系统(RTOS)。但RTOS总是必要的吗?答案是取决于具体
    发表于 10-28 10:41 9204次阅读
    <b class='flag-5'>选择</b>实时操作系统(<b class='flag-5'>RTOS</b>)的要点详解

    如何选择适合自己的开源RTOS

    选择适合自己的开源RTOS
    的头像 发表于 03-12 11:44 2742次阅读

    详解选择RTOS的要点

    大多数程序员不熟悉RTOS的限制和要求。大多数人通常因其性能选择RTOS。大多数RTOS产品代码少和速度快,现在RTOS还提升了一致性。
    的头像 发表于 04-05 09:44 1667次阅读

    RTOS如何使用及如何选择

      许多项目把自己画到了一个角落,改变 RTOS 或系统设计不再是可行的选择;编写了太多代码以允许改变方向。无论好坏,该项目都被它选择的任何东西所困扰。这对豆类柜台和其他所有人来说都是个坏消息。
    发表于 06-29 09:08 1343次阅读

    如何选择正确的RTOS

      在开发医疗设备时,选择 RTOS 是一个涉及生死攸关的复杂决定。仔细关注 RTOS 产品的技术特性及其在生命关键设备实施中的跟踪记录是唯一安全的方法。
    发表于 08-11 14:57 1043次阅读

    在单片机中使用的RTOS代码框架

    在这次开发中,也是遇到了很多的问题,主要的感想是关于代码的框架。在单片机开发中,特别是使用了RTOS的时候,一个良好的代码框架真的是相当的必要的。
    的头像 发表于 02-10 14:21 1120次阅读

    详解选择RTOS的要点

    对于许多嵌入式项目来说,在采用非实时操作系统(non-RTOS)的任何场合,也都可采用RTOS。但是,要找到一款具有完全相同应用编程接口(API)的匹配RTOS就相当困难了。因此,许多传统的操作系统
    的头像 发表于 03-31 15:20 858次阅读

    选择实时操作系统(RTOS)的要点详解

    对许多嵌入式项目来说,系统设计师都倾向于选择实时操作系统(RTOS)。但RTOS总是必要的吗?答案是取决于具体的应用,因此了解我们要达到什么目标是决定RTOS是必要的还是花瓶的关键。
    发表于 05-30 09:45 1051次阅读

    何时选择裸机?何时选择RTOS?何时选择GPOS?

    在每个开发项目的初期,你都必须选择软件开发的基础。虽然有很多选择,但它们通常分为三类:裸机、实时操作系统(RTOS)或通用操作系统(GPOS)。
    的头像 发表于 02-27 11:42 1146次阅读