|
Стэк в scmRTOS |
|
|
|
Apr 24 2012, 18:19
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Всем привет! Поясните, пожалуйста, есть ли какая-нибудь взаимосвязь между стеком программы и стеками процессов в ОС? И между их размерами... Что конкретно хранится в стеках процессов? Допустим, правильно ли следующее. В системе два процесса (П1 и П2). П1 завершает работу. Планировщик копирует содержимое стека программы в стек П1, а содержимое стека П2 в стек программы и передает управление П2. П2 работает, потом завершает работу. Планировщик копирует содержимое стека программы в стек П2, а содержимое стека П1 в стек программы и передает управление П1. Далее все повторяется по кругу... Стеки процессов не должны превышать размеры стека программы. Допустим, если в mega1280 во внутренней памяти размещается только стек программы, то стеки каждого из процессов не должны превышать 8192 байт. Бьюсь который день со спонтанной перезагрузкой, никак баг поймать не могу
|
|
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 32)
|
Apr 24 2012, 18:40
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(spongebob @ Apr 24 2012, 21:19)  Допустим, если в mega1280 во внутренней памяти размещается только стек программы, то стеки каждого из процессов не должны превышать 8192 байт. Это чтож за ПРОЦЕСС с таким размером стека? Цитата(spongebob @ Apr 24 2012, 21:19)  Бьюсь который день со спонтанной перезагрузкой, никак баг поймать не могу  Может стек здесь и ни причём? Был у меня такой случай: задача копировала данные из кругового буфера в линейней для дальнейшей обработки. И в функции копирования была ошибка: функция начинала копировать из буфера ~64 кБ данных в линейный буфер и при этом переписывала всё ОЗУ. Через какое-то время происходил сброс (по WDT или как-то ещё).
|
|
|
|
|
Apr 24 2012, 18:52
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(_Артём_ @ Apr 24 2012, 22:40)  Это чтож за ПРОЦЕСС с таким размером стека? В процессе вызываются функции обработки данных, в которых используются локальные крупные массивы. На самом деле памяти меньше съедается, я просто хочу понять принцип  Например, что произойдет, если я объявлю размер стека в процессе 10 кБ, а стек программы, как писалось выше, будет иметь размер не более 8 кБ? Цитата Может стек здесь и ни причём? Был у меня такой случай: задача копировала данные из кругового буфера в линейней для дальнейшей обработки. И в функции копирования была ошибка: функция начинала копировать из буфера ~64 кБ данных в линейный буфер и при этом переписывала всё ОЗУ. Через какое-то время происходил сброс (по WDT или как-то ещё). Может и ни при чем... Сторожевого таймера нет.
|
|
|
|
|
Apr 24 2012, 19:05
|
Гуру
     
Группа: Свой
Сообщений: 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 попадало?
|
|
|
|
|
Apr 24 2012, 19:28
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(_Артём_ @ Apr 24 2012, 23:05)  У вас внешняя память? Ага, к 8 кБ на кристалле еще 32 кБ снаружи. Цитата Стек программы - стек на котором работают прерывания и main до вызова OS::Run. Вы хотите сказать, что стек программы после запуска ОС не используется?  Кстати, мы ведь ради интереса можем взять адрес какой-нибудь локальной переменной, принадлежащей процессу. По адресу будет видно где она лежит... Цитата Стеки для процессов задаются индивидуально и их размеры никак не связаны друг с другом (лишбы памяти хватило и при этом всё работало). Об этом я знаю... я спрашивал как связан стек программы со стеками процессов... стеки процессов конечно не зависят друг от друга... Цитата Какой у вас компилятор IAR или GCC? GCC. Цитата Сейчас не помню точно был ли у меня включен WDT. Может и не был, но как оно тогда на reset попадало? Очень интересный вопрос, но для того, чтобы на резет попадало вотчдога не всегда нужно, нужен просто баг хороший
|
|
|
|
|
Apr 24 2012, 20:04
|
Гуру
     
Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322

