реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Уменьшение минимального кол-ва стека, TNKernel :-)
DASM
сообщение Mar 29 2007, 06:18
Сообщение #1


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Боюсь уже автора задолбать, поэтому спрашиваю у всех.
Есть такая штука.. tn_switch_context
Там такой код
Код
tn_sw_restore
        ldmfd  sp!, {r0}
        ldmfd  sp!, {r1}
        msr    CPSR_cxsf, r1; с этой точки прерывания разрешены ! Комментарий мой
        msr    SPSR_cxsf, r0

        mrs    r4, CPSR
        bic    r4, r4, #NOINT
        msr    CPSR_c, r4

        ldmfd  sp!, {r0-r12,lr,pc}

То есть стек задачи еще не развернут, прерывания разрешены. Наступление прерывания, требующего переключения контекста в нем затребует у этой задачи еще 15*4=60 байт стека. (вернее надо будет 68 байт, но 8 мы уже отыграли назад) Вот дальше у меня сомнения - сколько раз такое может произойти...
В реалии раза 3-4 я точно наблюдаю - хорошо видно по использованию стека. Как уменьшить тоже понятно - перенести восстановление CPSR после развертывания большей части стека через ldmfd sp!, {r0-r12,lr,pc}.
Но вот по идее то все равно, сколько раз такое может произойти - вобщем-то определить невозможно, а значит и минимальный требуемый стек для потока должен стремиться к бесконечности ?
Замена вышепреведенного кода на вот такой (жутко наивный, но все же)
Код
     ldmfd  sp!, {r0}        
        ldr r1, =t_spsr
        str r0, [r1]
        ldmfd  sp!, {r0}
        ldr r1, =t_cpsr
        str r0, [r1]

        ldmfd  sp!, {r0-r12,lr}
        push {r1}
        ldr r1, =t_spsr
        ldr r1,[r1]
        msr    SPSR_cxsf, r1
        ldr r1, =t_cpsr
        ldr r1,[r1]
        msr    CPSR_cxsf, r1
        pop {r1}    
        ldmfd  sp!, {pc}

уменьшила требуемый стек очень прилично.
Вопрос возник не праздно, прокачивю через USB большой поток.. и в результате например банальная tn_idle_task благополучно через перваливала за 96 слов требуемого стека, при том что по умолчанию он 48. Но все равно как я понимаю не застрахован и в этом случае. Какие будут соображения ?
Go to the top of the page
 
+Quote Post
yuri_t
сообщение Mar 29 2007, 12:11
Сообщение #2


Частый гость
**

Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937



Подумаю, поэксперементирую и обязательно отвечу. Если выяснится, что это
существенно, изменения будут сделаны уже в следующей версии (2.4).
В любом случае спасибо за тщательный анализ - вещи, кажущиеся банальными,
открываются с новой стороны...
Go to the top of the page
 
+Quote Post
yuri_t
сообщение Mar 30 2007, 20:07
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937



Отвечаю по-порядку...

Цитата
Но вот по идее то все равно, сколько раз такое может произойти - вобщем-то
определить невозможно, а значит и минимальный требуемый стек для потока должен
стремиться к бесконечности ?


Нет, стек не стремится к бесконечности. Здесь вот в чем соль - чтобы при прерывании
стек задачи(task) использовался для сохранения регистров, эта задача должна
прежде всего быть активной(curr_run). A когда задача становится активной,
то ее стек выгружается в регистры и соответственно ОПУСТОШАЕТСЯ. Отсюда -
не бесконечное увеличение стека, а лишь бесконечный цикл - заполнение/опустошение.

Цитата
Наступление прерывания, требующего переключения контекста в нем затребует у этой задачи еще 15*4=60 байт стека. (вернее надо будет 68 байт, но 8 мы уже отыграли назад)


Здесь Вы, Дмитрий, совершенно правы.
Существующий код выглядит так
Код
tn_sw_restore:

        ldmfd  sp!, {r0}
        ldmfd  sp!, {r1}
        msr    CPSR_cxsf, r1
        msr    SPSR_cxsf, r0

  /*   Эти 3 сроки  можно исключить, т.к. фактически прерывания уже разрешены
     после команды  msr CPSR_cxsf, r1,  как справедливо заметил DASM */

        mrs    r4, CPSR
        bic    r4, r4, #NOINT
        msr    CPSR_c, r4

   /* stack  опустошен */
        ldmfd  sp!, {r0-r12,lr,pc}


