Jump to content

    

Задержка прерывания в uC/OS-II

Здравствуйте.

Никто не измерял задержку (латентность) прерываний в uCOS-е?

По определению:

Задержка прерывания = Максимальное время, которое прерывания запрещены + Время старта ISR

 

Судя по исходникам, очень широко используются длинные критические секции, в которых прерывания запрещены. Это может довольно сильно увеличить время реакции на прерывание.

 

Например, кусок кода из os_core.c:

 

        while (ptcb->OSTCBPrio != OS_TASK_IDLE_PRIO) {     /* Go through all TCBs in TCB list              */

            OS_ENTER_CRITICAL();                          /*ПРЕРЫВАНИЯ ЗАПРЕЩЕНЫ*/
            if (ptcb->OSTCBDly != 0u) {                    /* No, Delayed or waiting for event with TO     */
                ptcb->OSTCBDly--;                          /* Decrement nbr of ticks to end of delay       */
                if (ptcb->OSTCBDly == 0u) {                /* Check for timeout                            */

                    if ((ptcb->OSTCBStat & OS_STAT_PEND_ANY) != OS_STAT_RDY) {
                        ptcb->OSTCBStat  &= (INT8U)~(INT8U)OS_STAT_PEND_ANY;          /* Yes, Clear status flag   */
                        ptcb->OSTCBStatPend = OS_STAT_PEND_TO;                 /* Indicate PEND timeout    */
                    } else {
                        ptcb->OSTCBStatPend = OS_STAT_PEND_OK;
                    }

                    if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) {  /* Is task suspended?       */
                        OSRdyGrp               |= ptcb->OSTCBBitY;             /* No,  Make ready          */
                        OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                    }
                }
            }
            ptcb = ptcb->OSTCBNext;                        /* Point at next TCB in TCB list                */

            OS_EXIT_CRITICAL();                             /*И ТОЛЬКО ТУТ РАЗРЕШАЕМ ПРЕРЫВАНИЯ*/
        }

 

 

Share this post


Link to post
Share on other sites
Судя по исходникам, очень широко используются длинные критические секции, в которых прерывания запрещены. Это может довольно сильно увеличить время реакции на прерывание.

 

Это не запрещение прерываний, а запрещение вытеснения.

Как будет сделано это запрещение зависит от конкретной адаптации RTOS на платформе.

Поэтому этот кусок кода ничего не говорит о латентности именно прерываний.

 

Кстати, не думаете сделать EDF под uCOS?

Share this post


Link to post
Share on other sites

Да, критическая секция - это запрещение вытеснения.

Но для той платформы, для которой я смотрю (PowerPC), да и для многих других, я думаю, это именно запрет прерываний.

Получается, значительный вклад в задержку прерывания вносит как раз время работы с запрещенными прерываниями в критической секции.

Например, в eCos-е такие критические секции сведены к минимуму, как и положено. В высоконадежных ОСРВ (INTEGRITY, ThreadX) при оценке времени реакции на прерывание вообще учитывается время выполнения самой длинной инструкции процессора. А тут такое...

Интересно узнать, может, кто-нибудь делал замеры временных характеристик uCOS-а? Было бы интересно посмотреть. Может, есть какой-то стандартный тест от разработчика ОС (как, например, в eCos-е)?

 

Нет.. EDF пока для uCOS-а я делать не собираюсь, хотя планировщик в uCOS-е мне не особо понравился. Сразу видно, что изначально он создавался для 8-ми и 16-разрядных контроллеров. Для 32-разрядного процессора можно было бы сделать чего-нибудь получше.

 

Share this post


Link to post
Share on other sites
Но для той платформы, для которой я смотрю (PowerPC), да и для многих других, я думаю, это именно запрет прерываний.

 

Интересно узнать, может, кто-нибудь делал замеры временных характеристик uCOS-а? Было бы интересно посмотреть. Может, есть какой-то стандартный тест от разработчика ОС (как, например, в eCos-е)?

 

Для 32-разрядного процессора можно было бы сделать чего-нибудь получше.

 

Я портировал uCOS на разные архитектуры: MSP430, M16, ST10, ARM7, ARM9 ...

Везде находился способ не запрещать полностью прерывания в критических секциях.

Как пример я всегда привожу вот эту разработку с использованием uCOS

Система охраны на MSP430

где при включенных сервисах оси проводилась выборка по прерываниям аудиосигналов и их же генерация с частотой сэмплирования 8 КГц.

Если бы при этом был заметный джиттер в связи с запрещением прерываний, то разборчивые для внешних систем сигналы генерировать не удалось бы с таким сэмплированием.

 

Программ для замеров RTOS конечно есть достаточно.

Легко портируется во эта к примеру:

http://rtos.com/downloads/articles_and_white_papers-1/ (искать под названием Thread-Metric Benchmark Suite)

 

Еще раз скажу, что то как написано в ядре RTOS мало интересно, вся соль в порте. Поэтому хаять uCOS малопродуктивно.

Важно как middleware работает с сервисами RTOS, вообще набор сервисов и как выполнен порт.

Share this post


Link to post
Share on other sites

Спасибо за ссылку. Надо будет эти тесты позапускать. И надо будет еще чего-нибудь погуглить на эту тему.

 

Я портировал uCOS на разные архитектуры: MSP430, M16, ST10, ARM7, ARM9 ...

Везде находился способ не запрещать полностью прерывания в критических секциях.

А не подскажете, как Вы организовывали критические секции?

 

