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

 
 
> Стэк в scmRTOS
spongebob
сообщение Apr 24 2012, 18:19
Сообщение #1


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Всем привет!

Поясните, пожалуйста, есть ли какая-нибудь взаимосвязь между стеком программы и стеками процессов в ОС?
И между их размерами...
Что конкретно хранится в стеках процессов?

Допустим, правильно ли следующее.

В системе два процесса (П1 и П2).
П1 завершает работу.
Планировщик копирует содержимое стека программы в стек П1, а содержимое стека П2 в стек программы и передает управление П2.
П2 работает, потом завершает работу.
Планировщик копирует содержимое стека программы в стек П2, а содержимое стека П1 в стек программы и передает управление П1.
Далее все повторяется по кругу...
Стеки процессов не должны превышать размеры стека программы. Допустим, если в mega1280 во внутренней памяти размещается только стек программы, то стеки каждого из процессов не должны превышать 8192 байт.

Бьюсь который день со спонтанной перезагрузкой, никак баг поймать не могу sad.gif
Go to the top of the page
 
+Quote Post
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 32)
_Артём_
сообщение Apr 24 2012, 18:40
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(spongebob @ Apr 24 2012, 21:19) *
Допустим, если в mega1280 во внутренней памяти размещается только стек программы, то стеки каждого из процессов не должны превышать 8192 байт.

Это чтож за ПРОЦЕСС с таким размером стека?

Цитата(spongebob @ Apr 24 2012, 21:19) *
Бьюсь который день со спонтанной перезагрузкой, никак баг поймать не могу sad.gif

Может стек здесь и ни причём?
Был у меня такой случай: задача копировала данные из кругового буфера в линейней для дальнейшей обработки. И в функции копирования была ошибка: функция начинала копировать из буфера ~64 кБ данных в линейный буфер и при этом переписывала всё ОЗУ. Через какое-то время происходил сброс (по WDT или как-то ещё).
Go to the top of the page
 
+Quote Post
spongebob
сообщение Apr 24 2012, 18:52
Сообщение #3


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Цитата(_Артём_ @ Apr 24 2012, 22:40) *
Это чтож за ПРОЦЕСС с таким размером стека?


В процессе вызываются функции обработки данных, в которых используются локальные крупные массивы.
На самом деле памяти меньше съедается, я просто хочу понять принцип sm.gif
Например, что произойдет, если я объявлю размер стека в процессе 10 кБ, а стек программы, как писалось выше, будет иметь размер не более 8 кБ?

Цитата
Может стек здесь и ни причём?
Был у меня такой случай: задача копировала данные из кругового буфера в линейней для дальнейшей обработки. И в функции копирования была ошибка: функция начинала копировать из буфера ~64 кБ данных в линейный буфер и при этом переписывала всё ОЗУ. Через какое-то время происходил сброс (по WDT или как-то ещё).


Может и ни при чем...
Сторожевого таймера нет.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Apr 24 2012, 19:05
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(spongebob @ Apr 24 2012, 21:52) *
Например, что произойдет, если я объявлю размер стека в процессе 10 кБ, а стек программы, как писалось выше, будет иметь размер не более 8 кБ?


У вас внешняя память?
Стек программы - стек на котором работают прерывания и main до вызова OS::Run.
Стеки для процессов задаются индивидуально и их размеры никак не связаны друг с другом (лишбы памяти хватило и при этом всё работало).
Какой у вас компилятор IAR или GCC?

Цитата(spongebob @ Apr 24 2012, 21:52) *
Сторожевого таймера нет.


Сейчас не помню точно был ли у меня включен WDT. Может и не был, но как оно тогда на reset попадало?
Go to the top of the page
 
+Quote Post
spongebob
сообщение Apr 24 2012, 19:28
Сообщение #5


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Цитата(_Артём_ @ Apr 24 2012, 23:05) *
У вас внешняя память?


Ага, к 8 кБ на кристалле еще 32 кБ снаружи.

Цитата
Стек программы - стек на котором работают прерывания и main до вызова OS::Run.