Код, уменьшающий использование стека, выглядит так:

Код
tn_sw_restore:

        ldmfd  sp!, {r0}
        ldmfd  sp!, {r1}

        orr    r1, r1, #NOINT /* disable int */
        msr    CPSR_cxsf, r1  /*restore CPSR, but int are off*/
        msr    SPSR_cxsf, r0  /*restore SPSR*/

        ldmfd  sp!, {r0-r12,lr}/* restore all regs, execept pc*/

    /* Enable interrupts */
        stmfd  sp!,{r0}      /* save r0- tmp*/
        mrs    r0, CPSR
        bic    r0, r0, #NOINT
        msr    CPSR_c, r0  /* точка разрешения прерываний */
        ldmfd  sp!,{r0}     /* restore r0*/

        ldmfd  sp!, {pc} /* new pc*/


И тот, и другой варианты функционируют корректно. Здесь лишь вечная задача выбора ("Вчера по 3, но маленькие, сегодня по 5, но большие"(с)) - или занимать больше памяти (стека),
но работать быстрее, или занимать меньше памяти, но работать медленнее.

Цитата
например банальная tn_idle_task благополучно через перваливала за 96 слов
требуемого стека, при том что по умолчанию он 48.


Ф-ция у задачи tn_idle_task выглядит так:

Код
static void tn_idle_task_func(void * par)
{
    for(;;)
    {
        tn_idle_count++;
    }
}

После создания tn_idle_task стек занимает 17 слов, сама задача стек или не использует или использует максимум 2-3 слова(зависит от компилятора).
В худшем варианте с прерываниями, который Вы рассмотрели, понадобится еще,
скажем,17 слов - итого 34(37) и мы явно укладываемся в 48 слов стека этой задачи.
Я запускал под отладчиком множество своих проектов и нигде не видел, чтобы
стек в tn_idle_task неконтролируемо возрастал.
Cовершенно не могу представить, откуда могут взятся здесь 96 слов ???
IMHO, здесь у Вас есть где-то проблемы в Вашем коде.
Go to the top of the page
 
+Quote Post
Alex B._
сообщение Mar 30 2007, 22:43
Сообщение #4


Знающий
****

Группа: Свой
Сообщений: 943
Регистрация: 6-07-04
Из: Санкт-Петербург
Пользователь №: 274



>> После создания tn_idle_task стек занимает 17 слов, сама задача
>> стек или не использует или использует максимум 2-3 слова
>> (зависит от компилятора). В худшем варианте с прерываниями, >> который Вы рассмотрели, понадобится еще, скажем,17 слов
>> - итого 34(37) и мы явно укладываемся в 48 слов стека этой
>> задачи.

А вложенные прерывания?
Go to the top of the page
 
+Quote Post
yuri_t
сообщение Mar 30 2007, 23:34
Сообщение #5


Частый гость
**

Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937



В авторском варианте TNKernel вложенные прерывания не поддерживаются
Go to the top of the page
 
+Quote Post
DASM
сообщение Mar 30 2007, 23:41
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



msr CPSR_c, r0 /* точка разрешения прерываний */
ldmfd sp!,{r0} /* restore r0*/