Смотрел порт uCOS под PowerPC с их сайта micrium.com. Там сделано так: сначала сохраняется регистр MachineStateRegister, затем запрещаются прерывания...при выходе из критической секции MSR восстанавливается:

 

#define  OS_CRITICAL_METHOD    3

#define  OS_ENTER_CRITICAL()    cpu_sr = OS_CPU_SR_Save();
#define  OS_EXIT_CRITICAL()     OS_CPU_SR_Restore(cpu_sr);

OS_CPU_SR_Save:

    addis  4, 0, 0xFFFD
    ori    4, 4, 0x7FFF
    mfmsr  3
    and    4, 4, 3                                      /* Clear bits 14 and 16, corresponding to...   */
    mtmsr  4                                            /* ...critical and non-critical interrupts     */
    blr

OS_CPU_SR_Restore:

    mtmsr  3                                            /* Restore the saved MSR                       */
    blr

Пока оставлю так, но возможно, придется поменять по-своему.

Share this post


Link to post
Share on other sites

Интересно, что получится, если заменить конструкцию

 

#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save(); \

OS_CPU_IntDisMeasStart();}

#define OS_EXIT_CRITICAL() {OS_CPU_IntDisMeasStop(); \

OS_CPU_SR_Restore(cpu_sr);}

 

 

на

 

 

#define OS_ENTER_CRITICAL() {cpu_sr = OSSchedLock(); \

OS_CPU_IntDisMeasStart();}

#define OS_EXIT_CRITICAL() {OS_CPU_IntDisMeasStop(); \

OSSchedUnlock(cpu_sr);}

 

 

забыл, конечно,

в самих OSSchedLock и OSSchedUnlock заменить функции OS_ENTER_CRITICAL() и OS_EXIT_CRITICAL() непосредственно на их код

Share this post


Link to post
Share on other sites
Смотрел порт uCOS под PowerPC с их сайта micrium.com. Там сделано так: сначала сохраняется регистр MachineStateRegister, затем запрещаются прерывания...при выходе из критической секции MSR восстанавливается:

Вот Вам более быстрый инлайновый вариант (под GCC), делает то же самое

INLINE_FORCED
DWORD
tn_lock_interrupt(void)
{
DWORD ret, tmp;

asm volatile
(
	"mfmsr		%0;"
       "rlwinm		%1, %0, 0, 17, 15;"
       "mtmsr		%1;"
       : "=r"(ret), "=r" (tmp)
);
//
// Дополнительная инструкция sync не нужна
// если изменяются только флаги разрешения
// прерываний
//
return ret;
}

//
// Восстановление состояния регистра MSR и флага прерываваний
//
#define tn_unlock_interrupt(sr)			\
asm volatile						\
(									\
	"mtmsr	%0;"					\
	: : "r"(sr)						\
)

 

Share this post


Link to post
Share on other sites
Интересно, что получится, если заменить конструкцию

 

#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save(); \

OS_CPU_IntDisMeasStart();}

#define OS_EXIT_CRITICAL() {OS_CPU_IntDisMeasStop(); \

OS_CPU_SR_Restore(cpu_sr);}

 

на

 

#define OS_ENTER_CRITICAL() {cpu_sr = OSSchedLock(); \

OS_CPU_IntDisMeasStart();}

#define OS_EXIT_CRITICAL() {OS_CPU_IntDisMeasStop(); \

OSSchedUnlock(cpu_sr);}

 

Я, конечно, еще только начинаю с uCOS-ом работать, но, по-ходу, в этом случае заведомо планировщик никогда работать не будет, потоки переключаться ни будут:

OSSchedLock инкрементирует переменную OSLockNesting. А теперь если посмотреть функцию OS_Sched(), то там сначала вызывается OS_ENTER_CRITICAL(), а потом проверяется OSLockNesting, и если она равна нулю, то выполняется планирование. То есть OSLockNesting нулю никогда равна не будет, и функция OS_Sched() просто завершит свою работу.

 

 

 

Вот Вам более быстрый инлайновый вариант (под GCC), делает то же самое

 

Спасибо, надо будет так и сделать, быстрее работать будет. Только, может, для единообразия сделать обе функции или оба макроса. Хотя это и не принципиально.

И вообще, в PowerPC через инструкции типа rlwin удобно очень с масками работать. Вот как, кстати, в том же eCos-е прерывания разрешаются/запрещаются:

 

#define HAL_DISABLE_INTERRUPTS(_old_)                   \
    CYG_MACRO_START                                     \
    cyg_uint32 tmp1, tmp2;                              \
    asm volatile (                     \
        "mfmsr  %0;         \n            \
        mr     %2,%0;         \n             \
        li     %1,0;         \n            \
        rlwimi %2,%1,0,16,16;    \n            \
        mtmsr  %2; "                          \
        : "=r"(_old_), "=r" (tmp1), "=r" (tmp2)); \
    CYG_MACRO_END

#define HAL_ENABLE_INTERRUPTS()         \
    CYG_MACRO_START                     \
    cyg_uint32 tmp1, tmp2;              \
    asm volatile (                      \
        "mfmsr  %0;           \n     \
        ori    %1,%1,0x8000;  \n          \
        rlwimi %0,%1,0,16,16; \n          \
        mtmsr  %0;"                        \
        : "=r" (tmp1), "=r" (tmp2));    \
    CYG_MACRO_END

где

#define CYG_MACRO_START do {
#define CYG_MACRO_END   } while (0)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this