Pages Menu
Categories Menu

Опубликовано | Нет комментариев

Обработка таймера

Интервальный таймер системных часов — пожалуй, наиболее важное устройство на Windows-машине, о чем свидетельствует его высокое значение IRQL (CLOCK_LEVEL). Его важность также следует из важности той работы, за которую он отвечает.

Без прерывания от таймера Windows не сможет отслеживать время, что выразится в ошибочных результатах доступного времени и показаний часов и, что еще хуже, приведет к тому, что время таймеров больше не будет истекать, и потоки никогда больше не израсходуют свои кванты времени. Windows также перестанет быть вытесняющей операционной системой, и, пока текущий работающий поток не уступит центральный процессор, важные фоновые задачи и планировщики никогда не будут работать на этом процессоре.

Windows программирует системные часы на выдачу сигнала через наиболее подходящий для машины интервал и впоследствии позволяет драйверам, приложениями и администраторам изменять этот интервал в соответствии с их потребностями. Обычно системные часы обслуживаются либо через программируемый интервальный таймер (Programmable Interrupt Timer, PIT), микросхему, которая имеется на всех компьютерах, начиная с PC/AT, либо через часы реального времени (RealTimeClock, RTC).

PIT работает на микросхеме, которая настроена на одну треть несущей частоты цвета стандарта NTSC (изначально она использовалась для телевизионного выхода на первых видеокартах CGA), а матричная логика с пользовательским программированием (HAL) использует различные доступные умножители для получения интервалов с шагом в 1 мс на модуль, начиная с 1 мс и заканчивая 15 мс.

RTC запускаются на частоте 32,768 КГц, которая, будучи степенью числа 2, легко настраивается для работы с различными интервалами, также являющимися степенями числа 2. На современных машинах APIC Multiprocessor HAL настраивает RTC на выдачу сигнала каждые 15,6 миллисекунды, что составляет примерно 64 раза в секунду. Некоторым видам Windows-приложений, таким как мультимедийные программы, требуется очень короткое время отклика.

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

Windows при любой возможности старается вернуть таймер часов к его исходному значению. При каждом запросе изменения интервала часов со стороны процесса Windows увеличивает значение внутреннего счетчика ссылок и связывает его с процессом. Аналогично этому драйверы (которые также могут изменить частоты следования импульсов) добавляются в глобальный счетчик ссылок.

Когда все драйверы восстановят работу часов и все процессы, изменившие их работу, либо завершатся, либо все восстановят, Windows возвращает настройку часов к ее исходному значению (или запрещает такое возвращение при переходе к более высокому значению, требуемому процессом или драйвером).

Идентификация таймеров, работающих с повышенной частотой.

В связи с проблемами, которые могут возникать из-за таймеров, работающих с повышенной частотой, Windows использует средство Event Tracing for Windows (ETW) для отслеживания всех процессов и драйверов, требующих изменения интервала системных часов с выводом времени события и требуемого интервала. Это средство показывает также и текущий интервал.

Эти данные пригодятся как разработчикам, так и системным администраторам при выяснении причин низкой производительности батареи на системах, которые в иных условиях работали вполне исправно, а также для уменьшения суммарной потребляемой мощности на больших системах. Для получения этих данных нужно просто запустить команду powercfg /energy и будет выдан HTML-файл energy-report.html похожий на этот.

energy-report

Прокрутите страницу вниз до раздела Разрешение аппаратного таймера (Platform Timer Resolution) и получите сведения обо всех приложениях, изменивших разрешение таймера и находящихся в активном состоянии, вместе с записями стека вызовов, показывающими причины данного вызова. Разрешения таймера показаны в сотнях наносекунд, следовательно, период в 20 000 соответствует 2 мс. В показанном примере оба приложения запрашивают более высокое разрешение.

Для получения данной информации можно также воспользоваться отладчиком. Для каждого процесса структура EPROCESS содержит ряд полей, показанных далее, которые помогают определить изменения в разрешении таймера:

+0x4a8 TimerResolutionLink : _LIST_ENTRY [ 0xfffffa80'05218fd8 - 0xfffffa80'059cd508 ]

+0x4b8 RequestedTimerResolution : 0

+0x4bc ActiveThreadsHighWatermark : 0x1d

+0x4c0 SmallestTimerResolution : 0x2710

+0x4c8 TimerResolutionStackRecord : 0xfffff8a0'0476ecd0 _PO_DIAG_STACK_RECORD

Следует заметить, что отладчик показывает дополнительный блок информации: наименьшее разрешение таймера, которое когда-либо было запрошено данным процессом. В этом примере показан процесс, относящийся к PowerPoint 2010, который обычно запрашивает более низкое разрешение таймера при показе слайдов, но это не относится к работе в режиме редактирования слайдов. EPROCESS-поля PowerPoint, показанные в предыдущем коде, служат доказательством этому, и стек можно проанализировать путем вывода дампа структуры PO_DIAG_STACK_RECORD.

И наконец, поле TimerResolutionLink соединяет все процессы внесшие изменения в разрешение таймера через список с двойными связями ExpTimerResolutionListHead. Анализ этого списка с помощью команды отладчика !list может выявить все процессы в системе, которые внесли или вносили изменения в разрешение таймера, когда команда powercfg недоступна или требуется информация о прошедших процессах:

lkd> !list "-e -x \"dt nt!_EPROCESS @$extret-@@(#FIELD_OFFSET(nt!_EPROCESS,

TimerResolutionLink))

ImageFileName SmallestTimerResolution RequestedTimerResolution\"

nt!ExpTimerResolutionListHead"

dt nt!_EPROCESS @$extret-@@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

ImageFileName

SmallestTimerResolution RequestedTimerResolution

+0x2e0 ImageFileName : [15] "audiodg.exe"

+0x4b8 RequestedTimerResolution : 0

+0x4c0 SmallestTimerResolution : 0x2710

dt nt!_EPROCESS @$extret-@@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

ImageFileName

SmallestTimerResolution RequestedTimerResolution

+0x2e0 ImageFileName : [15] "chrome.exe"

+0x4b8 RequestedTimerResolution : 0

+0x4c0 SmallestTimerResolution : 0x2710

dt nt!_EPROCESS @$extret-@@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

ImageFileName

SmallestTimerResolution RequestedTimerResolution

+0x2e0 ImageFileName : [15] "calc.exe"

+0x4b8 RequestedTimerResolution : 0

+0x4c0 SmallestTimerResolution : 0x2710

dt nt!_EPROCESS @$extret-@@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

ImageFileName

SmallestTimerResolution RequestedTimerResolution

+0x2e0 ImageFileName : [15] "devenv.exe"

+0x4b8 RequestedTimerResolution : 0

+0x4c0 SmallestTimerResolution : 0x2710

dt nt!_EPROCESS @$extret-@@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

ImageFileName

SmallestTimerResolution RequestedTimerResolution

+0x2e0 ImageFileName : [15] "POWERPNT.EXE"

+0x4b8 RequestedTimerResolution : 0

+0x4c0 SmallestTimerResolution : 0x2710

dt nt!_EPROCESS @$extret-@@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

ImageFileName

SmallestTimerResolution RequestedTimerResolution

+0x2e0 ImageFileName : [15] "winvnc.exe"

+0x4b8 RequestedTimerResolution : 0x2710

+0x4c0 SmallestTimerResolution : 0x2710.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.

↓