Вы хотите сказать, что стек программы после запуска ОС не используется? sm.gif
Кстати, мы ведь ради интереса можем взять адрес какой-нибудь локальной переменной, принадлежащей процессу. По адресу будет видно где она лежит...

Цитата
Стеки для процессов задаются индивидуально и их размеры никак не связаны друг с другом (лишбы памяти хватило и при этом всё работало).


Об этом я знаю... я спрашивал как связан стек программы со стеками процессов... стеки процессов конечно не зависят друг от друга...

Цитата
Какой у вас компилятор IAR или GCC?


GCC.

Цитата
Сейчас не помню точно был ли у меня включен WDT. Может и не был, но как оно тогда на reset попадало?


Очень интересный вопрос, но для того, чтобы на резет попадало вотчдога не всегда нужно, нужен просто баг хороший wink.gif
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Apr 24 2012, 20:04
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(spongebob @ Apr 24 2012, 22:28) *
Ага, к 8 кБ на кристалле еще 32 кБ снаружи.

Интересно как скажется на производительности то, что стек расположен по внешней ОЗУ?

Цитата(spongebob @ Apr 24 2012, 22:28) *
Вы хотите сказать, что стек программы после запуска ОС не используется? sm.gif

Если не ошибаюся, то возможны варианты:
1. В прерывании используется TISRW - прерывание работает на стеке прерванного процесса.
2. В прерывании используется TISRW_SS - прерывание использует стек выделенный для функции main.

Цитата(spongebob @ Apr 24 2012, 22:28) *
я спрашивал как связан стек программы со стеками процессов... стеки процессов конечно не зависят друг от друга...

Да вроде никак не связан.
Какая между ними связь может вообще быть?

Цитата(spongebob @ Apr 24 2012, 22:28) *
Очень интересный вопрос, но для того, чтобы на резет попадало вотчдога не всегда нужно, нужен просто баг хороший wink.gif

Возможный вариант: моя функция копирования портила часть (или всё озу), но в конечном итоге делала ret. Но стек уже был заполнен непонятно чем. Програма была небольшая (10-15 кБ). И в результате возврат происходил в область заполненную FF. И программа могла дойти до адреса 0.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Apr 25 2012, 04:32
Сообщение #7


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(_Артём_ @ Apr 24 2012, 23:04) *
Интересно как скажется на производительности то, что стек расположен по внешней ОЗУ?
Каждый push будет занимать не два такта, а минимум три, зависимо от настроек внешнего интерфейса. Ну и вся работа с локальными переменными на стеке (LDD Rx, Y+d).
Стоило бы подумать о том, чтобі большие массивы не делать локальными, стеки разместить во внутреннем ОЗУ, а большие массивы — во внешнем.

Цитата(_Артём_ @ Apr 24 2012, 23:04) *
Если не ошибаюся, то возможны варианты:
1. В прерывании используется TISRW - прерывание работает на стеке прерванного процесса.
2. В прерывании используется TISRW_SS - прерывание использует стек выделенный для функции main.
Да. Второй вариант несколько медлительнее, но экономичнее по суммарному объёму стеков при разрешении вложенных прерываний.
При входе в первое прерывание регистры сохраняются на стеке прерванной задачи, а вложенные прерывания уже сохраняют всё на выделенном стеке общем для всех процессов.
Если вложенные прерывания не разрешаются, то для AVR особого смысла использовать TISRW_SS нет.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
spongebob
сообщение Apr 25 2012, 05:57
Сообщение #8


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Цитата(ReAl @ Apr 25 2012, 08:32) *
Стоило бы подумать о том, чтобі большие массивы не делать локальными, стеки разместить во внутреннем ОЗУ, а большие массивы — во внешнем.


Ну как большие... около 300 байт. Несколько их (по одному в каждой вложенной функции), функций несколько... вот и набегает.
Фактически, большая часть из этих массивов - временные, нужны иногда, поэтому было принято решение делать их локальными, чтобы они создавались на стеке (типа, память сэкономить).

