Jump to content
    

Бездействие системы - как измерить?

Доброго времени суток!

 

Использую порт scmRTOS для кортексов.

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

Респект!

 

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

Ведь весьма полезная фича при отладке приложения.

 

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

 

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

 

2. как только попадаем в IdleProcessHook() - запускаем другой таймер (2) и взводим флаг IDLE.

Делаем это в критич. секции (?).

Если IDLE уже взведён - ничего не трогаем.

 

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

 

4. как только таймер (1) досчитывает до порогового значения периода измерения - сопоставляем натикавшее время (1) и (2) таймеров и вычисляем загрузку.

Если (2) таймер в нуле - 100% загрузка, если близок по значению к (1) - 0%.

Затем сбрасываем оба таймера и всё повторяется сначала.

 

Вроде для грубого вычисления подойдёт.

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

Это внесёт погрешность.

 

ЗЫ:Если я правильно понял, IdleProcess выполняется также, как и все остальные процессы - то есть продолжает выполняться с того места, откуда был прерван?

Share this post


Link to post
Share on other sites

Так все таймеры в процессоре только на это дело и уйдут. Как то не рационально. Может помозговать и обойтись системным таймером тиков?

Share this post


Link to post
Share on other sites

Так все таймеры в процессоре только на это дело и уйдут. Как то не рационально. Может помозговать и обойтись системным таймером тиков?

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

Разрешения в 1 мкс я думаю хватит.

 

Сегодня после работы попробую, что получится.

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

 

 

Share this post


Link to post
Share on other sites

Сегодня после работы попробую, что получится.

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

 

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

Попробуйте конечно, очень интересно.

 

ЗЫ. Я приблизительно измеряю загрузку STM32 по потребляемому току. Вставил в IdleProcessUserHook() вызов __WFI();, и контроллер у меня спит, когда он в Idle.

( Но зацепиться JTAG-ом к спящему контроллеру - это тот ещё ребус:) )

Share this post


Link to post
Share on other sites

Сделал вчера измерение по описанной методике - всё работает практически как часы :)

 

Попробую немного соптимизировать - использовать вместо двух таймеров один - системный 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.

Share this post


Link to post
Share on other sites

Раз все молчат, то, видимо, никто:)
Ну, некоторые еще в отпуске :)

 

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

Share this post


Link to post
Share on other sites

Ну, некоторые еще в отпуске :)

 

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

Спасибо, попробую Ваш метод.

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

 

Не подскажете реализацию функций работы со счётчиками для ОС?

Я пока с Си++ на Вы :)

Share this post


Link to post
Share on other sites

Ну, некоторые еще в отпуске :)

Везёт же некоторым! :-)

Может, тогось, ответвить веточку под развитие отладочных средств? Туда сразу контроль стека и другие имеющиеся наработки...

 

Share this post


Link to post
Share on other sites

Ну, некоторые еще в отпуске :)

+1. :)

 

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

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

 

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

 

P.S. Надо бы еще на хосте что-то придумать для удобного мониторинга. Самое простое - через терминал. Но не факт, что самое удобное.

Share this post


Link to post
Share on other sites

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 для обработчиков прерываний, но у меня пока такой надобности не было.

 

Share this post


Link to post
Share on other sites

Я пользуюсь TNKernel, но принцип можно применить почти к любой RTOS. Заводится один "сводобно-тикающий" таймер - 32-битный (разрядность не особо важна).

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

 

Только непонял, зачем функцию tn_profiler_update() ставить в крит. секцию (запрещать прерывания)?

Наверное, если вызывать подобную функцию из ContextSwitchUserHook() в scmRTOS, прерывания запрещать не нужно?

Share this post


Link to post
Share on other sites

Только непонял, зачем функцию tn_profiler_update() ставить в крит. секцию (запрещать прерывания)?

Модификация task_prof должна быть "в критической секции", так как теоретически task_prof может изменяться в нескольких потоках (например, хотя бы task_prof обнуляется сборщиком статистики).

Наверное, если вызывать подобную функцию из ContextSwitchUserHook() в scmRTOS, прерывания запрещать не нужно?

Да, у меня она именно оттуда (из аналога во внутренностях TNKernel) и вызывается, если у Вас в прерывания в ContextSwitchUserHook() запрещены (думаю что это так и есть) то дополнительно запрещать прерывания не надо. Принудительный запрет/восстановление прерываний в приведенной функции я не сделал для повышения быстродействия (кстати, hal_profiler_counter() - инлайновая, тоже снижает издержки).

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

 

Share this post


Link to post
Share on other sites

Да, у меня она именно оттуда (из аналога во внутренностях 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. вычисляю на базе считанных счётчиков загрузку по процессам.

Share this post


Link to post
Share on other sites

+1. :)
У меня наоборот. Кутерьма, а из-за жары еле ползают мысли.

 

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

    {
        TCritSect cs;
        ON(LOAD_PIN);
        OFF(LOAD_PIN);
    }

замерил среднее напряжение на ножке LOAD_PIN при всех спящих процессах, а потом чем сильнее загрузка, тем ниже среднее напряжение на ножке :-)

 

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

 

P.S. Надо бы еще на хосте что-то придумать для удобного мониторинга. Самое простое - через терминал. Но не факт, что самое удобное.
Для начала сам контроль/подсчёт реализовать с открытыми всем желающим функциями получения результата.

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...