Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Бездействие системы - как измерить?
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > scmRTOS
sonycman
Доброго времени суток!

Использую порт scmRTOS для кортексов.
Большое спасибо авторам ОС и порта, люди сделали большую работу и дали воспользоваться ей другим.
Респект!

Вот захотелось сделать прибамбас - индикацию бездействия контроллера.
Ведь весьма полезная фича при отладке приложения.

Пока идея такова:

1. в одном из процессов запускаем таймер (1) на 1 сек (к примеру).

2. как только попадаем в IdleProcessHook() - запускаем другой таймер (2) и взводим флаг IDLE.
Делаем это в критич. секции (?).
Если IDLE уже взведён - ничего не трогаем.

3. как только попадаем в ContextSwitchUserHook() - проверяем, взведён ли флаг IDLE. Если да - останавливаем таймер (2) и сбрасываем IDLE.

4. как только таймер (1) досчитывает до порогового значения периода измерения - сопоставляем натикавшее время (1) и (2) таймеров и вычисляем загрузку.
Если (2) таймер в нуле - 100% загрузка, если близок по значению к (1) - 0%.
Затем сбрасываем оба таймера и всё повторяется сначала.

Вроде для грубого вычисления подойдёт.
Что плохо - таймер простоя (2) будет считать время выполнения любых прерываний как бездействие системы.
Это внесёт погрешность.

ЗЫ:Если я правильно понял, IdleProcess выполняется также, как и все остальные процессы - то есть продолжает выполняться с того места, откуда был прерван?
sergeeff
Так все таймеры в процессоре только на это дело и уйдут. Как то не рационально. Может помозговать и обойтись системным таймером тиков?
sonycman
Цитата(sergeeff @ Aug 11 2010, 23:56) *
Так все таймеры в процессоре только на это дело и уйдут. Как то не рационально. Может помозговать и обойтись системным таймером тиков?

Нет, зачем, таймеры будут софтовые, на базе одного 32-ух битного аппаратного таймера их можно наплодить сотни.
Разрешения в 1 мкс я думаю хватит.

Сегодня после работы попробую, что получится.
Никто не реализовывал подобную фичу под этой ОС?

AHTOXA
Цитата(sonycman @ Aug 12 2010, 07:48) *
Сегодня после работы попробую, что получится.
Никто не реализовывал подобную фичу под этой ОС?


Раз все молчат, то, видимо, никтоsmile.gif Обсуждали, в контексте путей дальнейшего развития, и на этом пока всеsmile.gif
Попробуйте конечно, очень интересно.

ЗЫ. Я приблизительно измеряю загрузку STM32 по потребляемому току. Вставил в IdleProcessUserHook() вызов __WFI();, и контроллер у меня спит, когда он в Idle.
( Но зацепиться JTAG-ом к спящему контроллеру - это тот ещё ребусsmile.gif )
sonycman
Сделал вчера измерение по описанной методике - всё работает практически как часы smile.gif

Попробую немного соптимизировать - использовать вместо двух таймеров один - системный 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.
Сергей Борщ
Цитата(AHTOXA @ Aug 12 2010, 06:51) *
Раз все молчат, то, видимо, никтоsmile.gif
Ну, некоторые еще в отпуске smile.gif

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

В TBaseProcess добавлял еще dword LoadCounter. В прерывании системного таймера делал ++Kernel->ProcessTable[CurProcPriority].LoadCounter; Запустив программу на некоторое время и остановив ее в отладчике смотрю, сколько натикало в каждом счетчике. Не учитываются прерывания, но в целом дает достаточно точную картину распределения загрузки между процесами. Годится в для "внутреннего упротребелния". Для включения в основные исходники нужно в TKernel добавить функцию чтения и сброса счетчиков.

Спасибо, попробую Ваш метод.
Выглядит гораздо изящнее, хоть и несколько в ущерб точности.

Не подскажете реализацию функций работы со счётчиками для ОС?
Я пока с Си++ на Вы smile.gif
AHTOXA
Цитата(Сергей Борщ @ Aug 13 2010, 16:36) *
Ну, некоторые еще в отпуске smile.gif

Везёт же некоторым! :-)
Может, тогось, ответвить веточку под развитие отладочных средств? Туда сразу контроль стека и другие имеющиеся наработки...
dxp
Цитата(Сергей Борщ @ Aug 13 2010, 17:36) *
Ну, некоторые еще в отпуске smile.gif

+1. smile.gif

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

Просто и эффективно. Минус один (как уже заметили) - разрешающая способность может кому-то оказаться недостаточной - один тик системного таймера. Хотя в масштабах ОС, имхо, этого должно хватать.

Такую фишку надо делать включаемой/отключаемой - завести макрос в конфигурационном файле (в стиле имеющихся). Чтобы код счетчиков и доступа к ним был в условной компиляции. Поскольку ты, видно, уже реализовал основной функционал, сможешь довести до конца (и зафиксировать в реп)? А мы потестим. smile.gif

P.S. Надо бы еще на хосте что-то придумать для удобного мониторинга. Самое простое - через терминал. Но не факт, что самое удобное.
VslavX
Цитата(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 для обработчиков прерываний, но у меня пока такой надобности не было.
sonycman
Цитата(VslavX @ Aug 14 2010, 13:13) *
Я пользуюсь TNKernel, но принцип можно применить почти к любой RTOS. Заводится один "сводобно-тикающий" таймер - 32-битный (разрядность не особо важна).

О, спасибо, это тоже интересный вариант, который немного сложнее варианта Сергея, но способен дать бОльшую точность.

Только непонял, зачем функцию tn_profiler_update() ставить в крит. секцию (запрещать прерывания)?
Наверное, если вызывать подобную функцию из ContextSwitchUserHook() в scmRTOS, прерывания запрещать не нужно?
VslavX
Цитата(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 в моем примере) для обновления времени именно для той задачи, которая его "употребила".
sonycman
Цитата(VslavX @ Aug 14 2010, 17:45) *
Да, у меня она именно оттуда (из аналога во внутренностях TNKernel) и вызывается, если у Вас в прерывания в ContextSwitchUserHook() запрещены (думаю что это так и есть) то дополнительно запрещать прерывания не надо.

Да, прерывания в этом месте действительно запрещены.

Цитата
Upd: еще нюанс - вызов функции должен осуществляться еще ДО переключения контекста, в контексте задачи которая уходит, ну или явно давать ссылку на TCB вытесняемой задачи (tn_curr_run_task в моем примере) для обновления времени именно для той задачи, которая его "употребила".

Ага, это тоже понятно. В scmRTOS для этого служит CurProcPriority.

Ну, вроде понемногу разбираюсь.

Пойду проводить модернизацию кода smile.gif

В общем, пока делаю так:
1. в классе TBaseProcess завожу dword LoadCounter.
2. в SystemTimerUserHook() инкрементирую её: Kernel.ProcessTable[Kernel.CurProcPriority]->LoadCounter++;
3. по истечении одной секунды в том же SystemTimerUserHook() считываю LoadCounter всех процессов и сбрасываю их.
4. вычисляю на базе считанных счётчиков загрузку по процессам.
ReAl
Цитата(dxp @ Aug 14 2010, 09:18) *
+1. smile.gif
У меня наоборот. Кутерьма, а из-за жары еле ползают мысли.

Цитата(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. Надо бы еще на хосте что-то придумать для удобного мониторинга. Самое простое - через терминал. Но не факт, что самое удобное.
Для начала сам контроль/подсчёт реализовать с открытыми всем желающим функциями получения результата.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.