По поводу размещения... тут я совсем слаб...
Делаем большие массивы глобальными и с помощью ключей компилятора (линкера) перемещаем секции data, bss во внешнюю память (-Wl,--section-start,.data=0x802200)?
А как тогда разместить стеки процессов во внутреннем ОЗУ? Если процессов много, то хватит ли им 8 кБ внутреннего ОЗУ? sm.gif
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Apr 25 2012, 06:50
Сообщение #9


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Если массивы большие и нужда в них возникает редко, то может очень помочь использование кучи. Писал в своё время менеджер кучи для AVR, ничего сложного в этом нет. На производительность не слишком влияет ибо событие, как я уже говорил, редкое. Зато память экономится радикально.
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 25 2012, 07:25
Сообщение #10


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Если массивы временные, то почему бы не использовать один и тот же, глобальный, для разных целей? Только уже без ОС.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 25 2012, 07:44
Сообщение #11


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(ViKo @ Apr 25 2012, 13:25) *
Если массивы временные, то почему бы не использовать один и тот же, глобальный, для разных целей? Только уже без ОС.
А почему это вы думаете, что ОС запрещает использовать глобальные объекты? sm.gif

Цитата(spongebob @ Apr 25 2012, 11:57) *
Фактически, большая часть из этих массивов - временные, нужны иногда, поэтому было принято решение делать их локальными, чтобы они создавались на стеке (типа, память сэкономить).

В scmRTOS 4.0 появился механизм для вычисления используемого каждым процессом стека (см. пример 4-Debug). Включите его, погоняйте. Узнаете, сколько чего и где. Может быть, всё спокойно влезет во внутреннее ОЗУ.
Цитата(spongebob @ Apr 25 2012, 11:57) *
По поводу размещения... тут я совсем слаб...

Почитайте про линкерные скрипты. Примеры используемых avr-gcc скриптов находятся в lib\ldscripts.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 25 2012, 07:54
Сообщение #12


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(AHTOXA @ Apr 25 2012, 10:44) *
А почему это вы думаете, что ОС запрещает использовать глобальные объекты? sm.gif

Думаю, что в ОС будет сложно контролировать, кто пользуется в данный момент универсальным массивом.

upd. Разве что с кооперативной многозадачностью...
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 25 2012, 07:56
Сообщение #13


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



А вот как раз для такого контроля в ОС и предусмотрены средства синхронизации sm.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ReAl
сообщение Apr 25 2012, 07:56
Сообщение #14


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(spongebob @ Apr 25 2012, 08:57) *
Делаем большие массивы глобальными и с помощью ключей компилятора (линкера) перемещаем секции data, bss во внешнюю память (-Wl,--section-start,.data=0x802200)?
Не надо так. Не только стеки, все внутренние структуры scmRTOS полетят во внешнюю память. Вообще всё. С соответствующим замедлением. Во внутренней останется только «стек main()», который и использовать-то толком тяжело.

Перенести только нужное во внешнюю память можно так http://electronix.ru/forum/lofiversion/index.php/t47714.html



--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 25 2012, 07:57
Сообщение #15


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(AHTOXA @ Apr 25 2012, 10:56) *
А вот как раз для такого контроля в ОС и предусмотрены средства синхронизации sm.gif

Что это? sm.gif Мьютексы?
Работа с массивами - дело долгое. От многозадачности мало что останется, пмсм.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 25 2012, 08:24
Сообщение #16


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(ViKo @ Apr 25 2012, 13:57) *
Что это? sm.gif Мьютексы?
Работа с массивами - дело долгое. От многозадачности мало что останется, пмсм.

Да, мутексы. Тут ведь дело не в ОС/не ОС. А в логике работы. Если две разные задачи должны одновременно работать с одним массивом, то это проблемы в логике. Вероятнее, нужно так: одна задача готовит данные в массиве, вторая - обрабатывает. При таком подходе мутекс вполне оправдан - он позволяет второй задаче подождать, пока первая задача подготовит данные.
А в случае топикстартера всё похоже ещё проще - с массивом работает одна задача. Просто массив надо вынести из стека задачи. В этом случае можно и без мутекса.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
spongebob
сообщение Apr 25 2012, 10:37
Сообщение #17


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Цитата(ViKo @ Apr 25 2012, 11:57) *
Работа с массивами - дело долгое. От многозадачности мало что останется, пмсм.


