Программирование ARM FreeRTOS: как получить информацию о загрузке процессора Thu, July 02 2020  

Поделиться

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

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

FreeRTOS: как получить информацию о загрузке процессора Печать
Добавил(а) microsin   

У FreeRTOS есть опционально активируемая возможность собирать информацию по затрачиваемому процессорному времени для каждой задачи. API-функция vTaskGetRunTimeStats() может представить эту информацию в виде текстовой таблицы.

usartTask       12148           < 1%
IDLE            4438565          97%
tcpip_thread    398             < 1%
lcdTask         956             < 1%
mbTCP           97562             2%
Tmr Svc         0               < 1%
canTask         4               < 1%
EthIf           44              < 1%

Информация выводится в 3 столбца. Первый столбец это имя задачи. Второй столбец показывает абсолютное время, которое использовала задача. Это условное "время", которое каждая задача потратила на обработку задачи (т. е. время, в течение которого задача находилась в состоянии Running). Единицы базового времени выбирает пользователь (по умолчанию длительность тика составляет 1 мс.), в зависимости от требований приложения. Третий столбец показывает статистику загрузки в более удобной и привычной форме - проценты от общего времени системы, которое было использовано каждой задачей.

[Настройка и использование]

Нужно в проекте определить 3 макроса, обычно это делается в файле FreeRTOSConfig.h.

1. configGENERATE_RUN_TIME_STATS

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

2. portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()

Для сбора статистики времени выполнения нужна база времени с более точным разрешением, чем прерывание тика. Иначе статистика может быть слишком неточной и в итоге бесполезной. Это реализуется настройкой отдельного таймера с прерыванием в несколько раз чаще, чем прерывание тика - рекомендуется частоту прерываний сделать в 10 или даже в 100 раз чаще, чем прерывание тика. Чем выше будет частота прерываний таймера статистики, тем точнее будет эта статистика. Однако слишком часто частоту прерываний делать не рекомендуется, потому что есть риск переполнения счетчиков статистики, и слишком нерационально будет расходоваться время CPU.

Если определен в 1 макрос configGENERATE_RUN_TIME_STATS, то ядро FreeRTOS будет автоматически вызывать portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() при запуске планировщика (т. е. внутри API-функции vTaskStartScheduler()). Разработчику приложения необходимо использовать макрос portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(), где должен быть соответствующий код настройки базы времени статистики, примеры см. далее.

3. portGET_RUN_TIME_COUNTER_VALUE()

Этот макрос просто должен возвратить текущее "время", как это было сконфигурировано в portCONFIGURE_TIMER_FOR_RUN_TIME_STATS(), см. примеры ниже.

Для получения захваченной статистики используется API-функция vTaskGetRunTimeStats().

4. В каком-нибудь модуле необходимо определить переменную ulHighFrequencyTimerTicks:

volatile unsigned long ulHighFrequencyTimerTicks;

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

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
extern volatile unsigned long ulHighFrequencyTimerTicks;
#endif

[Примеры]

В качестве примера см. демо-приложения LM3Sxxxx Eclipse [3] и LPC17xx LPCXpresso [4], где сконфигурирована генерация статистики времени выполнения задач.

В демо-приложении LM3Sxxxx Eclipse уже настроен тестовый таймер, прерывания которого срабатывают с частотой 20 кГц. Обработчик прерывания просто инкрементирует переменную ulHighFrequencyTimerTicks. По этой причине portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() просто устанавливает эту переменную в 0, и portGET_RUN_TIME_COUNTER_VALUE() возвращает это значение. Для реализации этого функционала в файл FreeRTOSConfig.h нужно добавить несколько строчек:

extern volatile unsigned long ulHighFrequencyTimerTicks;
/* ulHighFrequencyTimerTicks уже инкрементируется с частотой 20 кГц.
   Поэтому здесь эта переменная просто сбрасывается в 0. */
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ( ulHighFrequencyTimerTicks = 0UL )
#define portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks

В демо-приложении LPC17xx не настроен соответствующий таймер, поэтому в portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() был написан код, инициализирующий таймер 0 для генерации базы времени статистики. Макрос portGET_RUN_TIME_COUNTER_VALUE() просто возвращает текущее значение счетчика таймера 0.

/* Этот код определен в модуле main.c. */
void vConfigureTimerForRunTimeStats( void )
{
   const unsigned long TCR_COUNT_RESET = 2,
                    CTCR_CTM_TIMER = 0x00,
                    TCR_COUNT_ENABLE = 0x01;
 
   /* Активация интерфейса Timer 0 подачей на него тактов. */
   PCONP |= 0x02UL;
   PCLKSEL0 = (PCLKSEL0 & (~(0x3<<2))) | (0x01 << 2);
 
   /* Сброс Timer 0 */
   T0TCR = TCR_COUNT_RESET;
 
   /* Запускается счет вверх. */
   T0CTCR = CTCR_CTM_TIMER;
 
   /* Установка прескалера на частоту тактов, достаточной для
      получения необходимой разрешающей способности,
      без риска переполнения счетчика. */
   T0PR =  ( configCPU_CLOCK_HZ / 10000UL ) - 1UL;
 
   /* Запуск таймера. */
   T0TCR = TCR_COUNT_ENABLE;
}
 
/* Это определено в FreeRTOSConfig.h. */
extern void vConfigureTimerForRunTimeStats( void );
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() vConfigureTimerForRunTimeStats()
#define portGET_RUN_TIME_COUNTER_VALUE() T0TC

Это способ сбора статистики потребляет довольно мало процессорного времени - приблизительно 0.3% (процессор STM32F429, конфигурация проекта Release, тактовая частота ядра 168 МГц, время тика 1 мс, частота срабатывания таймера статистики 44.1 кГц).

[Оценка свободного времени процессора]

Если нужно только узнать, насколько загружен CPU всеми задачами, то есть еще один более простой способ, опубликованный в статье [2]. Он менее ресурсоемкий, не требует настройки дополнительного таймера и позволяет получить только информацию о свободном текущем свободном времени CPU (информация о потоках недоступна). Метод определение загруженности процессора основан на механизме CPU idle hook API FreeRTOS, реализованном в функции vApplicationIdleHook. Эта функция вызывается из бесконечного цикла потока IDLE, у которого самый низкий приоритет. Чтобы была доступна функция vApplicationIdleHook нужно определить в 1 макрос configUSE_IDLE_HOOK.

[Ссылки]

1. Run Time Statistics site:freertos.org.
2. FreeRTOS определяем среднюю загрузку ядра микропроцессора (CPU utilization) site:easyelectronics.ru.
3. FreeRTOS Stellaris Web Server Demo site:freertos.org.
4. NXP LPC1766 ARM Cortex-M3 demo site:freertos.org.

 

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


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

Top of Page