|
|
  |
Бездействие системы - как измерить?, Мерялка занятости процессора |
|
|
|
Aug 12 2010, 01:48
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(sergeeff @ Aug 11 2010, 23:56)  Так все таймеры в процессоре только на это дело и уйдут. Как то не рационально. Может помозговать и обойтись системным таймером тиков? Нет, зачем, таймеры будут софтовые, на базе одного 32-ух битного аппаратного таймера их можно наплодить сотни. Разрешения в 1 мкс я думаю хватит. Сегодня после работы попробую, что получится. Никто не реализовывал подобную фичу под этой ОС?
|
|
|
|
|
Aug 12 2010, 03:51
|

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

|
Цитата(sonycman @ Aug 12 2010, 07:48)  Сегодня после работы попробую, что получится. Никто не реализовывал подобную фичу под этой ОС? Раз все молчат, то, видимо, никто  Обсуждали, в контексте путей дальнейшего развития, и на этом пока все  Попробуйте конечно, очень интересно. ЗЫ. Я приблизительно измеряю загрузку STM32 по потребляемому току. Вставил в IdleProcessUserHook() вызов __WFI();, и контроллер у меня спит, когда он в Idle. ( Но зацепиться JTAG-ом к спящему контроллеру - это тот ещё ребус  )
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Aug 13 2010, 01:51
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Сделал вчера измерение по описанной методике - всё работает практически как часы  Попробую немного соптимизировать - использовать вместо двух таймеров один - системный SysTick. И ещё возможен косяк с WFI вот тут: Код // 2. как только попадаем в IdleProcessHook() - запускаем другой таймер (2) и взводим флаг IDLE. // Делаем это в критич. секции (?). // Если IDLE уже взведён - ничего не трогаем.
void OS::IdleProcessUserHook() { if (!idle_flag) { TCritSect cs; idle_flag = TRUE; tmrIdle = 0; } __WFI(); } если проскочит переключение контекста прямо сразу за крит. секцией и перед инструкцией WFI - при следующем заходе в IdleProcess проц попадёт прямо на WFI и уснёт со сброшенным флагом idle_flag, так как: Код void OS::ContextSwitchUserHook() { if (idle_flag) { cpu_idle_acc += (dword)tmrIdle; idle_flag = FALSE; } } То есть внесётся некоторая ошибка. Чтобы исключить этот косяк - крит. секцию с установкой флага надо размещать в коде ОС прямо перед переключением на IdleProcess.
|
|
|
|
|
Aug 13 2010, 10:36
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(AHTOXA @ Aug 12 2010, 06:51)  Раз все молчат, то, видимо, никто  Ну, некоторые еще в отпуске  В TBaseProcess добавлял еще dword LoadCounter. В прерывании системного таймера делал ++Kernel->ProcessTable[CurProcPriority].LoadCounter; Запустив программу на некоторое время и остановив ее в отладчике смотрю, сколько натикало в каждом счетчике. Не учитываются прерывания, но в целом дает достаточно точную картину распределения загрузки между процесами. Годится в для "внутреннего упротребелния". Для включения в основные исходники нужно в TKernel добавить функцию чтения и сброса счетчиков.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 13 2010, 13:15
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(Сергей Борщ @ Aug 13 2010, 14:36)  Ну, некоторые еще в отпуске  В TBaseProcess добавлял еще dword LoadCounter. В прерывании системного таймера делал ++Kernel->ProcessTable[CurProcPriority].LoadCounter; Запустив программу на некоторое время и остановив ее в отладчике смотрю, сколько натикало в каждом счетчике. Не учитываются прерывания, но в целом дает достаточно точную картину распределения загрузки между процесами. Годится в для "внутреннего упротребелния". Для включения в основные исходники нужно в TKernel добавить функцию чтения и сброса счетчиков. Спасибо, попробую Ваш метод. Выглядит гораздо изящнее, хоть и несколько в ущерб точности. Не подскажете реализацию функций работы со счётчиками для ОС? Я пока с Си++ на Вы
|
|
|
|
|
Aug 14 2010, 06:18
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(Сергей Борщ @ Aug 13 2010, 17:36)  Ну, некоторые еще в отпуске  +1.  Цитата(Сергей Борщ @ Aug 13 2010, 17:36)  В TBaseProcess добавлял еще dword LoadCounter. В прерывании системного таймера делал ++Kernel->ProcessTable[CurProcPriority].LoadCounter; Запустив программу на некоторое время и остановив ее в отладчике смотрю, сколько натикало в каждом счетчике. Не учитываются прерывания, но в целом дает достаточно точную картину распределения загрузки между процесами. Годится в для "внутреннего упротребелния". Для включения в основные исходники нужно в TKernel добавить функцию чтения и сброса счетчиков. Просто и эффективно. Минус один (как уже заметили) - разрешающая способность может кому-то оказаться недостаточной - один тик системного таймера. Хотя в масштабах ОС, имхо, этого должно хватать. Такую фишку надо делать включаемой/отключаемой - завести макрос в конфигурационном файле (в стиле имеющихся). Чтобы код счетчиков и доступа к ним был в условной компиляции. Поскольку ты, видно, уже реализовал основной функционал, сможешь довести до конца (и зафиксировать в реп)? А мы потестим.  P.S. Надо бы еще на хосте что-то придумать для удобного мониторинга. Самое простое - через терминал. Но не факт, что самое удобное.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Aug 14 2010, 09:13
|