Фактически дело обстоит так.
Имеется очередь (OS::channel) из элементов структур (в структуре массив 250 байт + еще несколько переменных).
Один процесс кладет в очередь данные (команды) когда нужно, другой процесс - извлекает их и обрабатывает.
Очередь нужна, чтобы "копить" команды, т. к., команды могут выполняться достаточно долго, а терять их очень нежелательно.
Ну и чтобы поместить элемент в очередь (push) и извлечь его оттуда (pop) приходится заводить временный элемент (тип и размер - выше), который и отжирает стек.
Сама очередь - глобальная.

Ну, может, архитектура не совсем нормальная... посоветуйте, пожалуйста, как лучше sm.gif

Цитата(AHTOXA @ Apr 25 2012, 12:24) *
А в случае топикстартера всё похоже ещё проще - с массивом работает одна задача. Просто массив надо вынести из стека задачи. В этом случае можно и без мутекса.


Да, с массивом работает одна задача. Но их как минимум два sm.gif
Принцип действия следующий.

Процесс 1 (главный, дает команды): команда -> функция подготовки команды и помещения ее в очередь (помещает данные в свой локальный буфер 1, а из него в очередь) -> очередь.
Процесс 2 (подчиненный выполняет команды): функция извлечения команды из очереди в буфер 2 и обработки команды.

Команды занимают приличный объем и имеют разный размер. Буферы 1 и 2 - одного типа, под все команды (универсальные).
Проблема в том как поместить в очередь команду, не используя для этого промежуточный буфер 1.

Цитата(ReAl @ Apr 25 2012, 11:56) *
Не надо так. Не только стеки, все внутренние структуры scmRTOS полетят во внешнюю память. Вообще всё. С соответствующим замедлением. Во внутренней останется только «стек main()», который и использовать-то толком тяжело.


Вот так вот изначально было сделано... фактически во внутренних 8 кБ остался только стек main().
Кстати, возвращаясь к вопросу об устройстве стеков при использовании ОС. После старта ОС стек main() не используется (планировщик при передаче управления заносит в указатель стека адрес стека требуемого процесса, который может быть расположен где угодно)?

А почему стек main() использовать тяжело?

Цитата
Перенести только нужное во внешнюю память можно так http://electronix.ru/forum/lofiversion/index.php/t47714.html


Спасибо, почитаем.
Как я понял, надо осваивать скриптописание для линкера? sm.gif
В двух словах, создаем специальные секции, в которые по необходимости переносим некоторые переменные, а эти секции линкуются куда надо (в данном случае во внешнюю память)?

Цитата(AHTOXA @ Apr 25 2012, 11:44) *
В scmRTOS 4.0 появился механизм для вычисления используемого каждым процессом стека (см. пример 4-Debug). Включите его, погоняйте. Узнаете, сколько чего и где. Может быть, всё спокойно влезет во внутреннее ОЗУ.


Очень интересно sm.gif

Цитата
Почитайте про линкерные скрипты. Примеры используемых avr-gcc скриптов находятся в lib\ldscripts.


Спасибо, почитаем, главное - понять что там написано sm.gif Пока линкерные скрипты для меня страшны sad.gif
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Apr 25 2012, 11:52
Сообщение #18


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(ReAl @ Apr 25 2012, 10:56) *
Во внутренней останется только «стек main()», который и использовать-то толком тяжело.

Можно наверное в нём что-то расположить, используя указатели: адрес ведь известен.

Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 25 2012, 12:39
Сообщение #19


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Может, ляпну глупость, но, разве в очередь (message) обязательно пихать сам массив (структуру), а не указатель на него? В RTOS вроде, так делается?
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Apr 25 2012, 12:59
Сообщение #20


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(spongebob @ Apr 25 2012, 16:37) *
Процесс 1 (главный, дает команды): команда -> функция подготовки команды и помещения ее в очередь (помещает данные в свой локальный буфер 1, а из него в очередь) -> очередь.
Процесс 2 (подчиненный выполняет команды): функция извлечения команды из очереди в буфер 2 и обработки команды.

