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

Інтервальний таймер системного годинника - мабуть, найбільш важливий пристрій на Windows-машині, про що свідчить його високе значення IRQL (CLOCK_LEVEL). Його важливість також випливає із важливості тієї роботи, за яку він відповідає.

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

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

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

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

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

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

Ідентифікація таймерів, які працюють із підвищеною частотою.

У зв'язку з проблемами, які можуть виникати через таймери, що працюють з підвищеною частотою, Windows використовує засіб Event Tracing for Windows (ETW) для відстеження всіх процесів і драйверів, що вимагають зміни інтервалу системного годинника з виведенням часу події та необхідного інтервалу. Цей засіб показує також поточний інтервал.

Ці дані стануть у нагоді як розробникам, так і системним адміністраторам при з'ясуванні причин низької продуктивності батареї на системах, які в інших умовах працювали цілком справно, а також зменшення сумарної споживаної потужності на великих системах. Для отримання цих даних потрібно просто запустити команду powercfg /energy та буде видано HTML-файл energy-report.html схожий на цей.

Прокрутіть сторінку вниз до розділу Роздільна здатність апаратного таймера (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 @[email protected]@(#FIELD_OFFSET(nt!_EPROCESS,

ImageFileName SmallestTimerResolution RequestedTimerResolution\"

dt nt!_EPROCESS @[email protected]@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

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

+0x4b8 RequestedTimerResolution: 0

+0x4c0 SmallestTimerResolution: 0x2710

dt nt!_EPROCESS @[email protected]@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

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

+0x4b8 RequestedTimerResolution: 0

+0x4c0 SmallestTimerResolution: 0x2710

dt nt!_EPROCESS @[email protected]@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

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

+0x4b8 RequestedTimerResolution: 0

+0x4c0 SmallestTimerResolution: 0x2710

dt nt!_EPROCESS @[email protected]@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

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

+0x4b8 RequestedTimerResolution: 0

+0x4c0 SmallestTimerResolution: 0x2710

dt nt!_EPROCESS @[email protected]@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))

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

+0x4b8 RequestedTimerResolution: 0

+0x4c0 SmallestTimerResolution: 0x2710

dt nt!_EPROCESS @[email protected]@(#FIELD_OFFSET(nt!_EPROCESS, TimerResolutionLink))