VDK: поток ожидания (Idle Thread) |
![]() |
Добавил(а) microsin |
Idle thread это изначально определенный системой VDK поток ожидания, который автоматически создается в наборе идентификаторов потоков с идентификатором ThreadID, равным 0, и приоритетом, который ниже самого низкоприоритетного потока из всех потоков пользователя. Таким образом, когда в очереди готовности (ready queue) нет ни одного потока пользователя (все потоки находятся в состоянии сна на заданное время, либо заблокированы на семафорах), будет работать поток Idle. Единственное, что делает Idle thread, это уборка мусора, т. е. освобождение ресурсов потоков, которые были уничтожены. Другими словами, поток ожидания обрабатывает уничтожение потоков, которые были переданы в вызов DestroyThread() со значением FALSE в параметре inDestroyNow. После выполнения этой работы поток ожидания просто зацикливается, не выполняя никакую работу и не переводя процессор в состояние ожидания или режим пониженного энергопотребления, потому что тогда остановится таймер ядра и все сервисы VDK, работающие с реальным временем (см. ниже раздел "Таймер"). В зависимости от платформы имеется возможность настроить определенные параметры Idle thread, такие как размер стека и кучу, из которой удовлетворяются запросы к выделениям памяти (включая стек для Idle). Для получения дополнительных подробностей см. онлайн-Help. Здесь могут быть зависящие от процессора требования к свойствам потока Idle (см. приложение A "Processor-Specific Notes" [1], или перевод этой документации [4]). Процессорное время, которое приложение тратит во всех потоках кроме Idle thread, показано графиком на закладке Target Load информационного окна State History среды разработки VisualDSP++ (открывается через меню View -> VDK Windows -> History). Подробнее про окно истории см. раздел "VDK State History Window" онлайн-Help. [Таймер] Тики (VDK Ticks) вычисляются по таймеру, реализованному во внутреннем ядре процессоров Blackfin. Этот таймер засинхронизирован с с основной частотой ядра CCLK. Однако работа этого таймера запрещена, когда процессор Blackfin входит в режим низкого энергопотребления (low power mode). Таким образом, все службы VDK, связанные отсчетом реального времени (такие как вход потока в сон на заданное время, работа периодических семафоров), не работают, когда ядро находится в состоянии IDLE или low power mode. По умолчанию VDK не использует и не модифицирует таймеры общего назначения. На процессорах Blackfin можно зарегистрировать прерывания с помощью библиотечной функции register_handler() или через вызов API системных служб adi_int_CECHook(), тогда не надо декларировать прерывания на закладке проекта VDK Kernel. Прерывания, зарегистрированные вне конфигурации VDK, не должны использовать тот же уровень IVG, что и любое прерывание, определенное на закладке VDK Kernel. [Использование прерываниями стека потока] Из-за того, что код всех потоков работает в режиме супервизора, нет автоматического переключения между указателями пользовательского и системного стека. Таким образом, все ISR выполняются с использованием стека текущего работающего потока, во время активности которого произошло прерывание. Это означает, что размер стека каждого потока должен иметь достаточно места как для самого потока, так и для требований обработчиков прерываний (ISR). Это также относится и к размеру стека потока ожидания (Idle thread), что можно сконфигурировать средствами среды разработки VisualDSP++ (для дополнительной информации см. онлайн-Help). Когда разрешено вложение прерываний друг в друга, то наступает самый худший сценарий для выделения места в памяти под стек, потому что требования к стеку от отдельных ISR могут складываться. Когда вложение прерываний запрещено, то для удовлетворения требований к размеру стеку со стороны ISR нужно учитывать только требование от потока, который больше всего занимает памяти в стеке. [Как определить загрузку процессора?] Процессор, который выполняет VDK-приложение Blackfin, никогда не останавливается, и всегда выполняет какие-то вычисления, которые распределены между потоками системы. Не производительные вычисления, которые не связаны с полезной работой приложения, сосредоточены в потоке ожидания (Idle Thread). Таким образом, чтобы узнать, насколько загружен процессор полезной работой, нужно: 1. Узнать, сколько процессорного времени прошло. В тиках или в единицах счета таймера ядра, не важно. Предположим, что это время равно T. LOAD = 100 * (1 - Tidle/T) Все довольно просто, осталось только получить значения T и Tidle. Проще всего это сделать, если воспользоваться статистикой, которую накапливает так называемая инструментальная сборка проекта VDK. Сборка называется инструментальной по терминологии компании Analog Devices, которая разработала библиотеки VDK таким образом, что проект VDK можно собрать в 3 вариантах - Full Instrumentation (вариант полной инструментальной поддержки, который накапливает статистику по системе и потокам), Error Checking (этот вариант снабжен только проверкой ошибок) и None (программисту не предоставляется дополнительной отладочной информации по отлаживаемому проекту VDK). Информацию Full Instrumentation можно, если остановить приложение в отладчике, и открыть окошки VDK State History, VDK Target Load, VDK Status (доступно через меню View -> VDK Windows). Но как получить эту информацию в приложении, runtime, не прибегая к помощи отладчика, не нарушая работы приложения? К счастью, существует специальное API [2, 3], которое позволяет добраться до этой информации из кода приложения. Значение времени T в тиках можно получить вызовом функции GetUptime(), а время Tidle в тиках можно получить вызовом функции GetThreadTickData. Пример: VDK::Ticks outUpTime; //Это общее время T VDK::Ticks outIdleTime; //Это время Tidle outUpTime = VDK::GetUptime(); VDK::GetThreadTickData ((VDK::ThreadID)0, (VDK::Ticks *)NULL, (VDK::Ticks *)NULL, (VDK::Ticks *)NULL, &outIdleTime); float Load = 100 * (1 - (float)outIdleTime/outUpTime); printf ("Загрузка системы %.1%%\n", Load); Обратите внимание, что в функцию GetThreadTickData передан 0 в качестве идентификатора потока, потому что этому значению всегда равен идентификатор потока ожидания. Имейте в виду, что выведенная загрузка в процентах не учитывает процессорное время, которое ядро проводит в вычислениях драйверов устройств, если их код работает в контексте домена прерываний. А как узнать, сколько процессорного времени отнимает каждый поток? Тоже довольно просто, если получить список работающих потоков и узнать их идентификаторы. Это тоже делается вызовами API. Пример: VDK::Ticks outUpTime; //Общее время, сколько проработала система VDK::Ticks outThreadTime; //Время работы потока int totalthreads; //Сколько потоков имеется в системе //Выделение памяти под идентификаторы потоков: VDK::ThreadID *outThreadIDArray = (VDK::ThreadID *)heap_malloc(1, VDK_kMaxNumThreads * sizeof(VDK::ThreadID)); //Получение информации о потоках: totalthreads = VDK::GetAllThreads (outThreadIDArray, VDK_kMaxNumThreads); //Сколько проработала система всего:
outUpTime = VDK::GetUptime(); //Цикл по потокам:
for (int idx=0; idx < totalthreads; idx++) { //Получение имени потока: char *outName; //Указатель на имя потока VDK::GetThreadTemplateName(outThreadIDArray[idx], &outName); //Получение времени, сколько проработал поток: VDK::GetThreadTickData (outThreadIDArray[idx], (VDK::Ticks *)NULL, (VDK::Ticks *)NULL, (VDK::Ticks *)NULL, &outThreadTime); printf ("%i: %s, %.1f%%\n", outThreadIDArray[idx], outName, (float)100*outThreadTime/outUpTime); } heap_free(1, outThreadIDArray); Будет выведен список наподобие следующего (ID потока, имя потока, % процессорного времени): 0: Idle Thread, 80.2% 1: kmainthread, 0.3% 2: kuartRXthread, 0.2% 3: kuartTXthread, 0.1% 4: kscreenthread, 0.9% 5: kreadbattvoltage, 0.1% 6: kkeybrdthread, 1.7% 7: kDSPthread, 16.7% Имейте в виду, что эти примеры кода будут работать и для конфигурации Debug, и для конфигурации Release, но только при условии, если выбран вариант библиотек VDK с полной инструментальной поддержкой (настраивается в свойствах проекта на закладке Kernel, раздел System -> Instrumentation Level, здесь должен быть выбран вариант Full Instrumentation). [Ссылки] 1. VisualDSP++ 5.0 Kernel (VDK) User’s Guide site:analog.com. |