shaorei 发表于 2012-7-8 09:33:51

rt-thread系统开销将近18ms?

本帖最后由 shaorei 于 2012-7-8 09:38 编辑

小弟用Tim2产生20ms的定时,在定时ISR中发送事件给线程,然后在一个高优先级的线程中等待事件,得到事件后做某件耗时任务。
调试中发现20ms周期留给线程做任务的时间仅有2ms左右?
while (1)
    {
      if (rt_event_recv(&rf_event_20ms, (1<<0) ,
            RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e) == RT_EOK)//20ms event
      {

                //rt_kprintf(".");
                delay_ms(2);
      }
    }
当delay大于2ms时,低优先级的线程根本没机会得到时间片,tshell命令行都不显示,说明高优先级的线程根本没有空闲时间让给tshell线程执行,
OMG,开销不会这么大吧,哪里弄错了吧。


application.c:
--------------------------------------------
#include <board.h>
#include <rtthread.h>
#include "stm32f10x_conf.h"



struct rt_event rf_event_20ms;      //事件控制块




void delay_20ns()
{
    __no_operation();
}

void delay_ms(uint8_t ms)
{
    for (int i = 0; i<50000*ms; i++)
    {
      __no_operation();
    }
}




ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rf_stack[ 0x400 ];
static struct rt_thread rf_thread;


static void rf_thread_entry(void* parameter)
{
    rt_uint32_t e;

    while (1)
    {
      if (rt_event_recv(&rf_event_20ms, (1<<0) ,
            RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e) == RT_EOK)//20ms event
      {

                //rt_kprintf(".");
                delay_ms(2);
      }
    }
}

void rf_thread_setup()
{
    rt_err_t result;

    rt_event_init(&rf_event_20ms, "rf_ev", RT_IPC_FLAG_FIFO);


    rt_kprintf("RF init done.\nstarting rf thread...\n");
    /*---- init rf thread---- */
    result = rt_thread_init(&rf_thread,
                            "rf",
                            rf_thread_entry, RT_NULL,
                            (rt_uint8_t*)&rf_stack, sizeof(rf_stack),
                            0, 5);    //优先级为0,最高级别
    if (result == RT_EOK)
    {
      rt_thread_startup(&rf_thread);
    }
   
}


int rt_application_init()
{
    TIM_TimeBaseInitTypeDefTIM_TimeBaseStructure;
   
   
    /* TIM2 clock enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
   

    // ---- init tim2 ----
    //定时周期=((1+TIM_Prescaler )/56M)*(1+TIM_Period)=20ms

    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = 20000;
    TIM_TimeBaseStructure.TIM_Prescaler = 55;
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    /* Prescaler configuration */
    TIM_PrescalerConfig(TIM2, TIM_TimeBaseStructure.TIM_Prescaler, TIM_PSCReloadMode_Immediate);

    TIM_ARRPreloadConfig(TIM2, ENABLE);

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

    /* TIM2 enable counter */
    TIM_Cmd(TIM2, ENABLE);

    rt_kprintf("timer2 init done.\n");
   
   
    ///////////////////////////////////////////////////

    rf_thread_setup();

    return 0;
}


stm32f10x_it.c:
--------------------------------------------
void TIM2_IRQHandler(void)
{
    rt_interrupt_enter();

    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != 0)
    {
      /* Clear TIM2 Capture Compare1 interrupt pending bit*/
      TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

            rt_event_send(&rf_event_20ms, (1<<0));
    }

    rt_interrupt_leave();
   
}

rtconfig.h
------------------------------------------------
/* RT-Thread config file */
#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__

/* RT_NAME_MAX*/
#define RT_NAME_MAX        8

/* RT_ALIGN_SIZE*/
#define RT_ALIGN_SIZE        4

/* PRIORITY_MAX */
#define RT_THREAD_PRIORITY_MAX        32

/* Tick per Second */
#define RT_TICK_PER_SECOND        100

/* SECTION: RT_DEBUG */
/* Thread Debug */
//#define RT_DEBUG
//#define RT_THREAD_DEBUG

//#define RT_USING_OVERFLOW_CHECK