|
Цитата(spongebob @ Apr 24 2012, 22:28)  Ага, к 8 кБ на кристалле еще 32 кБ снаружи. Интересно как скажется на производительности то, что стек расположен по внешней ОЗУ? Цитата(spongebob @ Apr 24 2012, 22:28)  Вы хотите сказать, что стек программы после запуска ОС не используется?  Если не ошибаюся, то возможны варианты: 1. В прерывании используется TISRW - прерывание работает на стеке прерванного процесса. 2. В прерывании используется TISRW_SS - прерывание использует стек выделенный для функции main. Цитата(spongebob @ Apr 24 2012, 22:28)  я спрашивал как связан стек программы со стеками процессов... стеки процессов конечно не зависят друг от друга... Да вроде никак не связан. Какая между ними связь может вообще быть? Цитата(spongebob @ Apr 24 2012, 22:28)  Очень интересный вопрос, но для того, чтобы на резет попадало вотчдога не всегда нужно, нужен просто баг хороший  Возможный вариант: моя функция копирования портила часть (или всё озу), но в конечном итоге делала ret. Но стек уже был заполнен непонятно чем. Програма была небольшая (10-15 кБ). И в результате возврат происходил в область заполненную FF. И программа могла дойти до адреса 0.
|
|
|
|
|
Apr 25 2012, 04:32
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 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 нет.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 25 2012, 05:57
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(ReAl @ Apr 25 2012, 08:32)  Стоило бы подумать о том, чтобі большие массивы не делать локальными, стеки разместить во внутреннем ОЗУ, а большие массивы — во внешнем. Ну как большие... около 300 байт. Несколько их (по одному в каждой вложенной функции), функций несколько... вот и набегает. Фактически, большая часть из этих массивов - временные, нужны иногда, поэтому было принято решение делать их локальными, чтобы они создавались на стеке (типа, память сэкономить). По поводу размещения... тут я совсем слаб... Делаем большие массивы глобальными и с помощью ключей компилятора (линкера) перемещаем секции data, bss во внешнюю память (-Wl,--section-start,.data=0x802200)? А как тогда разместить стеки процессов во внутреннем ОЗУ? Если процессов много, то хватит ли им 8 кБ внутреннего ОЗУ?
|
|
|
|
|
Apr 25 2012, 07:44
|

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

|
Цитата(ViKo @ Apr 25 2012, 13:25)  Если массивы временные, то почему бы не использовать один и тот же, глобальный, для разных целей? Только уже без ОС. А почему это вы думаете, что ОС запрещает использовать глобальные объекты?  Цитата(spongebob @ Apr 25 2012, 11:57)  Фактически, большая часть из этих массивов - временные, нужны иногда, поэтому было принято решение делать их локальными, чтобы они создавались на стеке (типа, память сэкономить). В scmRTOS 4.0 появился механизм для вычисления используемого каждым процессом стека (см. пример 4-Debug). Включите его, погоняйте. Узнаете, сколько чего и где. Может быть, всё спокойно влезет во внутреннее ОЗУ. Цитата(spongebob @ Apr 25 2012, 11:57)  По поводу размещения... тут я совсем слаб... Почитайте про линкерные скрипты. Примеры используемых avr-gcc скриптов находятся в lib\ldscripts.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 25 2012, 07:56
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 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
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Apr 25 2012, 08:24
|

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

|
Цитата(ViKo @ Apr 25 2012, 13:57)  Что это?  Мьютексы? Работа с массивами - дело долгое. От многозадачности мало что останется, пмсм. Да, мутексы. Тут ведь дело не в ОС/не ОС. А в логике работы. Если две разные задачи должны одновременно работать с одним массивом, то это проблемы в логике. Вероятнее, нужно так: одна задача готовит данные в массиве, вторая - обрабатывает. При таком подходе мутекс вполне оправдан - он позволяет второй задаче подождать, пока первая задача подготовит данные. А в случае топикстартера всё похоже ещё проще - с массивом работает одна задача. Просто массив надо вынести из стека задачи. В этом случае можно и без мутекса.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Apr 25 2012, 10:37
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(ViKo @ Apr 25 2012, 11:57)  Работа с массивами - дело долгое. От многозадачности мало что останется, пмсм. Фактически дело обстоит так. Имеется очередь (OS::channel) из элементов структур (в структуре массив 250 байт + еще несколько переменных). Один процесс кладет в очередь данные (команды) когда нужно, другой процесс - извлекает их и обрабатывает. Очередь нужна, чтобы "копить" команды, т. к., команды могут выполняться достаточно долго, а терять их очень нежелательно. Ну и чтобы поместить элемент в очередь (push) и извлечь его оттуда (pop) приходится заводить временный элемент (тип и размер - выше), который и отжирает стек. Сама очередь - глобальная. Ну, может, архитектура не совсем нормальная... посоветуйте, пожалуйста, как лучше  Цитата(AHTOXA @ Apr 25 2012, 12:24)  А в случае топикстартера всё похоже ещё проще - с массивом работает одна задача. Просто массив надо вынести из стека задачи. В этом случае можно и без мутекса. Да, с массивом работает одна задача. Но их как минимум два  Принцип действия следующий. Процесс 1 (главный, дает команды): команда -> функция подготовки команды и помещения ее в очередь (помещает данные в свой локальный буфер 1, а из него в очередь) -> очередь. Процесс 2 (подчиненный выполняет команды): функция извлечения команды из очереди в буфер 2 и обработки команды. Команды занимают приличный объем и имеют разный размер. Буферы 1 и 2 - одного типа, под все команды (универсальные). Проблема в том как поместить в очередь команду, не используя для этого промежуточный буфер 1. Цитата(ReAl @ Apr 25 2012, 11:56)  Не надо так. Не только стеки, все внутренние структуры scmRTOS полетят во внешнюю память. Вообще всё. С соответствующим замедлением. Во внутренней останется только «стек main()», который и использовать-то толком тяжело. Вот так вот изначально было сделано... фактически во внутренних 8 кБ остался только стек main(). Кстати, возвращаясь к вопросу об устройстве стеков при использовании ОС. После старта ОС стек main() не используется (планировщик при передаче управления заносит в указатель стека адрес стека требуемого процесса, который может быть расположен где угодно)? А почему стек main() использовать тяжело? Цитата Спасибо, почитаем. Как я понял, надо осваивать скриптописание для линкера?  В двух словах, создаем специальные секции, в которые по необходимости переносим некоторые переменные, а эти секции линкуются куда надо (в данном случае во внешнюю память)? Цитата(AHTOXA @ Apr 25 2012, 11:44)  В scmRTOS 4.0 появился механизм для вычисления используемого каждым процессом стека (см. пример 4-Debug). Включите его, погоняйте. Узнаете, сколько чего и где. Может быть, всё спокойно влезет во внутреннее ОЗУ. Очень интересно  Цитата Почитайте про линкерные скрипты. Примеры используемых avr-gcc скриптов находятся в lib\ldscripts. Спасибо, почитаем, главное - понять что там написано  Пока линкерные скрипты для меня страшны
|
|
|
|
|
Apr 25 2012, 14:56
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

