реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Вычисление загрузки ядра микроконтроллера
elektronshik
сообщение Feb 13 2009, 07:25
Сообщение #1


Участник
*

Группа: Свой
Сообщений: 73
Регистрация: 25-10-07
Из: Тольятти
Пользователь №: 31 723



Имеются два камня с портами FreeRTOS (SAM9260 и STM32F103RB), в обоих крутятся по 5-10 задач. Необходимо с периодичностью ~1 с выводить (например в USART) загруженность ЦП с точностью 0.1-0.5%. Предполагаю что в vApplicationIdleHook нужно чего-нибудь сочинить... но не хотелось бы изобретать велосипед. А если еще вычислять по каждой задаче, вообще было бы здорово.

Сообщение отредактировал elektronshik - Feb 13 2009, 07:32
Go to the top of the page
 
+Quote Post
scifi
сообщение Feb 13 2009, 07:56
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Может быть, создать задачу с наименьшим приоритетом и считать, сколько времени программа в ней проводит?
Для подсчёта загрузки ЦП по задачам, судя по всему, нужно править FreeRTOS: зарядить таймер и при переключениях задач вести статистику.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Feb 13 2009, 08:08
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(scifi @ Feb 13 2009, 10:56) *
Может быть, создать задачу с наименьшим приоритетом и считать, сколько времени программа в ней проводит?
Это и есть готовая Idle задача - берите и пользуйтесь.
Цитата
Для подсчёта загрузки ЦП по задачам, судя по всему, нужно править FreeRTOS
Вообще-то как-бы нет, ибо макросы во все инетерсные места заложены - осталось только вписать в них нужное


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
elektronshik
сообщение Feb 13 2009, 08:22
Сообщение #4


Участник
*

Группа: Свой
Сообщений: 73
Регистрация: 25-10-07
Из: Тольятти
Пользователь №: 31 723



Цитата(zltigo @ Feb 13 2009, 11:08) *
Это и есть готовая Idle задача - берите и пользуйтесь.

Вот сам то-же самое хотел написать.. отвлекли. Собственно про vApplicationIdleHook я упоминал в вопросе чтоб залезть в Idle, а исходники самой оси при этом не править.

Дык помогите кто-нибудь по конкретнее (всмысле куском кода ). Не поверю что никто из читавших тему этого не делал.
Go to the top of the page
 
+Quote Post
KolyanV
сообщение Feb 14 2009, 11:27
Сообщение #5


Частый гость
**

Группа: Свой
Сообщений: 91
Регистрация: 1-06-05
Пользователь №: 5 621



Цитата(elektronshik @ Feb 13 2009, 10:22) *
Дык помогите кто-нибудь по конкретнее (всмысле куском кода ). Не поверю что никто из читавших тему этого не делал.


Пока без коментариев, нет времени. Позднее, если будет необходимо, могу прокоментировать.

Фрагмент FreeRTOS_stats.h
Код
#if FREERTOS_TASK_STATS
#define traceTASK_INCREMENT_TICK(xTickCount) TraceIncrementTick(xTickCount)
#define traceTASK_SWITCHED_OUT()   TraceSwitchedOut(pxCurrentTCB->uxTCBNumber, pxCurrentTCB)
#define traceTASK_SWITCHED_IN()    TraceSwitchedIn(pxCurrentTCB->uxTCBNumber)
#define traceTASK_DELETE(xTCB)     TraceTaskDelete(xTCB);

// Максимальное количество задач, для которых ведется статистика
#define MAX_TASK_STATS  15
// Период времени в тиках, на протяжении которого производится подсчет интервальной статистики
#define TIME_COUNTING_INTERVAL  1000
// Количество тиков PIT таймера на одно переполнение PIT таймера (т.е. на один тик системного таймера)
#define PIT_COUNTER_PERIOD  (( ( ( configCPU_CLOCK_HZ / 16 ) / 1000UL ) * (1000 / configTICK_RATE_HZ) ) + 1)

// ------------------------------------------------------------------------------
// Статистика активности задачи
struct STFRTaskStat
{ unsigned RunningST;          // Время работы задачи от момента старта (в системных тиках)
   unsigned RunningPT;          // Параметр уточняющий RunningST, значение в тиках PIT таймера (частота MCK/16)
   unsigned Switches;           // Количество переключений задачи от момента старта