Дык, помещайте в очередь не сам буфер, а его номерsm.gif (Ну или как правильно сказал ViKo, указатель на него).


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
spongebob
сообщение Apr 25 2012, 14:56
Сообщение #21


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Цитата(_Артём_ @ Apr 25 2012, 15:52) *
Можно наверное в нём что-то расположить, используя указатели: адрес ведь известен.


А, ну это да, можно...

Цитата(AHTOXA @ Apr 25 2012, 16:59) *
Дык, помещайте в очередь не сам буфер, а его номерsm.gif (Ну или как правильно сказал ViKo, указатель на него).


Т. е., заводим большой массив (глобальный статический), который, к примеру, может вместить в себя 10 команд (размер данных каждой команды = размеру данных максимальной команды). Доступ к массиву между процессами разделяем с помощью мьютекса.
Процесс 1 помещает команду в массив, указатель на команду в массиве помещает в очередь команд (она теперь маленькая по объему).
Процесс 2 извлекает из очереди указатель на команду и по нему получает доступ к данным команды.
Так?
Но тогда придется как-то учитывать процессу 1, что в массиве по определенным адресам уже есть команды, чтобы не затереть ничего.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 25 2012, 16:38
Сообщение #22


Гуру
******

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



QUOTE (spongebob @ Apr 25 2012, 17:56) *
Но тогда придется как-то учитывать процессу 1, что в массиве по определенным адресам уже есть команды, чтобы не затереть ничего.
Вот тут на помощь и приходит куча. Процесс 1 запрашивает у менеджера кучи область памяти нужного размера (а не максимального), получает указатель, заполняет память по этому указателю, после чего помещает указатель в очередь и забывает про него. Процесс 2 достает указетель из очереди, обрабатывает данные и дает менеджеру кучи команду освободить память. Поскольку команды у вас обрабатываются строго по порядку - проблема фрагментации кучи не возникнет. Забота "о том, чтобы ничего не затереть" ложится на менеджер кучи. Выкладывал тут на форуме переделанный под scmRTOS (завернутый в мутекс и переложенный на C++) легковесный менеджер кучи имени zltigo.

Кстати, при словах "Команды занимают приличный объем и имеют разный размер" приходят на ум умные слова "полиморфизм" и "кормление слона в примере 3-channel". Т.е. все команды можно сделать потомками одного абстрактного класса с виртуальной функцией execute(), которую и будет вызывать по извлеченному из канала указателю Процесс 2. И тогда команды очень легко и красиво создаются при помощи оператора new() и забирают из кучи ровно столько памяти, сколько необходимо. И заботу о необходимом каждой конкретной команде объеме памяти полностью берет на себя компилятор. А освобождается память после выполнения execute() оператором delete(). И при таком подходе компилятор же будет следить за тем, чтобы вы не забыли написать обработку для какой-либо команды.


--------------------
На любой вопрос даю любой ответ
"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
spongebob
сообщение Apr 26 2012, 05:12
Сообщение #23


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Цитата(Сергей Борщ @ Apr 25 2012, 20:38) *
Вот тут на помощь и приходит куча. Процесс 1 запрашивает у менеджера кучи область памяти нужного размера (а не максимального), получает указатель, заполняет память по этому указателю, после чего помещает указатель в очередь и забывает про него. Процесс 2 достает указетель из очереди, обрабатывает данные и дает менеджеру кучи команду освободить память. Поскольку команды у вас обрабатываются строго по порядку - проблема фрагментации кучи не возникнет. Забота "о том, чтобы ничего не затереть" ложится на менеджер кучи. Выкладывал тут на форуме переделанный под scmRTOS (завернутый в мутекс и переложенный на C++) легковесный менеджер кучи имени zltigo.