embarrassed systems engineer
    
Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038

|
Цитата(sonycman @ Aug 11 2010, 19:09)  3. как только попадаем в ContextSwitchUserHook() - проверяем, взведён ли флаг IDLE. Если да - останавливаем таймер (2) и сбрасываем IDLE. Я пользуюсь TNKernel, но принцип можно применить почти к любой RTOS. Заводится один "сводобно-тикающий" таймер - 32-битный (разрядность не особо важна). В управляющей структуре задачи заводится поле которое считает время отданное задаче (в тиках данного таймера), и при переключении контекста вызывается такое: Код //________________________________________________________________ // // Функция профайлера обновляет такты профайлера в TCB текущей // задачи прошедшее с момента последнего вызова данной функции // Должна вызываться с запрещенными прерываниями // #if TN_CPU_PERFMON TN_SYSTEM_CALL VOID TN_CALL_OPTION tn_profiler_update( void) { static DWORD prev = 0; DWORD value;
value = hal_profiler_counter(); tn_curr_run_task->task_prof += (value - prev); prev = value; } #endif В итоге в полях task_prof накапливается распределение времени по задачам. Чтобы не было переполнения счетчиков, в отдельном потоке вызвается с определенным интервалом (порядка секунды) сборщик статистики - и по ней уже можно строить графики распределения времени процессора по задачам - при отладке решает все проблемы кардинально. После сведения статистики task_prof-ы обнуляются и начинается новый цикл. Время бездействия системы - это время отданное задаче IDLE. Точность метода можно повысить если завести отдельный task_prof для обработчиков прерываний, но у меня пока такой надобности не было.
|
|
|
|
|
Aug 14 2010, 13:03
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(VslavX @ Aug 14 2010, 13:13)  Я пользуюсь TNKernel, но принцип можно применить почти к любой RTOS. Заводится один "сводобно-тикающий" таймер - 32-битный (разрядность не особо важна). О, спасибо, это тоже интересный вариант, который немного сложнее варианта Сергея, но способен дать бОльшую точность. Только непонял, зачем функцию tn_profiler_update() ставить в крит. секцию (запрещать прерывания)? Наверное, если вызывать подобную функцию из ContextSwitchUserHook() в scmRTOS, прерывания запрещать не нужно?
|
|
|
|
|
Aug 14 2010, 13:45
|

embarrassed systems engineer
    
Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038

