Программирование ARM IAR: техники измерения времени выполнения кода STM32 Sat, March 28 2020  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

IAR: техники измерения времени выполнения кода STM32 Печать
Добавил(а) microsin   

Для встраиваемых систем критически важно контролировать время выполнения определенных участков кода, чтобы оно не превышало заданную величину. Время обработки может иметь решающее значение для приложения, и скорость вычислений может быть повышена за счет использования новых алгоритмов или применения специальных оптимизаций для особо критичных участков кода. На скорость выполнения также влияют опции компилятора. Однако перед тем, как попытаться улучшить производительность кода, может потребоваться измерить реальную скорость выполнения определенных участков кода.

Известна популярная техника измерения времени выполнения с помощью дергания ножкой GPIO и осциллографа, и это конечно достоверный и реалистичный метод. Однако можно измерить время выполнения кода с помощью других достаточно простых способов, основанных на функционале MCU и средств разработки. В этой статье описаны 3 базовые техники и некоторые более продвинутые методы измерения времени на платформах ARM Cortex-M3/M4 и IAR Embedded Workbench for ARM.

[Техника 1: использование Log Breakpoint]

Если Вам нужно только грубое измерение, то можно использовать точку останова вывода в лог (Log Breakpoint). Когда код достигнет установленной Log Breakpoint, в окне лога отладки (debug log) будет отображено текущее время компьютера. Свойства этого метода:

• Не требуется модификация исходного кода.
• Точность измерения времени 1 секунда.

Как разрешить log breakpoint: сделайте правый клик на строке кода, в которой нужно узнать время выполнения, и выберите пункт "Toggle Breakpoint (Log)".

IAR measuring elapsed time01

Установленная точка останова лога помечается в коде красным кружком с буквой "L":

IAR measuring elapsed time02

При достижении установленной точки в лог будет выводиться информация о текущем времени, имени файла исходного кода и его номере строки, где сработала Log Breakpoint, и счетчик срабатываний:

...
Mon Mar 23, 2020 10:47:37: Hardware reset with strategy 0 was performed 
Mon Mar 23, 2020 10:47:37: Target reset
Mon Mar 23, 2020 10:48:51: [USARTconsole.c:209.7] #0
Mon Mar 23, 2020 10:48:54: [USARTconsole.c:209.7] #1
Mon Mar 23, 2020 10:48:55: [USARTconsole.c:209.7] #2
Mon Mar 23, 2020 10:48:55: [USARTconsole.c:209.7] #3
Mon Mar 23, 2020 10:48:55: [USARTconsole.c:209.7] #4
Mon Mar 23, 2020 10:48:56: [USARTconsole.c:209.7] #5
Mon Mar 23, 2020 10:48:56: [USARTconsole.c:209.7] #6
Mon Mar 23, 2020 10:48:57: [USARTconsole.c:209.7] #7
Mon Mar 23, 2020 10:48:57: [USARTconsole.c:209.7] #8

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

[Техника 2: использование регистра CycleCount]

Современные MCU содержат в себе встроенный аппаратный регистр, который показывает количество прошедших тактов ядра. Ядра микроконтроллеров ARM Cortex-M3/4/7 предоставляют для этого регистр с именем CYCLECOUNTER (счетчик циклов).

Следует взять значение CYCLECOUNTER в двух местах кода, время выполнения которого нужно измерить. Затем, зная значение тактовой частоты CPU, Вы можете измерить реальное время выполнения кода. Например, если CPU работает на частоте 100 МГц, то можно полученное значение прошедших тактов поделить на 100000000, и в результате получится измеренное время в секундах. Особенности метода:

• Не требуется модификация кода.
• Точность измерения времени составляет 1 такт CPU.
• Поддержка метода зависит от применяемого MCU.

Для использования CYCLECOUNTER сделайте следующее:

1. Запустите сессию отладки и откройте окно просмотра регистров через меню View.

IAR measuring elapsed time04

2. В открывшемся окне просмотра регистров сделайте правый клик мышью, и выберите View Group -> CPU Registers (в некоторых версиях IAR нужно выбрать Current CPU Registers). Откроется окно, где будет показано значение CYCLECOUNTER, которое равно количеству тактов, которое прошло с момента запуска программы.

IAR measuring elapsed time06

3. Чтобы измерить время выполнения функции, сделайте на ней шаг отладчика без захода в тело функции (Step Over). Значение CCSTEP покажет разницу между началом выполнения шага и его завершением:

IAR measuring elapsed time07

424(текущий CYCLECOUNTER) – 416(предыдущий CYCLECOUNTER) = 8(текущий CCSTEP)

Счетчик CYCLECOUNTER предоставляется ARM Cortex-M3 MCU, однако он запрещен по умолчанию в IAR Embedded Workbench for ARM. Если Вы используете отладчик I-jet, то CYCLECOUNTER будет разрешен. Если у Вас другой отладчик, и CYCLECOUNTER не обновляется, то попробуйте установить бит CYCCNTENA в регистре DWT Control (DWT_CTRL.CYCCNTEN), который можно найти в группе регистров Data Watchpoint and Trace unit.

