Pull to refresh

Comments 22

А почему бы не сделать профилирование методом дебаггера, просто выплёвывая в комп или через jtag, или через SWO регистр SP?
Если добавить ещё и PC то получим привязку к месту, откуда пришли данные по стеку.
А у тулчейна есть тулза, которая значение PC превращает в file:line
Подробнее про SWO можно почитать у sigrok
www.sigrok.org/blog/new-protocol-decoders-arm-tpiu-itm-etmv3
Это принципиально не отличается от окраски памяти из первой статьи — мы не делаем профилирование как таковое, мы экспериментально определяем, что вроде бы за разумное время в разумных условиях стек не отжирает больше, чем мы предполагали по методу научного тыка.
Принципиальное отличие в том, что мы не меняем полезного исходного кода и не добавляем ненужных для функционирования устройства действий в полученную прошивку.
В случае использования RTOS эти функции обычно уже есть в ней, в голых прошивках — никого же не удивляет, что есть debug-сборка и release-сборка.
В случае использования RTOS есть ещё и инструменты работы с ядром через TPI на стороне компа, что упрощает жизнь значительно.
А если нет RTOS, то и debug-сборка как правило не нужна. Задачи или очень простые, или с критичными к времени исполнения секциями, для которых профилирование debug кода, как и игра с флагами оптимизации компилятора, крайне нежелательна. Разве что ASSERTы.
Почти во всех. У STM32, которые в заголовке, присутствуют во всех моделях, с которыми мне приходилось работать.
Сейчас я открою Вам информацию, доступную только избранным.
Не во все ядра Cortex-M входит TPI.
Таки отличается — этот метод позволяет сначала построить с помощью статического анализатора дерево вызовов, а потом, например при помощи обработчика прерываний таймера с (псевдо)случайным интервалом, который определяет цепочку вложенности вызовов для контекста в котором произошло прерывание, и сохраняет SP — диапазон объёма использования стека для большинства из узлов этого дерева. После этого можно заполнить оставшиеся узлы на основе оценки максимального использования стека из компилятора, добавить к максимальным значениям оценку для прерываний — и получить полную потребность в памяти для стека. Преимущество этого метода перед чисто экспериментальным в том, что можно убедиться, что этой оценкой покрыто по крайней мере всё дерево вызовов. Есть нюансы с переменным объёмом стэка внутри функций, и с несколькими вызовами одной и той же функции из разных мест другой функции, но это тоже можно учесть.
С прерываниями на самом деле все гораздо проще — на каждом уровне приоритетов находится обработчик с максимальной глубиной стека а затем эти цифры суммируются для всех уровней.
Это даст оценку сверху. На практике и прерывания могут не всегда накладываться просто в силу особенностей реализации железа и/или маскирования прерываний в рантайме, а в совсем плохом случае — их приоритет меняться в рантайме по ситуации.
А зачем вам оценка «не сверху»? Вам надо гарантировать непереполнение — значит базироваться на физической возможности процессора выстроить цепь из вложенных на всех уровнях прерываний. Иначе все ваши рассуждения про главный цикл можно вести в этом же ключе — «а что если там в реальности тоже не вызывается цепь событий с максимальной глубиной»…

На практике если у вас приоритет прерываний меняется в рантайме — то это плохая не годная архитектура. (маскирование то понятно, что может применяться для синхронизации доступа к разделяемым ресурсам — но это никому не интересно в рамках проблемы размера стека).
Кстати, этот метод профилирования есть в IAR (как минимум, в IAR AVR, ARM'овским пользоваться не приходилось). Просто галка где-то в недрах настроек, которая добавляет в map-файл несколько строчек: main использует столько-то, прерывание A — столько-то, прерывание B — столько. Считалась максимальная глубина вызовов. Указатели он не умеет анализировать, складывать стеки прерываний тоже надо вручную. Работает быстро, т.к. анализ бинарников идёт без особых проблем.

Кстати-2, для gcc есть утилита, которая строит дерево вызовов по объектникам: mcuoneclipse.com/2015/08/21/gnu-static-stack-usage-analysis
Оно, правда, без костылей не умеет c++.
Настройки проекта — Linker — Advanced — Enable stack usage analysis. Плюс надо еще указать явно все обработчики прерываний (всё, что неявно вызывается, вроде как). Очень полезная вещь, да еще и из коробки!
Писал для себя похожую утилитку для анализа памяти под потоки ChibiOS на STM32 — github.com/Confucij/sudan
Она использует другую утилитку egypt и выдает граф выызовов функций и глубину стека на каждом уровне
Немного оффтоп: можете посоветовать утилиту для анализа не памяти, а команд и тактов на их выполнение? Временами код в прерываниях «толстоват», хотелось бы построить диаграмму таймингов, чтобы быть уверенным, что код в прерывании выполнится до наступления следующего события.
Не знаю такой.

Я обычно тайминги конкурирующих процессов смотрю осциллографом или анализатором, вытащив их начало/конец на свободные ножки — очень наглядно получается.
Хотелось бы без отладки по пину, а статически. Поскольку я сварщик не настоящий, осциллограф у меня вельми хреновый, подобранный списанный.
Вроде и написать не сложно, но лень возиться с несколькими системами команд.
На Cortex-M можно запрашивать показания Program Counter через ITM и строить flame graph, например. Так можно понять, какой процент времени ядро тратит в каких местах кода.
спасибо, этого не знал. Просто немного удивительно: есть ассемблерный листинг, есть данные по системе команд (AVR и ARM всё-таки не страшный и непредсказуемый х86), а статического анализатора нет.
В IAR'е для этого достаточно остановиться по точке останова в начале нужного фрагмента, в окне Register выбрать Data Watchpoint and Trace macrocel, в регистре DWT_CTRL установить CYCCNENA=1, и, шагая по коду, наблюдать изменение DWT_CYCCNT.
Для эклипса есть замечательный плагин freescale.com/lgfiles/updates/Eclipse/KDS
выдает по задачам и куче полную инфу только повозится с настройками надо и freeros 10 использовать
Sign up to leave a comment.

Articles