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

Поделиться

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

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите 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%

void vTaskGetRunTimeStats (char *pcWriteBuffer);

Функция напечатает в консоль информацию по потокам в виде таблицы.

Чтобы эта функция была доступна, должны быть определены в 1 макросы конфигурации configGENERATE_RUN_TIME_STATS, configUSE_STATS_FORMATTING_FUNCTIONS и configSUPPORT_DYNAMIC_ALLOCATION (в файле FreeRTOSConfig.h).

Также приложение должно предоставить определения для макросов portCONFIGURE_TIMER_FOR_RUN_TIME_STATS (чтобы сконфигурировать периферийное устройство таймера/счетчика, используемого для отсчета реального времени) и portGET_RUN_TIME_COUNTER_VALUE (для возврата текущего значения этого счетчика). Этот счетчик должен инкрементироваться как минимум в 10 раз за 1 инкремент тика FreeRTOS.

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

Функция vTaskGetRunTimeStats() вызовет uxTaskGetSystemState(), затем отформатирует сырые данные, которые сгенерировала uxTaskGetSystemState() в удобочитаемую для человека таблицу в виде текста ASCII. В этой таблице будет показано количество времени, которое каждая задача проводит в состоянии Running (т. е. сколько времени CPU каждая задача потребляет). Данные представлены как в абсолютном, так и в процентном выражении. Разрешающая способность в абсолютных значениях зависит от частоты сбора статистики времени выполнения, которую предоставило приложение (т. е. от частоты инкрементирования счетчика, сконфигурированного в portCONFIGURE_TIMER_FOR_RUN_TIME_STATS).

Функция vTaskGetRunTimeStats() эта просто утилита, предоставленная только для удобства. Она не считается частью ядра FreeRTOS. См. также описание функции vTaskList(), которая генерирует информацию о состоянии каждой задачи.

Параметр:

pcWriteBuffer Указатель на текстовый буфер, куда будет записана информация о статистике времени выполнения потоков. Подразумевается, что этот буфер достаточно большой, чтобы содержать сгенерированный отчет. Должно быть достаточным примерно 40 байт на одну задачу.

Информация выводится в 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

Boffalo SDK позволяет использовать FreeRTOS для чипов TG7100C (аналог BL602), BL602, BL604, BL606P, BL616, BL618, BL702, BL706. Как запустить отображение статистики по потокам:

1. В любом модуле приложения (например в main.c) добавьте глобальную переменную для счетчика реального времени:

volatile uint64_t timecnt;

2. В FreeRTOSConfig.h добавьте строчки:

#define configGENERATE_RUN_TIME_STATS 1
 
extern volatile uint64_t timecnt;
 
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() ( /*ulHighFrequencyTimerTicks*/timecnt = 0UL )
#define portGET_RUN_TIME_COUNTER_VALUE() pGRTCV()
 
uint32_t bl_timer_now_us(void);
 
inline uint32_t pGRTCV (void)
{
   timecnt = bl_timer_now_us();
   return timecnt;
}

3. В начале main.c:

timecnt uint32_t timecnt;
time_main = bl_timer_now_us();

После этого статистику по потокам можно получать с помощью вот такого кода:

char runtimestats[40*10]; 
 
vTaskGetRunTimeStats(runtimestats);
log_info("\r\n%s\r\n", runtimestats);

Пример отображения статистики в отладочной консоли UART0:

[     12812][WARN  : main.c: 839]
test_task       7460            < 1%
IDLE            10735465        82%
TCP/IP          26636           < 1%
Tmr Svc         202801          1%
hello_task      42770           < 1%
event_loop      592677          4%
wifi_mgmr       43376           < 1%
fw              1360216         10%
bloop_rt        56              < 1%

Этот способ сбора статистики потребляет довольно мало процессорного времени - приблизительно 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.
5. FreeRTOS vTaskList.

 

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


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

Top of Page