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

 
 
 
Reply to this topicStart new topic
> Измерение Загрузки CPU, ARM7, lpc2367
whiteTigr
сообщение Aug 10 2011, 09:36
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407



Захотел сделать измерение загрузки CPU.
Основная программа построена на прерываниях и работает с несколькими кнопками, сегментным индикатором и ком-портом.

Идея состоит в том, чтобы при начале любой (более-менее серъезной) процедуры стояло слово ImWorking, и заканчивалась процедура словом ImFinished.
Измеритель по этим словам выставляет тестовый диодик и считает сколько времени этот диодик простоял в высоком уровне (TimeInHighLevel).
Таймер в измерителе выдает прерывание раз в секунду, по которому значение TimeInHighLevel переписывается в буфер, доступный основной программе.

Вроде бы все получилось, но загрузка CPU, измеренная осцилографом, отличается от загрузки, измереной этим модулем.
Без оптимизации по осцилографу получается порядка 23% загрузки, модулем 24%. (вроде бы все нормально, списываем на погрешность)
С оптимизацией по времени выполнения получается: осцилограф - 13%, модуль 4%. (вот тут уже терзают сомнения)

И, так как я начинающий програмист, буду рад критике этого кода. sm.gif

Код
#include <LPC23xx.h>
#include "SystemMonitor.h"

// диодик
#define Work (1 << 1) // @ 1

#define PCTIM3  0x00800000; // 23

#define PCLK_TIMER3_OFFSET 14 // @ 1

#define INTTIM3 (1 << 27)

void Work_SET() { IOSET1 = Work; }
void Work_CLR() { IOCLR1 = Work; }

short WorkRefs = 0;

unsigned short CPUUsage = 0;

int TimeInHighLevel = 0;
int TimeSetHighLevel = 0;

__irq void Timer3Handler()
{
  if (WorkRefs > 0)  
    TimeInHighLevel += 10000 - TimeSetHighLevel;  

  CPUUsage = TimeInHighLevel;
  TimeInHighLevel = 0;
  TimeSetHighLevel = 0;

  T3IR = 0x01;
  VICVectAddr = 0;  
}

void InitSystemMonitor()
{
  TimeInHighLevel = 0;
  WorkRefs = 0;

  /* Initialize Timer 3 */  
  PCONP |= PCTIM3;

  PCLKSEL1 &= ~(3 << PCLK_TIMER3_OFFSET);
  PCLKSEL1 |=  (1 << PCLK_TIMER3_OFFSET);

  T3PR = 6399; // 100 mks  
  T3MR0 = 9999; // 1 s
  T3MCR = 3;

  VICIntEnClr = INTTIM3;
  VICVectAddr27 = (unsigned long)Timer3Handler;
  VICVectPriority27 = 15;  
  

  T3TCR = 0x01;

  VICIntEnable += INTTIM3;
}

void ImWorking()
{
  WorkRefs++;
  
  if (WorkRefs == 1)
  {
    Work_SET();
    TimeSetHighLevel = T3TC;
  }
}

void ImFinished()
{
  if (WorkRefs > 0)
    WorkRefs--;

  if (WorkRefs == 0)
  {
    TimeInHighLevel += T3TC - TimeSetHighLevel;
    Work_CLR();
  }
}
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Aug 10 2011, 10:43
Сообщение #2


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Если вы работаете с какой-то переменной и в основной программе и в прерывании (напр. TimeInHighLevel), то надо её как-то защищать, иначе возможны большие неприятности. Простейший вариант - запрещать прерывания на время обращения к переменной в основной программе.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
whiteTigr
сообщение Aug 10 2011, 10:51
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407



Цитата(AHTOXA @ Aug 10 2011, 14:43) *
Если вы работаете с какой-то переменной и в основной программе и в прерывании (напр. TimeInHighLevel), то надо её как-то защищать, иначе возможны большие неприятности. Простейший вариант - запрещать прерывания на время обращения к переменной в основной программе.


Неприятности, если в момент записи в переменную приходит прерывание (т.е. цепочка команд ассемблера разрывается прерыванием)? При возобновлении в регистре, который он хотел записать может оказаться мусор. Я правильно понимаю?
Go to the top of the page
 