IAR measuring elapsed time08

CYCLECOUNTER прост в использовании, и дает точное измерение времени. Если нужно узнать время в секундах, то разделите количество прошедших тактов на тактовую частоту CPU. Имейте в виду, что CYCLECOUNTER может отличаться при разных измерениях из-за влияния конвейера команд (pipeline) или попаданий кэша. Метод не рекомендуется для измерения времени выполнения одной или двух инструкций, однако для на десятке или большем количестве инструкций можно получить более точные данные.

[Техника 3: использование таймера MCU]

Таймер это важная функциональная особенность MCU, предназначенная для периодического запуска процессов. Часто таймер используется для получения прерывания на считающем вверх или вниз счетчике таймера. Вы также можете измерить время в программе чтением значения счетчика таймера. Особенности этого метода:

• Необходима модификация исходного кода.
• Нужно сконфигурировать таймер.
• Код должен получить доступ к значению счетчика таймера.
• Значение времени можно получать как в единицах счета таймера, так и в количествах его переполнений.
• Конфигурация таймера может отличаться для каждого конкретного MCU, однако общий принцип измерения времени одинаковый.

Таймер MCU для измерения времени используют следующим образом. Сначала нужно определиться с источником тактирования таймера и его прескалером. Если прескалер 10, то через каждые 10 периодов тактовой частоты таймера он изменит свой счетчик на 1 вверх или вниз. Например, если частота тактирования таймера совпадает с частотой CPU 100 МГц, коэффициент прескалера 1000, то таймер изменяет свое значение с частотой 100000000/1000 = 100000 Гц, или каждые 0,00001 секунды (каждую 0.01 мс). Таким образом, если разница в значении счетчика в начале и конце измеряемого кода составляет 100, то время его выполнения составит 0.01 * 100 = 1 мс. Ниже показан пример кода, где измеряется время выполнения функции func():

unsigned int cnt1 = 0;
unsigned int cnt2 = 0;
 
cnt1 = TIM3->CNT;
func();
cnt2 = TIM3->CNT; 
printf("cnt1:%u cnt2:%u diff:%u \n",cnt1,cnt2,cnt2-cnt1);

Результат может выглядеть примерно так:

cnt1:370 cnt2:740 diff:370

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

Счетчик таймера SysTick процессора ARM Cortex-M останавливается, когда CPU не запущен. Это делает его полезным для измерения времени, особенно для ARM Cortex-M0/M0+ MCU, в котором не реализован регистр CYCLECOUNTER.

[Техника 4: использование Data Log breakpoint]

Data Log breakpoint - мощная функция отладки MCU ARM Cortex-M3 и Cortex-M4 devices. С отладчиками, которые поддерживают SWD/SWO, такими как I-jet, можно в реальном времени получать доступ к данным лога и меткам времени.

Перед запуском сессии отладки нужно настроить отладчик для SWD и SWO:

IAR measuring elapsed time09

IAR measuring elapsed time10

Пример кода:

static int data_main = 0;
static int data_systick = 0;
 
void Delay(Int32U Dly)
{
   for(volatile Int32U j = Dly; j; j--) { }
}
 
void SysTick_Handler(void)
{
   data_systick += 10;
}
 
void main(void)
{
   SystemInit();
   SysTick_Config(900000);
   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
   while(1)
   {
      Delay(100000);
      data_main++;
   }
}

В главном цикле функции main переменная data_main будет инкрементироваться с некоторыми интервалами времени (определяются функцией задержки Delay). Здесь также есть обработчик прерывания таймера SysTick, который инкрементирует переменную data_systick. Используя Data Log Breakpoint, можно просмотреть значения переменных и время доступа.

Data Log Breakpoint устанавливается следующим образом. Выполните правый клик на переменной data_main в редакторе кода, и выберите в контекстном меню Set Data Log Breakpoint for 'data_main'.

IAR measuring elapsed time11

Также Вы можете установить Data Log Breakpoint для data_systick:

IAR measuring elapsed time12

После этого запустите сессию отладки:

IAR measuring elapsed time13

Информацию по существующим точкам останова можно просмотреть выбором View -> Breakpoints.

IAR measuring elapsed time14

Вы увидите список установленных Data Log breakpoints.

IAR measuring elapsed time15

По умолчанию Data Log запрещен. Чтобы разрешить его, откройте окно Data Log (I-jet/JTAGjet -> Data Log).

IAR measuring elapsed time16

Сделайте правый клик в окне Data Log и выберите Enable.

IAR measuring elapsed time17

Запустите код в отладчике на выполнение. Когда программа будет обращаться к этим двум переменным, их значение и время обращения будет показано в окне Data Log.

IAR measuring elapsed time18

Время также может отображаться в тактах CPU.

IAR measuring elapsed time19