ldmfd sp!, {pc} /*
Тот же вараиант, что я и привел выше по-сути. Прерывания разрешаются, когда еще в стеке задачи два int - а (R0 и PC). Далее ситуация - прерывания, требующее irq_context_int. Задача вытесняется на этой точке. Потом задача делается опять планируемой (через обычный switch_context уже ) Выполнение продолжается с точки ldmfd sp!,{r0}. НО ТУТ же задача опять вытесняется вышеназванным методом. И так далее. Я не вижу тут ограничения для бесконечного роста стека в вытесненной задаче, т.к. вытеснение происходит многократно в точке, где стек еще несбалансирован. Изучение стека задачи, кушающей так много стека это подтверждает. Там сплошные точки возврата в эти две команды.
"В худшем варианте с прерываниями, который Вы рассмотрели, понадобится еще,
скажем,17 слов - итого 34(37) и мы явно укладываемся в 48 слов стека этой задачи."
Тут не понял... при вытеснении этой задачи в ей стек будут сохранены все R0-R12, PC, LR, SPSR и CPSR.
Проверить это все просто. В примере USB_BULK через USBIO закидать допустим 2-ую endpoint мегабайтами траффика. Для нагляндности в USBIO размер буффера лучше поставить например 5-ть байт, так прерываний больше будет. ( Упростил код только до ожидания очереди от приема 2-ой endpoint и тут же release_mem, ьессмысленный но отладочный вариант). А потом поглядеть насколько опускался стек idle_task. И мы НЕ уложимся в стек задачи именно из-за множественного вытеснения. В исправленном варианте все намного лучше - стек будет увеличиваться не более чем на два слова. Но вот сколько раз это рекуррентно произойдет ?
Go to the top of the page
 
+Quote Post
Alex B._
сообщение Mar 31 2007, 00:06
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 943
Регистрация: 6-07-04
Из: Санкт-Петербург
Пользователь №: 274



>> В авторском варианте TNKernel вложенные прерывания
>> не поддерживаются
Тогда не понимаю, зачем нужен tn_int_counter и его проверка на >1 (я так думал, чтобы разрешить переключение контекста только из первого прервания - что логично):

Код
tn_cpu_irq_isr:

        stmfd  sp!,{r0-r12,lr}   /* Save ALL registers */

       /*--  interrupt_counter++ */

        ldr    r2, =tn_int_counter
        ldr    r3, [r2]                /* interrupt_counter -> r3 */
        add    r0, r3,#1               /* interrupt_counter++     */
        str    r0, [r2]

        bl     tn_cpu_irq_handler      /* Actually  Handle interrupt */

        /* interrupt_counter-- */

        ldr    r2, =tn_int_counter
        ldr    r1, [r2]
        sub    r3, r1,#1
        str    r3, [r2]
        cmp    r3, #0x00               /* if it is nested int - return */
                                               /* ваш комментарий ^^^^^^^ */

        bne    exit_irq_int            /* return from int*/
        ldr    r0, =tn_context_switch_request  /* see if we need to do a context switch */
        ldr    r1, [R0]
        cmp    r1, #0                  /* if 0 - return */
        beq    exit_irq_int
        mov    r1, #0                  /* else - clear req flag and  goto context switch */
        str    r1, [r0]
        b      tn_int_ctx_switch


Еще, Дмитрий, пока не забыл -
В версии с сайта (2.3) есть небольшой баг - при возникновении любого прерывания, переключающего контекст во время выполнения tn_task_exit() задача по activate не восстанавливается. Мы с Юрием это обсуждали, он прислал код 2.3.1, но на сайт его почему-то не выложил...
Go to the top of the page
 
+Quote Post
DASM
сообщение Mar 31 2007, 00:08
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



А я допишу пока для ясности..
"A когда задача становится активной,
то ее стек выгружается в регистры и соответственно ОПУСТОШАЕТСЯ."
Так в том то и дело, что он не успевает полностью выгрузиться в регистры, как задача снова вытесняется. Проблему полностью бы решила атомарная загрузка регистров +CPSR через {la-la} ^
Но пока я не очень представляю как это сделать, в CPSR надо не содержимое SPSR отнюдь загружать.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 31 2007, 01:05
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(DASM @ Mar 30 2007, 23:08) *
Но пока я не очень представляю как это сделать, в CPSR надо не содержимое SPSR отнюдь загружать.
"Я Пастернака не читал...", в смысле исходники TNKernel не изучал, но если SPSR после восстановления не нужен, то значит в него и надо перед восстановлением всех регистров занести требуемое значение для CPSR. И при его восстановлении операцией ldmfd xx, {...}^ разрешать прерывания. Глянь мой порт scmRTOS, может там мысль почерпнешь.

P.S. Там долго думал как организовать восстановление из SPSR когда смена контекста вызывается из User/System Mode, в которых SPSR нет. Не нашел ничего лучше чем принудительно одновременно с запретом прерываний irq переключиться в IRQ Mode и использовать неиспользуемый (по причине запрещенных прерываний) в этот момент SPSR_irq.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
DASM
сообщение Mar 31 2007, 01:14
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Цитата(Сергей Борщ @ Mar 31 2007, 02:05) *
"Я Пастернака не читал...", в смысле исходники TNKernel не изучал, но если SPSR после восстановления не нужен, то значит в него и надо перед восстановлением всех регистров занести требуемое значение для CPSR. И при его восстановлении операцией ldmfd xx, {...}^ разрешать прерывания. Глянь мой порт scmRTOS, может там мысль почерпнешь.

