|
Измерение Загрузки CPU, ARM7, lpc2367 |
|
|
|
Aug 10 2011, 09:36
|
Участник

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

|
Захотел сделать измерение загрузки CPU. Основная программа построена на прерываниях и работает с несколькими кнопками, сегментным индикатором и ком-портом. Идея состоит в том, чтобы при начале любой (более-менее серъезной) процедуры стояло слово ImWorking, и заканчивалась процедура словом ImFinished. Измеритель по этим словам выставляет тестовый диодик и считает сколько времени этот диодик простоял в высоком уровне (TimeInHighLevel). Таймер в измерителе выдает прерывание раз в секунду, по которому значение TimeInHighLevel переписывается в буфер, доступный основной программе. Вроде бы все получилось, но загрузка CPU, измеренная осцилографом, отличается от загрузки, измереной этим модулем. Без оптимизации по осцилографу получается порядка 23% загрузки, модулем 24%. (вроде бы все нормально, списываем на погрешность) С оптимизацией по времени выполнения получается: осцилограф - 13%, модуль 4%. (вот тут уже терзают сомнения) И, так как я начинающий програмист, буду рад критике этого кода.  Код #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(); } }
|
|
|
|
|
 |
Ответов
|
Aug 10 2011, 10:51
|
Участник

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

|
Цитата(AHTOXA @ Aug 10 2011, 14:43)  Если вы работаете с какой-то переменной и в основной программе и в прерывании (напр. TimeInHighLevel), то надо её как-то защищать, иначе возможны большие неприятности. Простейший вариант - запрещать прерывания на время обращения к переменной в основной программе. Неприятности, если в момент записи в переменную приходит прерывание (т.е. цепочка команд ассемблера разрывается прерыванием)? При возобновлении в регистре, который он хотел записать может оказаться мусор. Я правильно понимаю?
|
|
|
|
|
Aug 10 2011, 11:17
|

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

|
Цитата(whiteTigr @ Aug 10 2011, 16:51)  Неприятности, если в момент записи в переменную приходит прерывание (т.е. цепочка команд ассемблера разрывается прерыванием)? При возобновлении в регистре, который он хотел записать может оказаться мусор. Я правильно понимаю? Ну вот смотрите: Код TimeInHighLevel += T3TC - TimeSetHighLevel; Здесь происходит считывание значения переменной TimeInHighLevel в регистр, прибавление к нему какого-то значения и запись значения этого регистра в переменную TimeInHighLevel. Теперь представьте, что после считывания, но перед записью возникло прерывание. А там вот что: Код TimeInHighLevel = 0; Получается, что это обнуление пропадает, ибо в переменную TimeInHighLevel тут же запишется старое значение TimeInHighLevel, увеличенное на T3TC - TimeSetHighLevel. Вот так и возрастает подсчитанная загрузка
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 10 2011, 12:02
|
Участник

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

|
Цитата(AHTOXA @ Aug 10 2011, 15:17)  Ну вот смотрите: Код TimeInHighLevel += T3TC - TimeSetHighLevel; Здесь происходит считывание значения переменной TimeInHighLevel в регистр, прибавление к нему какого-то значения и запись значения этого регистра в переменную TimeInHighLevel. Теперь представьте, что после считывания, но перед записью возникло прерывание. А там вот что: Код TimeInHighLevel = 0; Получается, что это обнуление пропадает, ибо в переменную TimeInHighLevel тут же запишется старое значение TimeInHighLevel, увеличенное на T3TC - TimeSetHighLevel. Вот так и возрастает подсчитанная загрузка  Угук, спасибо за разъяснение.  А то у меня только на подсознательному уровне из книжек отложилось, что нежелательно так делать, а вот до осмысления так и не дошло. А как запретить прерывания на время записи переменной? И будут ли обработаны пришедшие за это время прерывания? Ошибка в показаниях нашлась. Таймер был настроен на отсчет по 100 мкс, и получалось так, что без оптимизации длительность сигнлов была больше этого времени, а с оптимизацией слишком сильно сократилась и перестала считаться.
|
|
|
|
|
Aug 10 2011, 20:18
|
Участник

Группа: Участник
Сообщений: 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) Потренироваться в программировании. Завтра только допишу блокировку прерываний на время работы с переменной, и, я думаю, будет достаточно. На последних тестах перед уходом домой показания осцилографа и модуля были примерно одинаковыми.
|
|
|
|
|
Aug 11 2011, 13:07
|
Знающий
   
Группа: Участник
Сообщений: 537
Регистрация: 22-02-06
Пользователь №: 14 594

|
Цитата(whiteTigr @ Aug 11 2011, 00:18)  Посмотрел на скриншот. ОС, судя по всему, откликается по веб-интерфейсу, которого в моей платке и в помине нет.
Идея то у меня банальная: 1) Обнаружить, если мы написали что-то страшное, и оно сожрало все процессорное время; 2) Потренироваться в программировании. выводить можно хоть как, хоть в компорт, если почитаете, там просто текстовый массив заполняется. В общем там идея подсчета загрузки примерно такая же как и вы предложили, просто все это твориться без вашего ручного участия. Поделюсь своим опытом, в 100% своих проектов на АРМах я ставлю Ось, по моему иначе такой сильной машиной не реально управлять оптимально, выжимать из нее всю мощность. Отклонился от темы я..
|
|
|
|
Сообщений в этой теме
whiteTigr Измерение Загрузки CPU Aug 10 2011, 09:36  ar__systems Цитата(whiteTigr @ Aug 10 2011, 06:51) Не... Aug 10 2011, 11:16     kan35 А не проще ли использовать RTOS, в них чаще всего ... Aug 10 2011, 19:37      _Pasha Цитата(kan35 @ Aug 10 2011, 22:37) А не п... Aug 10 2011, 20:02 whiteTigr Нашел только такой вариант отключение прерываний:
... Aug 11 2011, 07:39 toweroff после
КодVICIntEnClr = INTTIM3;
прерывание от тай... Aug 11 2011, 09:52 whiteTigr Цитата(toweroff @ Aug 11 2011, 13:52) Есл... Aug 11 2011, 12:20
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|