+Quote Post
ar__systems
сообщение Aug 10 2011, 11:16
Сообщение #4


self made
****

Группа: Свой
Сообщений: 855
Регистрация: 7-03-09
Из: Toronto, Canada
Пользователь №: 45 795



Цитата(whiteTigr @ Aug 10 2011, 06:51) *
Неприятности, если в момент записи в переменную приходит прерывание (т.е. цепочка команд ассемблера разрывается прерыванием)? При возобновлении в регистре, который он хотел записать может оказаться мусор. Я правильно понимаю?

Сделайте проще. Два синхронно бегущих таймера, T3 & T2. В ImWorking пишите T3_START В ImFinished T3_STOP.

Раз в 1/4 секунды (измеренной с помощью T2) смотрите сколько накопилось в Т3, после чего его стираете.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Aug 10 2011, 11:17
Сообщение #5


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(whiteTigr @ Aug 10 2011, 16:51) *
Неприятности, если в момент записи в переменную приходит прерывание (т.е. цепочка команд ассемблера разрывается прерыванием)? При возобновлении в регистре, который он хотел записать может оказаться мусор. Я правильно понимаю?

Ну вот смотрите:
Код
    TimeInHighLevel += T3TC - TimeSetHighLevel;

Здесь происходит считывание значения переменной TimeInHighLevel в регистр, прибавление к нему какого-то значения и запись значения этого регистра в переменную TimeInHighLevel.
Теперь представьте, что после считывания, но перед записью возникло прерывание. А там вот что:
Код
  TimeInHighLevel = 0;

Получается, что это обнуление пропадает, ибо в переменную TimeInHighLevel тут же запишется старое значение TimeInHighLevel, увеличенное на T3TC - TimeSetHighLevel.
Вот так и возрастает подсчитанная загрузкаsm.gif


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
whiteTigr
сообщение Aug 10 2011, 12:02
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407



Цитата(AHTOXA @ Aug 10 2011, 15:17) *
Ну вот смотрите:
Код
    TimeInHighLevel += T3TC - TimeSetHighLevel;

Здесь происходит считывание значения переменной TimeInHighLevel в регистр, прибавление к нему какого-то значения и запись значения этого регистра в переменную TimeInHighLevel.
Теперь представьте, что после считывания, но перед записью возникло прерывание. А там вот что:
Код
  TimeInHighLevel = 0;

Получается, что это обнуление пропадает, ибо в переменную TimeInHighLevel тут же запишется старое значение TimeInHighLevel, увеличенное на T3TC - TimeSetHighLevel.
Вот так и возрастает подсчитанная загрузкаsm.gif


Угук, спасибо за разъяснение. sm.gif А то у меня только на подсознательному уровне из книжек отложилось, что нежелательно так делать, а вот до осмысления так и не дошло.

А как запретить прерывания на время записи переменной? И будут ли обработаны пришедшие за это время прерывания?

Ошибка в показаниях нашлась. Таймер был настроен на отсчет по 100 мкс, и получалось так, что без оптимизации длительность сигнлов была больше этого времени, а с оптимизацией слишком сильно сократилась и перестала считаться.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Aug 10 2011, 13:21
Сообщение #7


фанат дивана
******

Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Цитата(whiteTigr @ Aug 10 2011, 18:02) *
А как запретить прерывания на время записи переменной? И будут ли обработаны пришедшие за это время прерывания?

Зависит от используемого компилятора. Что-то типа disable_irq()/enable_irq().


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
kan35
сообщение Aug 10 2011, 19:37
Сообщение #8


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



А не проще ли использовать RTOS, в них чаще всего определение загрузки процессора уже заложено, можно даже по отдельным задачам все проанализировать. Например:
http://www.freertos.org/rtos-run-time-stats.html
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Aug 10 2011, 20:02
Сообщение #9


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(kan35 @ Aug 10 2011, 22:37) *
А не проще ли использовать RTOS...