Надо подумать.. Кстати по-моему в UCOS засада со стеком точно такая же сидит
.
Проверил ! Все замечательно работает, и стека не кушает :-) Немного тяжко думать, прав ли я теряя SPSR и записывая в него на самом деле CPSR, но раз работает - значит можно :-) Возможно Юрий лучше ответит на этот вопрос, я в АРМовском асме дня три три только копаться начал. Но со стеком теперь совсем хорошо - 18 байт скушал idle_task и больше ни словом больше, несмотря ни на какие вытеснения. Вопрос решен !!!!!!!!!!!!!!!!!!!!!!!!!!!!
Вот итоговый код.
Код
tn_sw_restore
        add sp, sp, #4; easy adjust stack pointer, since we don't need restore original  SPCR
        ldmfd  sp!, {r1}
        msr    SPSR_cxsf, r1; transfer saved CPSR to SPSR        
        ldmfd  sp!, {r0-r12,lr,pc}^
Go to the top of the page
 
+Quote Post
spf
сообщение Mar 31 2007, 05:22
Сообщение #11


Странник
****

Группа: Свой
Сообщений: 766
Регистрация: 29-08-05
Из: Екатеринбург
Пользователь №: 8 051



Цитата(yuri_t @ Mar 31 2007, 02:34) *
В авторском варианте TNKernel вложенные прерывания не поддерживаются

Существенное ограничение. Это затрудняет появление портов операцинки на других МК, где имеется более развитый, чем у ARM7, контроллер прерываний.


--------------------
"Как много есть на свете вещей, которые мне не нужны!" Сократ
Go to the top of the page
 
+Quote Post
DASM
сообщение Mar 31 2007, 07:43
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Цитата(spf @ Mar 31 2007, 06:22) *
Существенное ограничение. Это затрудняет появление портов операцинки на других МК, где имеется более развитый, чем у ARM7, контроллер прерываний.

да это ограничение обойти то не вопрос. Да и не нада нам ваших процев tongue.gif
Go to the top of the page
 
+Quote Post
spf
сообщение Mar 31 2007, 08:41
Сообщение #13


Странник
****

Группа: Свой
Сообщений: 766
Регистрация: 29-08-05
Из: Екатеринбург
Пользователь №: 8 051



Цитата(DASM @ Mar 31 2007, 10:43) *
да это ограничение обойти то не вопрос.

Это понятно, но зачем обходить, если можно взять другую, в которой об этом позаботились сразу.
(отношение к "собственным" вариантам ОС уже высказывал)
Почему это не реализовано сразу? Хотя в первой строке записано
"TNKernel is a compact and very fast real-time kernel for the embedded 32/16 bits microprocessors."
т.е. предлагается забыть об аппаратных возможностях большинства 32/16 МК?

PS:Прошу отнестись к моему вопросу с пониманием, а не бравым отрицанием НЕarm'ов.

Цитата
Да и не нада нам ваших процев tongue.gif

Не горячись раньше времени wink.gif


--------------------
"Как много есть на свете вещей, которые мне не нужны!" Сократ
Go to the top of the page
 
+Quote Post
DASM
сообщение Mar 31 2007, 09:18
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



Цитата(spf @ Mar 31 2007, 09:41) *
Это понятно, но зачем обходить, если можно взять другую, в которой об этом позаботились сразу.
(отношение к "собственным" вариантам ОС уже высказывал)
Почему это не реализовано сразу? Хотя в первой строке записано
"TNKernel is a compact and very fast real-time kernel for the embedded 32/16 bits microprocessors."
т.е. предлагается забыть об аппаратных возможностях большинства 32/16 МК?

PS:Прошу отнестись к моему вопросу с пониманием, а не бравым отрицанием НЕarm'ов.
Не горячись раньше времени wink.gif

Ну так заведи свою ветку как плох TNKernel и почему ты выбрал не её. Тут обсуждаем расход памяти потоком
Go to the top of the page
 
+Quote Post
yuri_t
сообщение Mar 31 2007, 09:30
Сообщение #15


Частый гость
**

Группа: Свой
Сообщений: 163
Регистрация: 24-08-05
Пользователь №: 7 937



По материалам дискуссии буду делать v.2.4. Туда же войдет исправление
бага в ф-ции tn_task_exit(), который нашел Alex_B.
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 6th August 2025 - 11:34
Рейтинг@Mail.ru


Страница сгенерированна за 0.01487 секунд с 7
ELECTRONIX ©2004-2016