   unsigned STLastInterval;     // Время работы задачи на предыдущем интервале измерения (в системных тиках)
   unsigned PTLastInterval;     // Параметр уточняющий STLastInterval, значение в тиках PIT таймера
   unsigned SwitchesLastInterval; // Количество переключений задачи на предыдущем интервале времени

   unsigned STCounter;          // Время работы задачи от момента tasks_start_intervalST (в системных тиках)
   unsigned PTCounter;          // Параметр уточняющий STCounter, значение в тиках PIT таймера
   unsigned SwitchesCounter;    // Количество переключений задачи от момента  StartTickCount

   unsigned TaskEnterST;        // Момент времени входа в задачу (в системных тиках)
   unsigned TaskEnterPT;        // Параметр уточняющий TaskEnterST, значение в тиках PIT таймера

   char pcTaskName[ configMAX_TASK_NAME_LEN ];  // Имя задачи
   void *xTask;                 // Дискриптор задачи
   unsigned  InitFlag;          // Флаг инициализации структуры ос статистикаой
};

#endif /* FREERTOS_TASK_STATS */


#if FREERTOS_STATS
// ------------------------------------------------------------------------------
// Структура описания статистики
struct STFRStat
{
#if FREERTOS_TASK_STATS
   struct STFRTaskStat tasks[MAX_TASK_STATS]; // Статистика задач
   unsigned tasks_start_intervalST;           // Момент начала интервала измерения (используется для вычисления STLastInterval)
#endif
};

extern struct STFRStat FreeRTOS_stats;

#endif /* FREERTOS_STATS */



Фрагемент FreeRTOS_stats.c
Код
// ver 1.02 (16.11.2008)
// Модуль предназначен для сбора, хранения и управления статистикой работы FreeRTOS
// и пользовательских задач в его окружении
// Также, модуль может выполнять контроль за переполнение стека задач

/* Library includes. */
#include <string.h>
#include <stdbool.h>

/* Hardware specific headers. */
#include "Board.h"
#include "AT91SAM7X256.h"