|
Цитата(sonycman @ Aug 14 2010, 16:03)  Только непонял, зачем функцию tn_profiler_update() ставить в крит. секцию (запрещать прерывания)? Модификация task_prof должна быть "в критической секции", так как теоретически task_prof может изменяться в нескольких потоках (например, хотя бы task_prof обнуляется сборщиком статистики). Цитата(sonycman @ Aug 14 2010, 16:03)  Наверное, если вызывать подобную функцию из ContextSwitchUserHook() в scmRTOS, прерывания запрещать не нужно? Да, у меня она именно оттуда (из аналога во внутренностях TNKernel) и вызывается, если у Вас в прерывания в ContextSwitchUserHook() запрещены (думаю что это так и есть) то дополнительно запрещать прерывания не надо. Принудительный запрет/восстановление прерываний в приведенной функции я не сделал для повышения быстродействия (кстати, hal_profiler_counter() - инлайновая, тоже снижает издержки). Upd: еще нюанс - вызов функции должен осуществляться еще ДО переключения контекста, в контексте задачи которая уходит, ну или явно давать ссылку на TCB вытесняемой задачи (tn_curr_run_task в моем примере) для обновления времени именно для той задачи, которая его "употребила".
|
|
|
|
|
Aug 14 2010, 14:58
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(VslavX @ Aug 14 2010, 17:45)  Да, у меня она именно оттуда (из аналога во внутренностях TNKernel) и вызывается, если у Вас в прерывания в ContextSwitchUserHook() запрещены (думаю что это так и есть) то дополнительно запрещать прерывания не надо. Да, прерывания в этом месте действительно запрещены. Цитата Upd: еще нюанс - вызов функции должен осуществляться еще ДО переключения контекста, в контексте задачи которая уходит, ну или явно давать ссылку на TCB вытесняемой задачи (tn_curr_run_task в моем примере) для обновления времени именно для той задачи, которая его "употребила". Ага, это тоже понятно. В scmRTOS для этого служит CurProcPriority. Ну, вроде понемногу разбираюсь. Пойду проводить модернизацию кода  В общем, пока делаю так: 1. в классе TBaseProcess завожу dword LoadCounter. 2. в SystemTimerUserHook() инкрементирую её: Kernel.ProcessTable[Kernel.CurProcPriority]->LoadCounter++; 3. по истечении одной секунды в том же SystemTimerUserHook() считываю LoadCounter всех процессов и сбрасываю их. 4. вычисляю на базе считанных счётчиков загрузку по процессам.
|
|
|
|
|
Aug 14 2010, 15:10
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(dxp @ Aug 14 2010, 09:18)  +1.  У меня наоборот. Кутерьма, а из-за жары еле ползают мысли. Цитата(dxp @ Aug 14 2010, 09:18)  Просто и эффективно. Минус один (как уже заметили) - разрешающая способность может кому-то оказаться недостаточной - один тик системного таймера. Хотя в масштабах ОС, имхо, этого должно хватать. Мало — для высокоприоритетных процессов, которые просыпаются ненадолго, часто на время гораздо меньше тика. Поэтому надо комбинировать счётчик тиков и выдернутое из таймера, который прерывания тиков генерирует. А это уже и в 32 бита не лезет, поэтому на AVR я ограничил хотелку и обошёлся другим простым способом определения загрузки системы - в IdleProcessUserHook добавил Код { TCritSect cs; ON(LOAD_PIN); OFF(LOAD_PIN); } замерил среднее напряжение на ножке LOAD_PIN при всех спящих процессах, а потом чем сильнее загрузка, тем ниже среднее напряжение на ножке :-) Цитата(dxp @ Aug 14 2010, 09:18)  Такую фишку надо делать включаемой/отключаемой - завести макрос в конфигурационном файле (в стиле имеющихся). Чтобы код счетчиков и доступа к ним был в условной компиляции. Обязательно. И для контроля стека тоже. А то я просто скопипастил шаблон процесса и поменял имя, добавил контроль и успокоился. Цитата(dxp @ Aug 14 2010, 09:18)  P.S. Надо бы еще на хосте что-то придумать для удобного мониторинга. Самое простое - через терминал. Но не факт, что самое удобное. Для начала сам контроль/подсчёт реализовать с открытыми всем желающим функциями получения результата.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|