Кстати, при словах "Команды занимают приличный объем и имеют разный размер" приходят на ум умные слова "полиморфизм" и "кормление слона в примере 3-channel". Т.е. все команды можно сделать потомками одного абстрактного класса с виртуальной функцией execute(), которую и будет вызывать по извлеченному из канала указателю Процесс 2. И тогда команды очень легко и красиво создаются при помощи оператора new() и забирают из кучи ровно столько памяти, сколько необходимо. И заботу о необходимом каждой конкретной команде объеме памяти полностью берет на себя компилятор. А освобождается память после выполнения execute() оператором delete(). И при таком подходе компилятор же будет следить за тем, чтобы вы не забыли написать обработку для какой-либо команды.


Принцип понятен, спасибо большое за рекомендации.
Но как же мнение о том, что динамическая память для AVR - это слишком ресурсоемко и не выгодно?
Кстати, в WinAVR уже есть менеджер кучи и чем он отличается от выше Вами указанного?
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Apr 26 2012, 07:16
Сообщение #24


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(spongebob @ Apr 26 2012, 08:12) *
Но как же мнение о том, что динамическая память для AVR - это слишком ресурсоемко и не выгодно?

Опять мифы!!!
Аналогичные мифы (применительно к МК) о C++, printf/scanf, RTOS и прочая циркулируют в эмбеддерской среде с пугающей живучестью.
Подумайте над следующим. Чьи ресурсы занимаются? Контроллера или лично Ваши (рабочее время, деньги)? Ваши затраты будут единоразовыми и неизвестно в каком случае больше - применив кучу или изголяясь окольными путями. В случае контроллера, если он решает поставленную задачу и решает успешно, то какая Вам разница? Попробуйте лично и определитесь.

PS Когда не устраивает библиотечный вариант какой-либо фичи, напишите или используйте кем-нибудь написанный готовый - облегчённый. Что касается варианта кучи, то Вам уже предложили или возьмите из второй версии scmRTOS.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 26 2012, 07:28
Сообщение #25


Гуру
******

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



QUOTE (spongebob @ Apr 26 2012, 08:12) *
Но как же мнение о том, что динамическая память для AVR - это слишком ресурсоемко и не выгодно?
А вы попробуйте. На первый взгляд ресурсоемким и невыгодным выглядит решение без менеджера кучи. Менеджеры бывают разные...
В вашем случае менеджер можно упростить до предела, сделав его на базе кольцевого буфера. Выделение памяти двигает указатель головы, освобождение - указатель хвоста. Вы обещаете освобождать память строго в том же порядке, в котором она была выделена (а в случае вашей очереди это так и получается) и за счет этого менеджеру не нужны поиск свободного блока нужного размера, "склеивание" освобожденных блоков и т.д. А чтобы оставить возможность в дальнейшем для каких-то других целей использовать "настоящий" менеджер - можно обращаться к этому через переопределенный оператор new.

QUOTE (spongebob @ Apr 26 2012, 08:12) *
Кстати, в WinAVR уже есть менеджер кучи и чем он отличается от выше Вами указанного?
Не знаю. Я этот менеджер использовал на ARM, где родной библиотечный тянет за собой мама дорогая сколько лишнего. Менеджер из avr-libc я не использовал. Сравните, будет интересно узнать результаты.


--------------------
На любой вопрос даю любой ответ
"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
ViKo
сообщение Apr 26 2012, 09:04
Сообщение #26


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Цитата(Сергей Борщ @ Apr 26 2012, 10:28) *
В вашем случае менеджер можно упростить до предела, сделав его на базе кольцевого буфера. Выделение памяти двигает указатель головы, освобождение - указатель хвоста. Вы обещаете освобождать память строго в том же порядке, в котором она была выделена (а в случае вашей очереди это так и получается)...

Вряд ли такую строго упорядоченную конструкцию можно назвать кучей. Скорее уж, действительно, кольцевой буфер. Тогда к чему лишние процедуры выделения, освобождения...?
Я понимаю, работа с этими массивами идет постоянно. Вот и сделать их глобальными. Иметь некий индекс текущего рабочего буфера, им и манипулировать.
Go to the top of the page
 