Если мы видим, что для 'data_main' W:12 и 'data_main' W:13 разница составляет 866768 тактов, то можно заключить, что время выполнения функции Delay(100000) составляет около 866768 тактов.

Изначально Data Log предназначен для трассировки доступа к данным. Однако на практике также его можно использовать и для измерения времени.

Имейте в виду:

• Переменные для Data Log Breakpoints должны иметь в памяти фиксированные адреса, т. е. это должны быть статические или глобальные переменные.
• Data Log не несет никаких дополнительных вычислительных затрат.
• Согласно спецификации ARM Cortex-M3/M4, можно установить максимум 4 экземпляра Data Log Breakpoints.

[Техника 5: использование Event Log]

Лог событий (Event Log) это еще одна функция отладки микроконтроллеров ARM Cortex-M3/M4. Вы можете добавить в свое приложение код события (event code), и каждый раз при выполнении этого кода будет генерироваться запись в Event Log.

Предыдущий пример, в котором изменено несколько строк:

#include < arm_itm.h>
 
static int data_main = 0;
static int data_systick = 0;
 
void Delay(Int32U Dly)
{
   for(volatile Int32U j = Dly; j; j--) { }
}
 
void SysTick_Handler(void)
{
   data_systick += 10;
   ITM_EVENT32_WITH_PC(2,data_systick);
}
 
void main(void)
{
   SystemInit();
   SysTick_Config(900000);
   SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
   while(1)
   {
      Delay(100000);
      data_main++;
      ITM_EVENT32_WITH_PC(1,data_main);
   }
}

Для генерации лога событий должен быть подключен заголовочный файл arm_itm.h. В нем определен макрос ITM_EVENT32_WITH_PC, у которого первый параметр это канал, а второй это данные. Данными могут быть константа или переменная, канал может быть от 1 до 4.

Чтобы увидеть Event Log в сессии отладки, откройте и разрешите окно Event Log.

IAR measuring elapsed time20

Сделайте правый клик в окне Event Log и выберите Enable.

IAR measuring elapsed time21

Теперь можно запустить приложение в отладчике, и увидеть данные лога событий.

IAR measuring elapsed time22

Данные канала 1 отображены в столбце ITM1, и данные канала 2 - в столбце ITM2. Также Вы можете увидеть метку времени в микросекундах (time stamp, столбец Time) и значение счетчика программы PC (столбец Program Counter), которые выводит в лог код макроса.

Также можно поменять отображаемое время в тактах CPU (Cycles).

IAR measuring elapsed time23

Время, прошедшее между ITM1 56 и ITM1 57 составляет 48541271 – 47674478 = 866793. Это значение почти такое же, как мы видели в окне Data Log.

Имейте в виду:

• Использование макроса событий (ITM event macro) вводит небольшую дополнительную нагрузку в виде кода и времени выполнения. Поэтому использование этого макроса уместно для не слишком малых интервалов времени (которые значительно больше времени выполнения макроса).
• В заголовочном файле arm_itm.h file имеются и другие макросы, такие как ITM_EVENT16_WITH_PC, ITM_EVENT16. Если Вам не нужна информация об адресе кода (не нужен столбец Program Counter), то для снижения нагрузки используйте макросы ITM_EVENT8, ITM_EVENT16, ITM_EVENT32.

Собранные данные можно сохранить в текстовый файл для последующего анализа.

[Просмотр Data Log и Event Log в окне Timeline]

Лог данных и событий можно просмотреть в окне шкалы времени Timeline, а одном и том же масштабе времени. Можно визуализировать, когда произошел каждый доступ к данным и когда произошло событие ITM, и узнать между ними разницу во времени. Для этого откройте окно I-jet/JTAGjet -> Timeline.

IAR measuring elapsed time24

Вы увидите несколько цветовых полос. Сделайте правый клик на область Data Log и область Events, и выберите Enable.

IAR measuring elapsed time25

Можно поменять шкалу времени в пункте Zoom контекстного меню (правый клик -> Zoom).

IAR measuring elapsed time26

Данные Data Log и данные ITM Event отобразятся графически, вместе с метками времени.

IAR measuring elapsed time27

При подведении курсора мыши к данным будет отображаться подробная информация о времени.

IAR measuring elapsed time28

Можно выбрать диапазон времени, и тогда будет отображена информация об этом диапазоне.

IAR measuring elapsed time29

Перед тем, как попытаться улучшить производительность кода, Вам следует настроить соответствующие средства измерения времени выполнения. Для измерения прошедшего времени существуют как традиционные техники, так и специфические для используемого MCU и отладчика. Вы можете адаптировать и улучшить техники, описанные в этой статье, чтобы они соответствовали требованиям отладки и разработки. См. также дополнительную информацию по описанному здесь функционалу в руководстве по отладке "C-SPY Debugging Guide", доступном в меню Help среды разработки IAR Embedded Workbench.

[Ссылки]

1. Techniques for measuring the elapsed time site:iar.com.

 

Добавить комментарий


Защитный код
Обновить

Top of Page