Comments 23
Отличная идея! Только ведь стек не зануляется, когда мы выходим из подпрограммы ? Получается, что вы фиксируете максимальный уровень стека за все время наблюдений. Это отлично как аварийный критерий (например, можно переставать сбрасывать watchdog и вызывать перезагрузку контроллера - вместо продолжения работы с переполненным стеком и испорченными переменными). А вот если вы хотите соотнести использование стека с какими-то активностями - то вам надо понимать когда уровень воды в колодце опустился...
Лучше не нули, а паттерн. Потому как какая-то функция сделает внутри себя
char myarray[100500] = {0};
strcpy(myarray, "hi");
т.е. по факту стек был съеден, но не использован. А был бы каким-то 0xDEADBEEF заполнен - было бы видно...
Достаточно теперь прогнать модульные тесты, посмотреть на заполнения стека
можете пояснить этот момент? Обычно подобные тесты "крутятся" во framework-е, отличном от рабочей программы, и в тестах не будет повторения цепочки вызовов как в рабочем коде.
Для отладки потенциальных stackoverflow можно еще breakpoint на ячейку памяти поставить. На M0, если я правильно помню это можно только с помощью jtag-а
В программировании микроконтроллеров модульные тесты можно исполнять прямо внутри отладочной версии прошивки.
Прошивка тестирует сама себя изнутри.
и в тестах не будет повторения цепочки вызовов как в рабочем коде.
Глубина заполнения стека зачастую зависит от того какие входные данные поступают в прошивку по мере ее работы.
можете пояснить этот момент?
Модульное Тестирование в Embedded
https://habr.com/ru/articles/698092/
Во FreeRTOS эта раскраска уже реализована (сама проверка в функции prvTaskCheckFreeStackSpace, а получать результат можно через uxTaskGetSystemState). При этом если пользоваться FreeRTOS (или любой другой RTOS), то важен как раз стек в задачах, а стек для main который в задается LD файле не особо важен.
Э... глупый вопрос, а кто мешает просто посмотреть на значение регистра Stack Pointer, чтобы узнать, сколько места осталось в стеке?
Если вы это делаете в определенном месте (например, в главном цикле в main), то можете получать оттуда успокаивающие данные: стек почти не используется. А между этими замерами процедуры обработки прерываний, например, его переполняют. Самое неприятное - что никакой ошибки нет! Процедура прерывания загнала стек вверх, попортила чьи-то значения своими, благополучно отработала - и вернулась. А ошибка возникает позже, и в совершенно другом месте, не связанном логически с тем где реально переполнилось. А поскольку прерывания зависят от внешних источников - то оно может месяц нормально работать, а потом пошел звон по линии подключенного датчика - и вот процессор получает кучу прерываний по изменению уровня сигнала на ноге. А отваливается при этом индикация, или еще хуже - заменяются на случайные значения константы в pid-контроллере... А покраска стека хотя бы позволяет понять откуда ноги растут...
оно может месяц нормально работать, а потом пошел звон по линии подключенного датчика - и вот процессор получает кучу прерываний по изменению уровня сигнала на ноге
В этой ситуации и раскраска стека будет месяц показывать, что все нормально. Но да, согласен, она позволит надежно измерить пиковое заполнение стека. Хотя если в микроконтроллере есть штатные средства слежения за стеком (прерывание по определенному значению Stack Pointer), то лучше все-таки использовать их.
Хотя если в микроконтроллере есть штатные средства слежения за стеком (прерывание по определенному значению Stack Pointer), то лучше все-таки использовать их.
Это не штатные средства, а MPU, который еще надо сконфигурировать под стек.
MPU вообще всё равно есть стек или нет.
Ну, раз уж вы сослались на мою статью - отмечусь :)
В целом, способ хороший, но тоже не всеобъемлющий (наверное, ни один из возможных сам по себе таковым не является); так как по сути проверка происходит периодически - то переполнение можно и пропустить, если оно вклинивается в этот период, в смысле, если это уже на финальном изделии выполняется. В этом плане MPU или "мой" хак с HardFault'ом полезнее, т.к. позволит само переполнение перехватить как только мы за границы стека вылезаем. И на этапе отладки это тоже может быть удобнее, когда отладчик просто останавливается ровно на той строке, которая слишком много стека отъедает.
С другой стороны, ваш подход позволяет и статистику собрать и максимум за какое-то время оценить (хоть и не совсем бесплатно). Так что эти подходы друг другу не противоречат, а скорее дополняют друг друга.
Еще из поста не совсем понятно, как вы оценивали сложность разных подходов; на мой взгляд они все достаточно простые - особенно если не делать их с нуля, а брать готовые шаблоны.
Покраска Cтека (Stack Painting)