/* Using Hook */
//#define RT_USING_HOOK

/* Using Software Timer */
#define RT_USING_TIMER_SOFT
#define RT_TIMER_THREAD_PRIO                30
#define RT_TIMER_THREAD_STACK_SIZE        0x100
#define RT_TIMER_TICK_PER_SECOND        100

/* SECTION: IPC */
/* Using Semaphore*/
#define RT_USING_SEMAPHORE

/* Using Mutex */
//#define RT_USING_MUTEX

/* Using Event */
#define RT_USING_EVENT

/* Using MailBox */
#define RT_USING_MAILBOX

/* Using Message Queue */
//#define RT_USING_MESSAGEQUEUE

/* SECTION: Memory Management */
/* Using Memory Pool Management*/
#define RT_USING_MEMPOOL

/* Using Dynamic Heap Management */
#define RT_USING_HEAP

/* Using Small MM */
#define RT_USING_SMALL_MEM

/* SECTION: Device System */
/* Using Device System */
#define RT_USING_DEVICE
#define RT_USING_UART1

/* SECTION: Console options */
#define RT_USING_CONSOLE
/* the buffer size of console*/
#define RT_CONSOLEBUF_SIZE        128

/* SECTION: finsh, a C-Express shell */
#define RT_USING_FINSH
#define FINSH_THREAD_STACK_SIZE 0x200
/* Using symbol table */
#define FINSH_USING_SYMTAB
#define FINSH_USING_DESCRIPTION

/* SECTION: device filesystem */
/* #define RT_USING_DFS */

//#define RT_USING_DFS_ELMFAT
//#define RT_DFS_ELM_WORD_ACCESS
///* Reentrancy (thread safe) of the FatFs module.*/
//#define RT_DFS_ELM_REENTRANT
///* Number of volumes (logical drives) to be used. */
//#define RT_DFS_ELM_DRIVES                        2
///* #define RT_DFS_ELM_USE_LFN                        1 */
//#define RT_DFS_ELM_MAX_LFN                        255
///* Maximum sector size to be handled. */
//#define RT_DFS_ELM_MAX_SECTOR_SIZE512

/* the max number of mounted filesystem */
//#define DFS_FILESYSTEMS_MAX                        2
///* the max number of opened files                 */
//#define DFS_FD_MAX                                        4

/* SECTION: lwip, a lighwight TCP/IP protocol stack */
/* #define RT_USING_LWIP */
/* LwIP uses RT-Thread Memory Management */
//#define RT_LWIP_USING_RT_MEM
///* Enable ICMP protocol*/
//#define RT_LWIP_ICMP
///* Enable UDP protocol*/
//#define RT_LWIP_UDP
///* Enable TCP protocol*/
//#define RT_LWIP_TCP
///* Enable DNS */
//#define RT_LWIP_DNS
//
///* the number of simulatenously active TCP connections*/
//#define RT_LWIP_TCP_PCB_NUM        5

/* Using DHCP */
/* #define RT_LWIP_DHCP */

/* ip address of target*/
//#define RT_LWIP_IPADDR0        192
//#define RT_LWIP_IPADDR1        168
//#define RT_LWIP_IPADDR2        1
//#define RT_LWIP_IPADDR3        30
//
///* gateway address of target*/
//#define RT_LWIP_GWADDR0        192
//#define RT_LWIP_GWADDR1        168
//#define RT_LWIP_GWADDR2        1
//#define RT_LWIP_GWADDR3        1
//
///* mask address of target*/
//#define RT_LWIP_MSKADDR0        255
//#define RT_LWIP_MSKADDR1        255
//#define RT_LWIP_MSKADDR2        255
//#define RT_LWIP_MSKADDR3        0
//
///* tcp thread options */
//#define RT_LWIP_TCPTHREAD_PRIORITY                12
//#define RT_LWIP_TCPTHREAD_MBOX_SIZE                10
//#define RT_LWIP_TCPTHREAD_STACKSIZE                1024
//
///* ethernet if thread options */
//#define RT_LWIP_ETHTHREAD_PRIORITY                15
//#define RT_LWIP_ETHTHREAD_MBOX_SIZE                10
//#define RT_LWIP_ETHTHREAD_STACKSIZE                512