+Quote Post
spongebob
сообщение Apr 26 2012, 19:32
Сообщение #27


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Кстати, насколько прожорлив sprintf? Сколько он потребляет стека? Использует ли он кучу?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 26 2012, 21:06
Сообщение #28


Гуру
******

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



Кучу - нет. По стеку можно посмотреть его исходники, порядка 20-30 байт плюс на передачу параметров (это относится только к sprintf из avr-libc, естественно).


--------------------
На любой вопрос даю любой ответ
"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
spongebob
сообщение Apr 27 2012, 06:25
Сообщение #29


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

Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879



Цитата(Сергей Борщ @ Apr 27 2012, 01:06) *
Кучу - нет. По стеку можно посмотреть его исходники, порядка 20-30 байт плюс на передачу параметров (это относится только к sprintf из avr-libc, естественно).


Ну, получается и не прожорливый совсем... мельком погуглил - жалуются на прожорливость.
Да, вопрос про avr-libc sm.gif
Кстати, в WinAVR есть эти исходники (сейчас нет под рукой посмотреть, к сожалению)?
Наверное, в avr-libc sprintf жутко оптимизированный под AVRы? sm.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 27 2012, 10:01
Сообщение #30


Гуру
******

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



QUOTE (spongebob @ Apr 27 2012, 09:25) *
Кстати, в WinAVR есть эти исходники (сейчас нет под рукой посмотреть, к сожалению)?
В WinAVR нет. Лежат отдельно в репозитории avr-libc.
QUOTE (spongebob @ Apr 27 2012, 09:25) *
Наверное, в avr-libc sprintf жутко оптимизированный под AVRы? sm.gif
Да.


--------------------
На любой вопрос даю любой ответ
"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
ReAl
сообщение Apr 27 2012, 18:46
Сообщение #31


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Сергей Борщ @ Apr 27 2012, 00:06) *
Кучу - нет. По стеку можно посмотреть его исходники, порядка 20-30 байт
Полный вариант — немного больше сорока, добавляется буфер под максимально возможную длину для преобразования float. В очень старых версиях (~10-летней давности) полный вариант при наличии float-форматов выделял этот буфер через malloc. Это притянулось от какого-то распространённого варината форматтера, но быстро было исправлено.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Apr 27 2012, 21:18
Сообщение #32


Гуру
******

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



QUOTE (ReAl @ Apr 27 2012, 21:46) *
добавляется буфер под максимально возможную длину для преобразования float.
Что-то я не нашел его в исходниках. 11-байтовый плюс еще несколько локальных переменных видел, но они используются во всех вариантах. преобразование float скидывает 6 регистров на стек, плюс сами параметры printf на стек кладутся.


--------------------
На любой вопрос даю любой ответ
"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
ReAl
сообщение Apr 28 2012, 17:00
Сообщение #33


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Точно. Давненько я туда не заглядывал. Работает, да и ладно :-)
Когда-то давно-давно, до avr-libc 1.6, как я сейчас выяснил, было
Код
#define FLTBUFLEN 40
...
#if PRINTF_LEVEL >= PRINTF_FLT
    int8_t    decpt;
    char    fb[FLTBUFLEN];    /* floating point buffer */
#endif
остатки от форматтера, который и double умел.
Сейчас они 1) жёстко урезали до float с максимум 7 значащими цифрами и написанная на ассемблере __ftoa_engine в тот 11-байтовый буфер складывает флаги результата преобразования (в т.ч. NAN) и преобраованную мантиссу, а порядок возвращает в vfprintf как число, которое там уже выводится отдельно. Итого к стеку в самом vfprintf добавляется адрес возврата при вызове __ftoa_engine и шесть байтов для сохраняемых в ней регистров. Очень хорошо (то-то я как пример 4-debug написал, так удивился, что отладочній процесс с printf-ом ест меньше стека, чем яожидал :-) ).


--------------------
Ну, я пошёл… Если что – звоните…
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 Текстовая версия Сейчас: 21st July 2025 - 20:35
Рейтинг@Mail.ru


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