|
Цитата(_Артём_ @ Apr 25 2012, 15:52)  Можно наверное в нём что-то расположить, используя указатели: адрес ведь известен. А, ну это да, можно... Цитата(AHTOXA @ Apr 25 2012, 16:59)  Дык, помещайте в очередь не сам буфер, а его номер  (Ну или как правильно сказал ViKo, указатель на него). Т. е., заводим большой массив (глобальный статический), который, к примеру, может вместить в себя 10 команд (размер данных каждой команды = размеру данных максимальной команды). Доступ к массиву между процессами разделяем с помощью мьютекса. Процесс 1 помещает команду в массив, указатель на команду в массиве помещает в очередь команд (она теперь маленькая по объему). Процесс 2 извлекает из очереди указатель на команду и по нему получает доступ к данным команды. Так? Но тогда придется как-то учитывать процессу 1, что в массиве по определенным адресам уже есть команды, чтобы не затереть ничего.
|
|
|
|
|
Apr 25 2012, 16:38
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Apr 26 2012, 05:12
|
Частый гость
 
Группа: Участник
Сообщений: 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 уже есть менеджер кучи и чем он отличается от выше Вами указанного?
|
|
|
|
|
Apr 26 2012, 07:16
|

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

|
Цитата(spongebob @ Apr 26 2012, 08:12)  Но как же мнение о том, что динамическая память для AVR - это слишком ресурсоемко и не выгодно? Опять мифы!!! Аналогичные мифы (применительно к МК) о C++, printf/scanf, RTOS и прочая циркулируют в эмбеддерской среде с пугающей живучестью. Подумайте над следующим. Чьи ресурсы занимаются? Контроллера или лично Ваши (рабочее время, деньги)? Ваши затраты будут единоразовыми и неизвестно в каком случае больше - применив кучу или изголяясь окольными путями. В случае контроллера, если он решает поставленную задачу и решает успешно, то какая Вам разница? Попробуйте лично и определитесь. PS Когда не устраивает библиотечный вариант какой-либо фичи, напишите или используйте кем-нибудь написанный готовый - облегчённый. Что касается варианта кучи, то Вам уже предложили или возьмите из второй версии scmRTOS.
|
|
|
|
|
Apr 26 2012, 07:28
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
Apr 26 2012, 09:04
|

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

|
Цитата(Сергей Борщ @ Apr 26 2012, 10:28)  В вашем случае менеджер можно упростить до предела, сделав его на базе кольцевого буфера. Выделение памяти двигает указатель головы, освобождение - указатель хвоста. Вы обещаете освобождать память строго в том же порядке, в котором она была выделена (а в случае вашей очереди это так и получается)... Вряд ли такую строго упорядоченную конструкцию можно назвать кучей. Скорее уж, действительно, кольцевой буфер. Тогда к чему лишние процедуры выделения, освобождения...? Я понимаю, работа с этими массивами идет постоянно. Вот и сделать их глобальными. Иметь некий индекс текущего рабочего буфера, им и манипулировать.
|
|
|
|
|
Apr 27 2012, 06:25
|
Частый гость
 
Группа: Участник
Сообщений: 126
Регистрация: 14-11-10
Пользователь №: 60 879

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

Гуру
     
Группа: Модераторы
Сообщений: 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ы?  Да.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Apr 28 2012, 17:00
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 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-ом ест меньше стека, чем яожидал :-) ).
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|