All streams
Search
Write a publication
Pull to refresh

Comments 23

Отличная идея! Только ведь стек не зануляется, когда мы выходим из подпрограммы ? Получается, что вы фиксируете максимальный уровень стека за все время наблюдений. Это отлично как аварийный критерий (например, можно переставать сбрасывать watchdog и вызывать перезагрузку контроллера - вместо продолжения работы с переполненным стеком и испорченными переменными). А вот если вы хотите соотнести использование стека с какими-то активностями - то вам надо понимать когда уровень воды в колодце опустился...

 Это отлично как аварийный критерий (например, можно переставать сбрасывать watchdog и вызывать перезагрузку контроллера - вместо продолжения работы с переполненным стеком и испорченными переменными).

Благодарю за идею. В самом деле.
Если стек переполнился, то лучше перезагрузиться.

Лучше не нули, а паттерн. Потому как какая-то функция сделает внутри себя

char myarray[100500] = {0};
strcpy(myarray, "hi");

т.е. по факту стек был съеден, но не использован. А был бы каким-то 0xDEADBEEF заполнен - было бы видно...

Лучше не нули, а паттерн. 

Да. Это хорошее замечание. Мне пока не сосем понятно, как на assembler прописать паттерн.

проще всего в стартап скрипте сделать заполнение диапазона стека перет отдачей управления в main...

Нужен пример ассемблерного кода.

Вместо "movs r3, #0" напишите "mov r3, #0xbeef", потом "movt r3, #0xdead".

Достаточно теперь прогнать модульные тесты, посмотреть на заполнения стека

можете пояснить этот момент? Обычно подобные тесты "крутятся" во framework-е, отличном от рабочей программы, и в тестах не будет повторения цепочки вызовов как в рабочем коде.

Для отладки потенциальных stackoverflow можно еще breakpoint на ячейку памяти поставить. На M0, если я правильно помню это можно только с помощью jtag-а

В программировании микроконтроллеров модульные тесты можно исполнять прямо внутри отладочной версии прошивки.

Прошивка тестирует сама себя изнутри.

у вас в продакшн коде присутствует код для тестирования? Или отключаете код тестирования в релизе?

у вас в продакшн коде присутствует код для тестирования?

нет

Или отключаете код тестирования в релизе?

да

да

ну тогда есть немаленькая вероятность, что замеры глубины стека будут не валидны

На этот случай в ARM Cortex-M есть MPU, который сгенерирует прерывание, если мы вывалимся за стек.

 и в тестах не будет повторения цепочки вызовов как в рабочем коде.

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

Во FreeRTOS эта раскраска уже реализована (сама проверка в функции prvTaskCheckFreeStackSpace, а получать результат можно через uxTaskGetSystemState). При этом если пользоваться FreeRTOS (или любой другой RTOS), то важен как раз стек в задачах, а стек для main который в задается LD файле не особо важен.

Это хорошо. В Zephyr RTOS тоже так.
Однако не всегда нужно использовать RTOS.
Вот в тестировочных прошивках RTOS не нужна. 

Э... глупый вопрос, а кто мешает просто посмотреть на значение регистра Stack Pointer, чтобы узнать, сколько места осталось в стеке?

Если вы это делаете в определенном месте (например, в главном цикле в main), то можете получать оттуда успокаивающие данные: стек почти не используется. А между этими замерами процедуры обработки прерываний, например, его переполняют. Самое неприятное - что никакой ошибки нет! Процедура прерывания загнала стек вверх, попортила чьи-то значения своими, благополучно отработала - и вернулась. А ошибка возникает позже, и в совершенно другом месте, не связанном логически с тем где реально переполнилось. А поскольку прерывания зависят от внешних источников - то оно может месяц нормально работать, а потом пошел звон по линии подключенного датчика - и вот процессор получает кучу прерываний по изменению уровня сигнала на ноге. А отваливается при этом индикация, или еще хуже - заменяются на случайные значения константы в pid-контроллере... А покраска стека хотя бы позволяет понять откуда ноги растут...

оно может месяц нормально работать, а потом пошел звон по линии подключенного датчика - и вот процессор получает кучу прерываний по изменению уровня сигнала на ноге

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

Хотя если в микроконтроллере есть штатные средства слежения за стеком (прерывание по определенному значению Stack Pointer), то лучше все-таки использовать их.

Это не штатные средства, а MPU, который еще надо сконфигурировать под стек.
MPU вообще всё равно есть стек или нет.

Полагаю, что речь не про MPU, а про МК на которых есть именно прерывание по определенному значению стек поинтера (вроде на PIC такое было) - это именно средство борьбы с переполнением стека. Удивительно, что в кортексах такого нет (хотя мб в более новых моделях появились, я уже не очень слежу).

Ну, раз уж вы сослались на мою статью - отмечусь :)

В целом, способ хороший, но тоже не всеобъемлющий (наверное, ни один из возможных сам по себе таковым не является); так как по сути проверка происходит периодически - то переполнение можно и пропустить, если оно вклинивается в этот период, в смысле, если это уже на финальном изделии выполняется. В этом плане MPU или "мой" хак с HardFault'ом полезнее, т.к. позволит само переполнение перехватить как только мы за границы стека вылезаем. И на этапе отладки это тоже может быть удобнее, когда отладчик просто останавливается ровно на той строке, которая слишком много стека отъедает.

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

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

Sign up to leave a comment.

Articles