А не проще ли, там, где ртос не нада, ея не использовать? sm.gif
В общем случае, нужен один таймер для отсчета интервала времени и одна переменная для хранения кол-ва тактов, с атомарным доступом для записи.
Далее - в суперпуперлупе вызываете функцию, которая ничего не делает, кроме того, что прибавляет число тактов на выполнение самой себя (это - из профайлера узнаем) к счетчику циклов.
По прерыванию таймера - получаем число "полезных" тактов как разность между числом тактов в заданном интервале и содержимым счетчика.
Самое правильное здесь в том, что мы считаем так и прерывания/исключения без особого напряга
Go to the top of the page
 
+Quote Post
whiteTigr
сообщение Aug 10 2011, 20:18
Сообщение #10


Участник
*

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407



Цитата(AHTOXA @ Aug 10 2011, 17:21) *
Зависит от используемого компилятора. Что-то типа disable_irq()/enable_irq().


Спасибо.

Цитата(kan35 @ Aug 10 2011, 23:37) *
А не проще ли использовать RTOS, в них чаще всего определение загрузки процессора уже заложено, можно даже по отдельным задачам все проанализировать. Например:
http://www.freertos.org/rtos-run-time-stats.html


Посмотрел на скриншот. ОС, судя по всему, откликается по веб-интерфейсу, которого в моей платке и в помине нет.

Идея то у меня банальная:
1) Обнаружить, если мы написали что-то страшное, и оно сожрало все процессорное время;
2) Потренироваться в программировании.

Завтра только допишу блокировку прерываний на время работы с переменной, и, я думаю, будет достаточно.
На последних тестах перед уходом домой показания осцилографа и модуля были примерно одинаковыми.
Go to the top of the page
 
+Quote Post
whiteTigr
сообщение Aug 11 2011, 07:39
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407



Нашел только такой вариант отключение прерываний:
Код
    VICIntEnClr = INTTIM3;
    TimeSetHighLevel = T3TC;
    VICIntEnable += INTTIM3;

Код
    VICIntEnClr = INTTIM3;
    TimeInHighLevel += T3TC - TimeSetHighLevel;    
    VICIntEnable += INTTIM3;


Как такой код отреагирует, если прерывание придет во время записи в переменные? Выполнится после разрешения прерывания, или проигнорируется?
Go to the top of the page
 
+Quote Post
toweroff
сообщение Aug 11 2011, 09:52
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 2 957
Регистрация: 19-09-06
Из: Москва
Пользователь №: 20 514



после
Код
VICIntEnClr = INTTIM3;

прерывание от таймера НЕ произойдет, посему присвоение значения переменной выполнится атомарно
после этого прерывание снова разрешается, но мавр дело уже сделал sm.gif
Если флаг прерывания выставлен во время операции присвоения, то после разрешения прерывания автоматом попадаем в обработку прерывания
Go to the top of the page
 
+Quote Post
whiteTigr
сообщение Aug 11 2011, 12:20
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 55
Регистрация: 25-07-11
Пользователь №: 66 407



Цитата(toweroff @ Aug 11 2011, 13:52) *
Если флаг прерывания выставлен во время операции присвоения, то после разрешения прерывания автоматом попадаем в обработку прерывания


Спасибо. sm.gif
Кажется, я стал немножко больше понимать механизмы работы arm'а.
А то, 2 недели назад, все это было темным лесом и непонятно было с какой стороны к этому зверю подойти. sm.gif
Go to the top of the page
 
+Quote Post
kan35
сообщение Aug 11 2011, 13:07
Сообщение #14


Знающий
****

Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594



Цитата(whiteTigr @ Aug 11 2011, 00:18) *
Посмотрел на скриншот. ОС, судя по всему, откликается по веб-интерфейсу, которого в моей платке и в помине нет.

Идея то у меня банальная:
1) Обнаружить, если мы написали что-то страшное, и оно сожрало все процессорное время;
2) Потренироваться в программировании.

выводить можно хоть как, хоть в компорт, если почитаете, там просто текстовый массив заполняется.
В общем там идея подсчета загрузки примерно такая же как и вы предложили, просто все это твориться без вашего ручного участия. Поделюсь своим опытом, в 100% своих проектов на АРМах я ставлю Ось, по моему иначе такой сильной машиной не реально управлять оптимально, выжимать из нее всю мощность. Отклонился от темы я..
Go to the top of the page
 
+Quote Post

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

 


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


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