/* TCP sender buffer space */
//#define RT_LWIP_TCP_SND_BUF        8192
/* TCP receive window. */
//#define RT_LWIP_TCP_WND                8192

/* SECTION: RT-Thread/GUI */
/* #define RT_USING_RTGUI */

/* name length of RTGUI object */
//#define RTGUI_NAME_MAX                12
/* support 16 weight font */
//#define RTGUI_USING_FONT16
/* support Chinese font */
//#define RTGUI_USING_FONTHZ
/* use DFS as file interface */
//#define RTGUI_USING_DFS_FILERW
/* use font file as Chinese font */
//#define RTGUI_USING_HZ_FILE
/* use Chinese bitmap font */
//#define RTGUI_USING_HZ_BMP
/* use small size in RTGUI */
//#define RTGUI_USING_SMALL_SIZE
/* use mouse cursor */
/* #define RTGUI_USING_MOUSE_CURSOR */
/* default font size in RTGUI */
//#define RTGUI_DEFAULT_FONT_SIZE        16

/* image support */
/* #define RTGUI_IMAGE_XPM */
/* #define RTGUI_IMAGE_BMP */

#endif

gzhuli 发表于 2012-7-8 09:47:31

RT-Thread本来就是低优先级线程不能抢占高优先级的,你用for循环做delay,低优先级线程根本没机会得到CPU。

shaorei 发表于 2012-7-8 09:51:22

gzhuli 发表于 2012-7-8 09:47 static/image/common/back.gif
RT-Thread本来就是低优先级线程不能抢占高优先级的,你用for循环做delay,低优先级线程根本没机会得到CPU。 ...

谢谢回复,rt_event_recv如果获取不到事件,是会挂起线程吧?低优先级线程应该有机会获得时间片。

gzhuli 发表于 2012-7-8 09:59:16

50000*ms,你确认你的delay_ms是精确1ms?

shaorei 发表于 2012-7-8 10:10:35

gzhuli 发表于 2012-7-8 09:59 static/image/common/back.gif
50000*ms,你确认你的delay_ms是精确1ms?

查了一下汇编,这个delay确实不准。
感谢~

tiancaigao7 发表于 2012-7-8 10:40:30

关键是相差多少?RTT的开销应该是us级别的,不会是ms级别的。

shaorei 发表于 2012-7-8 10:58:21

tiancaigao7 发表于 2012-7-8 10:40 static/image/common/back.gif
关键是相差多少?RTT的开销应该是us级别的,不会是ms级别的。

在不优化的情况下汇编中delay_ms每一次循环是7条指令,其中有多cycle指令,具体没去细算了,暂且假设7条均为单cycle指令,我将delay_ms改成
void delay_ms(uint8_t ms)
{
    for (int i = 0; i<7142*ms; i++)
    {
      __no_operation();
    }
}
20ms大概有16ms是可以给线程做任务,当然这样算还是太粗了。

delay_ms的汇编,哪位懂汇编的可以算下具体是多少个cycle

aozima 发表于 2012-7-8 11:12:16

都RTOS了,除了几us以下,或是ns级别的delay。
谁还使用 delay_ms 就应该拉出去TJJTDS。

zxq6 发表于 2012-7-8 11:13:30

楼上正解,

gzhuli 发表于 2012-7-8 11:19:31

本帖最后由 gzhuli 于 2012-7-8 11:20 编辑

循环主体指令周期数:
NOP: 1
ADDS: 1
UXTB: 1
MOVW: 1
MUL: 1
CMP: 1
BLT.N: 3

共9个CPU周期,56MHz主频下约161ns。

BTW: 你没开优化,开了应该会是6个周期。

gzhuli 发表于 2012-7-8 11:25:29

aozima 发表于 2012-7-8 11:12 static/image/common/back.gif
都RTOS了,除了几us以下,或是ns级别的delay。
谁还使用 delay_ms 就应该拉出去TJJTDS。 ...

我觉得楼主只是想用delay_ms来模拟“某件耗时任务”场景而已,问题是delay_ms比预期慢了9倍,刚好就是2ms * 9 = 18ms...

