sonycman 2 August 11, 2010 Posted August 11, 2010 · Report post Доброго времени суток! Использую порт scmRTOS для кортексов. Большое спасибо авторам ОС и порта, люди сделали большую работу и дали воспользоваться ей другим. Респект! Вот захотелось сделать прибамбас - индикацию бездействия контроллера. Ведь весьма полезная фича при отладке приложения. Пока идея такова: 1. в одном из процессов запускаем таймер (1) на 1 сек (к примеру). 2. как только попадаем в IdleProcessHook() - запускаем другой таймер (2) и взводим флаг IDLE. Делаем это в критич. секции (?). Если IDLE уже взведён - ничего не трогаем. 3. как только попадаем в ContextSwitchUserHook() - проверяем, взведён ли флаг IDLE. Если да - останавливаем таймер (2) и сбрасываем IDLE. 4. как только таймер (1) досчитывает до порогового значения периода измерения - сопоставляем натикавшее время (1) и (2) таймеров и вычисляем загрузку. Если (2) таймер в нуле - 100% загрузка, если близок по значению к (1) - 0%. Затем сбрасываем оба таймера и всё повторяется сначала. Вроде для грубого вычисления подойдёт. Что плохо - таймер простоя (2) будет считать время выполнения любых прерываний как бездействие системы. Это внесёт погрешность. ЗЫ:Если я правильно понял, IdleProcess выполняется также, как и все остальные процессы - то есть продолжает выполняться с того места, откуда был прерван? Quote Share this post Link to post Share on other sites More sharing options...
sergeeff 1 August 11, 2010 Posted August 11, 2010 · Report post Так все таймеры в процессоре только на это дело и уйдут. Как то не рационально. Может помозговать и обойтись системным таймером тиков? Quote Share this post Link to post Share on other sites More sharing options...
sonycman 2 August 12, 2010 Posted August 12, 2010 · Report post Так все таймеры в процессоре только на это дело и уйдут. Как то не рационально. Может помозговать и обойтись системным таймером тиков? Нет, зачем, таймеры будут софтовые, на базе одного 32-ух битного аппаратного таймера их можно наплодить сотни. Разрешения в 1 мкс я думаю хватит. Сегодня после работы попробую, что получится. Никто не реализовывал подобную фичу под этой ОС? Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 25 August 12, 2010 Posted August 12, 2010 · Report post Сегодня после работы попробую, что получится. Никто не реализовывал подобную фичу под этой ОС? Раз все молчат, то, видимо, никто:) Обсуждали, в контексте путей дальнейшего развития, и на этом пока все:) Попробуйте конечно, очень интересно. ЗЫ. Я приблизительно измеряю загрузку STM32 по потребляемому току. Вставил в IdleProcessUserHook() вызов __WFI();, и контроллер у меня спит, когда он в Idle. ( Но зацепиться JTAG-ом к спящему контроллеру - это тот ещё ребус:) ) Quote Share this post Link to post Share on other sites More sharing options...
sonycman 2 August 13, 2010 Posted August 13, 2010 · Report post Сделал вчера измерение по описанной методике - всё работает практически как часы :) Попробую немного соптимизировать - использовать вместо двух таймеров один - системный 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. Quote Share this post Link to post Share on other sites More sharing options...
Сергей Борщ 187 August 13, 2010 Posted August 13, 2010 · Report post Раз все молчат, то, видимо, никто:)Ну, некоторые еще в отпуске :) В TBaseProcess добавлял еще dword LoadCounter. В прерывании системного таймера делал ++Kernel->ProcessTable[CurProcPriority].LoadCounter; Запустив программу на некоторое время и остановив ее в отладчике смотрю, сколько натикало в каждом счетчике. Не учитываются прерывания, но в целом дает достаточно точную картину распределения загрузки между процесами. Годится в для "внутреннего упротребелния". Для включения в основные исходники нужно в TKernel добавить функцию чтения и сброса счетчиков. Quote Share this post Link to post Share on other sites More sharing options...
sonycman 2 August 13, 2010 Posted August 13, 2010 · Report post Ну, некоторые еще в отпуске :) В TBaseProcess добавлял еще dword LoadCounter. В прерывании системного таймера делал ++Kernel->ProcessTable[CurProcPriority].LoadCounter; Запустив программу на некоторое время и остановив ее в отладчике смотрю, сколько натикало в каждом счетчике. Не учитываются прерывания, но в целом дает достаточно точную картину распределения загрузки между процесами. Годится в для "внутреннего упротребелния". Для включения в основные исходники нужно в TKernel добавить функцию чтения и сброса счетчиков. Спасибо, попробую Ваш метод. Выглядит гораздо изящнее, хоть и несколько в ущерб точности. Не подскажете реализацию функций работы со счётчиками для ОС? Я пока с Си++ на Вы :) Quote Share this post Link to post Share on other sites More sharing options...
AHTOXA 25 August 13, 2010 Posted August 13, 2010 · Report post Ну, некоторые еще в отпуске :) Везёт же некоторым! :-) Может, тогось, ответвить веточку под развитие отладочных средств? Туда сразу контроль стека и другие имеющиеся наработки... Quote Share this post Link to post Share on other sites More sharing options...
dxp 218 August 14, 2010 Posted August 14, 2010 · Report post Ну, некоторые еще в отпуске :) +1. :) В TBaseProcess добавлял еще dword LoadCounter. В прерывании системного таймера делал ++Kernel->ProcessTable[CurProcPriority].LoadCounter; Запустив программу на некоторое время и остановив ее в отладчике смотрю, сколько натикало в каждом счетчике. Не учитываются прерывания, но в целом дает достаточно точную картину распределения загрузки между процесами. Годится в для "внутреннего упротребелния". Для включения в основные исходники нужно в TKernel добавить функцию чтения и сброса счетчиков. Просто и эффективно. Минус один (как уже заметили) - разрешающая способность может кому-то оказаться недостаточной - один тик системного таймера. Хотя в масштабах ОС, имхо, этого должно хватать. Такую фишку надо делать включаемой/отключаемой - завести макрос в конфигурационном файле (в стиле имеющихся). Чтобы код счетчиков и доступа к ним был в условной компиляции. Поскольку ты, видно, уже реализовал основной функционал, сможешь довести до конца (и зафиксировать в реп)? А мы потестим. :) P.S. Надо бы еще на хосте что-то придумать для удобного мониторинга. Самое простое - через терминал. Но не факт, что самое удобное. Quote Share this post Link to post Share on other sites More sharing options...
VslavX 0 August 14, 2010 Posted August 14, 2010 · Report post 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 для обработчиков прерываний, но у меня пока такой надобности не было. Quote Share this post Link to post Share on other sites More sharing options...
sonycman 2 August 14, 2010 Posted August 14, 2010 · Report post Я пользуюсь TNKernel, но принцип можно применить почти к любой RTOS. Заводится один "сводобно-тикающий" таймер - 32-битный (разрядность не особо важна). О, спасибо, это тоже интересный вариант, который немного сложнее варианта Сергея, но способен дать бОльшую точность. Только непонял, зачем функцию tn_profiler_update() ставить в крит. секцию (запрещать прерывания)? Наверное, если вызывать подобную функцию из ContextSwitchUserHook() в scmRTOS, прерывания запрещать не нужно? Quote Share this post Link to post Share on other sites More sharing options...
VslavX 0 August 14, 2010 Posted August 14, 2010 · Report post Только непонял, зачем функцию tn_profiler_update() ставить в крит. секцию (запрещать прерывания)? Модификация task_prof должна быть "в критической секции", так как теоретически task_prof может изменяться в нескольких потоках (например, хотя бы task_prof обнуляется сборщиком статистики). Наверное, если вызывать подобную функцию из ContextSwitchUserHook() в scmRTOS, прерывания запрещать не нужно? Да, у меня она именно оттуда (из аналога во внутренностях TNKernel) и вызывается, если у Вас в прерывания в ContextSwitchUserHook() запрещены (думаю что это так и есть) то дополнительно запрещать прерывания не надо. Принудительный запрет/восстановление прерываний в приведенной функции я не сделал для повышения быстродействия (кстати, hal_profiler_counter() - инлайновая, тоже снижает издержки). Upd: еще нюанс - вызов функции должен осуществляться еще ДО переключения контекста, в контексте задачи которая уходит, ну или явно давать ссылку на TCB вытесняемой задачи (tn_curr_run_task в моем примере) для обновления времени именно для той задачи, которая его "употребила". Quote Share this post Link to post Share on other sites More sharing options...
sonycman 2 August 14, 2010 Posted August 14, 2010 · Report post Да, у меня она именно оттуда (из аналога во внутренностях 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. вычисляю на базе считанных счётчиков загрузку по процессам. Quote Share this post Link to post Share on other sites More sharing options...
ReAl 0 August 14, 2010 Posted August 14, 2010 · Report post +1. :)У меня наоборот. Кутерьма, а из-за жары еле ползают мысли. Просто и эффективно. Минус один (как уже заметили) - разрешающая способность может кому-то оказаться недостаточной - один тик системного таймера. Хотя в масштабах ОС, имхо, этого должно хватать.Мало — для высокоприоритетных процессов, которые просыпаются ненадолго, часто на время гораздо меньше тика. Поэтому надо комбинировать счётчик тиков и выдернутое из таймера, который прерывания тиков генерирует. А это уже и в 32 бита не лезет, поэтому на AVR я ограничил хотелку и обошёлся другим простым способом определения загрузки системы - в IdleProcessUserHook добавил { TCritSect cs; ON(LOAD_PIN); OFF(LOAD_PIN); } замерил среднее напряжение на ножке LOAD_PIN при всех спящих процессах, а потом чем сильнее загрузка, тем ниже среднее напряжение на ножке :-) Такую фишку надо делать включаемой/отключаемой - завести макрос в конфигурационном файле (в стиле имеющихся). Чтобы код счетчиков и доступа к ним был в условной компиляции.Обязательно. И для контроля стека тоже. А то я просто скопипастил шаблон процесса и поменял имя, добавил контроль и успокоился. P.S. Надо бы еще на хосте что-то придумать для удобного мониторинга. Самое простое - через терминал. Но не факт, что самое удобное.Для начала сам контроль/подсчёт реализовать с открытыми всем желающим функциями получения результата. Quote Share this post Link to post Share on other sites More sharing options...