Как определить максимальное использование стека во встроенной системе с gcc? - PullRequest
37 голосов
/ 17 июня 2011

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

Мне сказали, что у компилятора gcc теперь есть опция -fstack-Использование и опция -fcallgraph-info, которые можно каким-то образом использовать для статического расчета точного «Максимального использования стека» для меня. ( «Анализ требований стека во время компиляции с помощью GCC» от Botcazou, Comar и Hainque).

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

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

Без обработчиков рекурсии или повторных входов должно быть возможно статически определить максимальное использование стека. (И поэтому большинство ответов на Как определить максимальное использование стека? не применимы). Насколько я понимаю, я (или, желательно, некоторый фрагмент кода на моем компьютере, который автоматически запускается каждый раз, когда я перестраиваю исполняемый файл) сначала нахожу максимальную глубину стека для каждого обработчика прерываний, когда он не прерывается прерыванием с более высоким приоритетом, и максимальный глубина стека функции main (), когда она не прерывается. Затем я добавляю их все, чтобы найти общую (в худшем случае) максимальную глубину стека. Это происходит (в моей встроенной системе), когда фоновая задача main () находится на своей максимальной глубине, когда она прерывается прерыванием с самым низким приоритетом, и это прерывание находится на своей максимальной глубине, когда оно прерывается следующим самым низким приоритетом. прерывание и т. д.

Я использую YAGARTO с gcc 4.6.0 для компиляции кода для LM3S1968 ARM Cortex-M3.

Итак, как мне использовать опцию -fstack-using и -fcallgraph-info с gcc для вычисления максимальной глубины стека? Или есть какой-то лучший подход для определения максимального использования стека?

(См. Как определить максимальное использование стека во встроенной системе? почти для того же вопроса, нацеленного на компилятор Keil.)

Ответы [ 5 ]

20 голосов
/ 17 июня 2011

GCC документы:

-fstack-использование

Создает для программы информацию об использовании выходного стека компилятора для каждой функции. Имя файла для дампа создается путем добавления .su к вспомогательному имени. auxname генерируется из имени выходного файла, если явно указано, и это не исполняемый файл, в противном случае это базовое имя исходного файла. Запись состоит из трех полей:

  • Название функции.
  • Количество байтов.
  • Один или несколько классификаторов: статические, динамические, ограниченные.

Классификатор static означает, что функция управляет стеком статически: фиксированное количество байтов выделяется для кадра при входе в функцию и освобождается при выходе из функции; никакие настройки стека не выполняются в функции. Второе поле - это фиксированное число байтов.

Определитель динамический означает, что функция динамически управляет стеком: в дополнение к статическому выделению, описанному выше, в теле функции выполняются корректировки стека, например, для выдвижения аргументов push / pop вокруг вызовов функции. Если ограничитель также присутствует, то количество этих настроек ограничено во время компиляции, а второе поле является верхней границей общего количества стека, используемого функцией. Если его нет, то количество этих настроек не ограничено во время компиляции, а второе поле представляет только ограниченную часть.

Я не могу найти ссылки на -fcallgraph-info

Вы можете потенциально создать необходимую информацию из -fstack-use и -fdump-tree-optimized

Для каждого листа в -fdump-tree-optimized получить его родителей и суммировать их размер размера стека (имея в виду, что это число лежит для любой функции с «динамической», но не «ограниченной») из -fstack-using, найдите максимальное из этих значений, и это должно быть вашим максимальным использованием стека.

12 голосов
/ 18 июня 2011

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

GCC 4.6 добавляет опцию -fstack-usage, которая предоставляет статистику использования стека для каждой функции.

Если вы объедините эту информацию с графом вызовов, созданным с помощью cflow или подобного инструмента, вы сможете получить необходимый вам анализ глубины стека (сценарий, вероятно, можно было бы написать довольно легко, чтобы сделать этот). Пусть скрипт прочитает информацию об использовании стека и загрузит карту имен функций вместе со стеком, используемым функцией. Затем пусть скрипт пройдется по графику cflow (который может быть легко анализируемым текстовым деревом), суммируя использование стека, связанное с каждой строкой, для каждой ветви в графе вызовов.

Итак, похоже, что это можно сделать с помощью GCC, но вам, возможно, придется собрать воедино правильный набор инструментов.

5 голосов
/ 20 мая 2016

В итоге я написал скрипт на python для реализации ответа . Здесь слишком много кода для размещения, но его можно найти на github

5 голосов
/ 28 сентября 2014

Довольно поздно, но для тех, кто смотрит на это, ответы, включающие объединение выходных данных инструментов fstack-using и графа вызовов, таких как cflow, могут оказаться в корне неверными для любого динамического распределения, даже ограниченного, потому что нет никакой информации о том, когдаэто динамическое распределение стека происходит.Поэтому невозможно узнать, к каким функциям следует применять значение.В качестве надуманного примера, если (упрощенный) результат использования fstack:

main        1024     dynamic,bounded
functionA    512     static
functionB     16     static

и очень простое дерево вызовов:

main
    functionA
    functionB

Наивный подход к их объединению может привести кmain -> functionA выбирается как путь максимального использования стека, в 1536 байтах.Но если наибольшее динамическое выделение стека в main () состоит в том, чтобы передать большой аргумент, такой как запись, в functionB () непосредственно в стек в условном блоке, который вызывает functionB (я уже говорил, что это было придумано), тогда действительно main ->functionB - путь максимального использования стека, в 1040 байтах.В зависимости от существующего программного обеспечения, а также от других более ограниченных целей, которые передают все в стек, накопительные ошибки могут быстро привести вас к поиску совершенно неправильных путей, требующих значительно завышенных максимальных размеров стека.

Кроме того, в зависимости от вашегоклассификация «реентерабельных», когда речь идет о прерываниях, можно полностью пропустить некоторые выделения стека.Например, прерывания уровня 7 многих процессоров Coldfire чувствительны к фронту и, следовательно, игнорируют маску блокировки прерываний, поэтому, если семафор используется для преждевременного выхода из инструкции, вы можете не считать ее повторной, но первоначальное выделение стека все же произойдет до того, каксемафор проверен.

Короче говоря, вы должны быть чрезвычайно осторожны при использовании этого подхода.

3 голосов
/ 17 июня 2011

Я не знаком с параметрами -fstack-usage и -fcallgraph-info.Тем не менее, всегда можно выяснить фактическое использование стека с помощью:

  1. Выделите достаточное пространство стека (для этого эксперимента) и инициализируйте его для чего-то, что можно легко идентифицировать.Мне нравится 0xee.
  2. Запустите приложение и протестируйте все его внутренние пути (по всем комбинациям ввода и параметров).Дайте ему поработать дольше, чем «достаточно долго».
  3. Изучите область стека и посмотрите, сколько стека было использовано.
  4. Сделайте размер стека плюс 10% или 20% ктерпеть обновления программного обеспечения и редкие условия.
...