其实楼主的遇到的问题是低优先级任务无法抢占高优先级任务,本来就是这样的,所以解决办法只能是把耗时任务的优先级降低,把需要实时响应的任务优先级提高。

shaorei 发表于 2012-7-8 11:34:12

gzhuli 发表于 2012-7-8 11:25 static/image/common/back.gif
我觉得楼主只是想用delay_ms来模拟“某件耗时任务”场景而已,问题是delay_ms比预期慢了9倍,刚好就是2ms ...

ls说得对,delay_ms只是模拟某任务,调试过程中发现实时性达不到要求,所以在排查哪里耗时。

shaorei 发表于 2012-7-8 11:41:04

gzhuli 发表于 2012-7-8 11:19 static/image/common/back.gif
循环主体指令周期数:
NOP: 1
ADDS: 1


牛!懂汇编的人都是牛人!
161ns*7142*16 = 18.4ms
这还是粗算,其中还有一些跳转指令也是花时间的,所以系统开销应该在1ms以下。
看来怀疑OS是无谓的。

shaorei 发表于 2012-7-8 11:43:19

gzhuli 发表于 2012-7-8 11:25 static/image/common/back.gif
我觉得楼主只是想用delay_ms来模拟“某件耗时任务”场景而已,问题是delay_ms比预期慢了9倍,刚好就是2ms ...

要命的是最耗时的任务是最重要的任务。。。。
得好好优化一下任务实现了,感谢帮忙定位!!!

aozima 发表于 2012-7-8 12:06:04

最耗时的任务是最重要的任务
常见的应用情景是数据采集+处理。
优先级高的应该是数据采集,甚至简单的可以直接读取的数据采集可以放在中断里面处理。
然后再是数据运算,这部分虽然重要,但因为运算量大,优先级反而应该低一些。
此时应该把一些执行可以确定的控制类的操作优先级高于数据运算,这样才能兼得。

这样可以对控制操作快速响应,除了有数据到来或是有用户操作,所有CPU都在进行数据运算。
如果这样还是运算不过来,那只能说明CPU没法满足要求。

要注意的是这里的运算操作可以降低优先级是指虽然数据运算很重要,却不紧急,只要能处理完,时间上延迟一些也关系不大。
如果数据运算很重要,也很紧急,那就只能详细测出每个步骤的具体时间再做合理安排了。

shaorei 发表于 2012-7-8 13:59:28

aozima 发表于 2012-7-8 12:06 static/image/common/back.gif
常见的应用情景是数据采集+处理。
优先级高的应该是数据采集,甚至简单的可以直接读取的数据采集可以放在 ...

多谢指点。

tiancaigao7 发表于 2012-7-8 14:58:24

gzhuli 发表于 2012-7-8 11:25 static/image/common/back.gif
我觉得楼主只是想用delay_ms来模拟“某件耗时任务”场景而已,问题是delay_ms比预期慢了9倍,刚好就是2ms ...

楼主的意思很清楚,不过按照这样说,rt_event_recv(&rf_event_20ms, (1<<0) ,
            RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e) == RT_EOK)这条语句执行需要花2ms这个貌似也有点儿长。没有精确的计算过这个函数到底执行需要花多长的时间,但是2ms在56M主频的系统上可是一个相当长的时间了。

aozima 发表于 2012-7-8 17:10:49

本帖最后由 aozima 于 2012-7-8 17:14 编辑


rt_event_recv(&rf_event_20ms, (1<<0) ,
            RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR,
            RT_WAITING_FOREVER, &e) == RT_EOK)
这条语句执行需要花2ms这个貌似也有点儿长
请注意这里是:RT_WAITING_FOREVER

所以,你需要测量的时间是从 准备执行rt_event_send之前 到 rt_event_recv 返回之后 的时间

注意: 测试时,执行rt_event_send之前 ,rt_event_recv已经执行过了,但因为没有收到所以处于等待状态。
当然,也可以测试一下,先 rt_event_send ,然后再 rt_event_recv,当系统任务很繁重时,需要根据这些时间去计算任务的分配。
页: [1]
查看完整版本: rt-thread系统开销将近18ms?