/* Scheduler includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "FreeRTOSConfig.h"

// Статистика FreeRTOS
#if FREERTOS_STATS
struct STFRStat FreeRTOS_stats;
#endif

// Счетчик тиков таймера
unsigned CurrentTickCount;

#if FREERTOS_TASK_STATS

// ------------------------------------------------------------------------------
// Функция вызывается системой FreeRTOS после обработки системного тика
inline void TraceIncrementTick(portTickType TickCount)
{ CurrentTickCount=TickCount;
}

// ------------------------------------------------------------------------------
// Функция вызывается системой FreeRTOS перед сменой планировщиком текущей задачи.
// Входные параметры:
// TaskNumber - номер задачи, которая прервана планировщиком
// hTask - дискриптор задачи (которая прервана планировщиком)
void TraceSwitchedOut(portBASE_TYPE TaskNumber, xTaskHandle xTask)
{ static unsigned PTPos;
   static unsigned PTOv;
   static long PTCount;
   static struct STFRTaskStat *TaskStat;

   if (TaskNumber< MAX_TASK_STATS)
     { // Запоминаем значение счетчика PIT таймера - параметра определяющего точное значение текущего времени
       PTPos=AT91C_BASE_PITC->PITC_PIIR;
       PTOv= (PTPos & AT91C_PITC_PICNT) >> 20;
       PTPos &= AT91C_PITC_CPIV;
       // Выделяем адрес структуры статистики текущей задачи (для увеличесния скорости доступа)
       TaskStat= &FreeRTOS_stats.tasks[TaskNumber];
       // Увеличесние счетчиков количества переключений задачи
       TaskStat->Switches++;
       TaskStat->SwitchesCounter++;
       // Если код выполняется впервые - инициализируем
       if (CurrentTickCount - TaskStat->TaskEnterST > 10)
         { TaskStat->TaskEnterST=CurrentTickCount;
           TaskStat->TaskEnterPT=PTPos;
         }
       // Определение точного времени выполнения задачи
       PTCount = (CurrentTickCount - TaskStat->TaskEnterST + PTOv) * PIT_COUNTER_PERIOD + (PTPos - TaskStat->TaskEnterPT);

       if (PTCount < 0)
         PTCount+=PIT_COUNTER_PERIOD;
       // Увеличение счетчиков времени выполнения задачи
       TaskStat->PTCounter+=PTCount;
       while (TaskStat->PTCounter >= PIT_COUNTER_PERIOD)
         { TaskStat->STCounter++;
           TaskStat->PTCounter -= PIT_COUNTER_PERIOD;
         }
       // Если задача вытесняется впервые - выполняем копирования имени задачи
       if (TaskStat->InitFlag==false)
         { TaskStat->xTask=xTask;
           TaskStat->InitFlag=true;
           memcpy(TaskStat->pcTaskName, (char *)((unsigned)xTask+52),16);
         }
       // Если необходимо - подсчитываем параметры времени выполнения задач за предыдущий интервал (если он завершен)
       if (CurrentTickCount - FreeRTOS_stats.tasks_start_intervalST >= TIME_COUNTING_INTERVAL)
         { for (int i=0;i < MAX_TASK_STATS; i++)
            { TaskStat=&FreeRTOS_stats.tasks[i];
              // Увеличение счетчика времени выполнения задачи
              TaskStat->RunningST += TaskStat->STCounter;
              TaskStat->RunningPT += TaskStat->PTCounter;
              while (TaskStat->RunningPT >= PIT_COUNTER_PERIOD)
                { TaskStat->RunningST++;
                  TaskStat->RunningPT -= PIT_COUNTER_PERIOD;
                }
              // Обновление данных о активности задачи за предыдущий интервал времени
              TaskStat->STLastInterval =  TaskStat->STCounter;
              TaskStat->PTLastInterval =  TaskStat->PTCounter;
              TaskStat->SwitchesLastInterval = TaskStat->SwitchesCounter;
              // Очистка текущих счетчиков
              TaskStat->STCounter=0;
              TaskStat->PTCounter=0;
              TaskStat->SwitchesCounter=0;
            }
           // Стартовая метка времени начинающегося интервала
           FreeRTOS_stats.tasks_start_intervalST=CurrentTickCount;
         }
     }
}

// ------------------------------------------------------------------------------
// Функция вызывается системой FreeRTOS после выбора планировщиком новой текущей задачи.
// Входные параметры:
// TaskNumber - номер задачи, которая сейчас будет запущена планировщиком
void TraceSwitchedIn(portBASE_TYPE TaskNumber)
{ if (TaskNumber< MAX_TASK_STATS)
     { FreeRTOS_stats.tasks[TaskNumber].TaskEnterST = CurrentTickCount;
       FreeRTOS_stats.tasks[TaskNumber].TaskEnterPT = (AT91C_BASE_PITC->PITC_PIIR) & AT91C_PITC_CPIV;
     }
}

// ------------------------------------------------------------------------------
// Функция вызывается системой при удалении задачи
// Входные параметры:
// xTCB - дискриптор удаляемой задачи
void TraceTaskDelete(xTaskHandle xTCB)
{ for (int i=0; i < MAX_TASK_STATS; i++)
     if (FreeRTOS_stats.tasks[i].xTask==xTCB)
       { FreeRTOS_stats.tasks[i].xTask=NULL;
         break;
       }
}

#endif /*  FREERTOS_TASK_STATS */
Go to the top of the page
 
+Quote Post
elektronshik
сообщение Feb 16 2009, 07:23
Сообщение #6


Участник
*

Группа: Свой
Сообщений: 73
Регистрация: 25-10-07
Из: Тольятти
Пользователь №: 31 723



KolyanV, спасибо Вам огромное, очень помогли! Жаль в stm32 это не будет работать, если SysTick-таймер используется как миллисекундный.
Go to the top of the page
 
+Quote Post
Faradey
сообщение Mar 3 2009, 22:23
Сообщение #7


Частый гость
**

Группа: Свой
Сообщений: 127
Регистрация: 31-05-06
Из: Belarus, Minsk
Пользователь №: 17 638



Цитата(elektronshik @ Feb 16 2009, 09:23) *
KolyanV, спасибо Вам огромное, очень помогли! Жаль в stm32 это не будет работать, если SysTick-таймер используется как миллисекундный.


Не вижу проблем для использования в интересуемом вас STM32F103RB, тем более что systick используется для тика FreeRTOS и его частота у вас равна 1 кГц
Для получения времени в интервале systick необходимо воспользовать одним из доступных аппаратных таймеров, например TIM2.
Настройте его на частоту 1 МГц без прерываний, в ф-ции TraceIncrementTick - обнуляете его а в TraceSwitchedOut читаете.
Таким образом вы получите "точность" в мксек. более чем достаточно.


--------------------
Завтра пойму, что нужно было сделать вчера...
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 5th July 2025 - 11:56
Рейтинг@Mail.ru


Страница сгенерированна за 0.01421 секунд с 7
ELECTRONIX ©2004-2016