Частота системного таймера windows

5 Системный таймер

Кроме часов реального времени, любой компьютер (даже простейший IBM PC) содержит устройство, называемое системным таймером. Это устройство подключено к линии запроса на прерывание IRQ0 и вырабатывает прерывание INT 8h приблизительно 18,2 раза в секунду (точное значение — 1193180/65536 раз в секунду).

Обработка прерываний таймера

При инициализации BIOS устанавливает свой обработчик для прерывания таймера. Этот обработчик каждый раз увеличивает на единицу текущее значение 4-байтовой переменной, располагающейся в области данных BIOS по адресу 0000:046Ch — счетчик таймера. Если этот счетчик переполнится из-за того что прошло более 24 часов с момента запуска таймера, в ячейку 0000:0470h заносится значение 1.

Другое действие, выполняемое стандартным обработчиком прерывания таймера — контроль за работой двигателей НГМД. Если после последнего обращения к НГМД прошло более 2 секунд, обработчик прерывания выключает двигатель. Ячейка с адресом 0000:0440h содержит время, оставшееся до выключения двигателя. Это время постоянно уменьшается обработчиком прерывания таймера. Когда оно становится равно 0, двигатель НГМД отключается.

Последнее действие, которое выполняет обработчик прерывания таймера — вызов прерывания INT 1Ch. После инициализации системы вектор INT 1Ch указывает на команду IRET, то есть обработчик прерывания INT 1Ch ничего не делает. Программа может установить собственный обработчик этого прерывания для того чтобы выполнять какие-либо периодические действия.

Необходимо отметить, что прерывание INT 1Ch вызывается обработчиком прерывания INT 8h до сброса контроллера прерывания, поэтому во время выполнения прерывания INT 1Ch все аппаратные прерывания запрещены. В частности, запрещены прерывания от клавиатуры.

Обработчик прерывания INT 1Ch должен заканчиваться командой IRET. Если же вы подготавливаете собственный обработчик для прерывания INT 8h, перед завершением его работы необходимо сбросить контроллер прерываний. Это можно сделать, например, так:

Таймер обычно реализуется на микросхеме Intel 8253 (для компьютеров IBM PC и IBM PC/XT) или 8254 (для компьютеров IBM PC/AT и IBM PS/2), а также на аналогах этих микросхем. Следующий раздел книги посвящен описанию микросхемы 8254.

Мы не будем подробно рассказывать о всех возможностях микросхем 8253 и 8254, так как обычно используются только несколько режимов работы (а чаще всего один). Полное описание вы сможете найти в справочной литературе по микросхемам 8253/8254, а также по их отечественным аналогам КР1810ВИ53 и КР1810ВИ54.

Микросхемы таймера 8253 и 8254

Таймеры 8253 и 8254 состоят из трех независимых каналов, или счетчиков. Каждый канал содержит регистры:

· состояния канала RS (8 разрядов);

· управляющего слова RSW (8 разрядов);

· буферный регистр OL (16 разрядов);

· регистр счетчика CE (16 разрядов);

· регистр констант пересчета CR (16 разрядов)

Каналы таймера подключаются к внешним устройствам при помощи трех линий:

· GATE — управляющий вход;

· CLOCK — вход тактовой частоты;

· OUT — выход таймера

Регистр счетчика CE работает в режиме вычитания. Его содержимое уменьшается по заднему фронту сигнала CLOCK при условии, что на вход GATE установлен уровень логической 1.

В зависимости от режима работы таймера при достижении счетчиком CE нуля тем или иным образом изменяется выходной сигнал OUT.

Буферный регистр OL предназначен для запоминания текущего содержимого регистра счетчика CE без остановки процесса счета. После запоминания буферный регистр доступен программе для чтения.

Регистр констант пересчета CR может загружаться в регистр счетчика, если это требуется в текущем режиме работы таймера.

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

Режимы работы таймера

Возможны шесть режимов работы таймера. Они разделяются на три типа:

· режимы 0, 4 — однократное выполнение функций.

· режимы 1, 5 — работа с перезапуском.

· режимы 2, 3 — работа с автозагрузкой

Режим однократного выполнения функций

В режиме однократного выполнения функций перед началом счета содержимое регистра констант пересчета CR переписывается в регистр счетчика CE по сигналу CLOCK, если сигнал GATE установлен в 1. В дальнейшем содержимое регистра CE уменьшается по мере прихода импульсов CLOCK. Процесс счета можно приостановить, если подать на вход GATE уровень логического 0. Если затем на вход GATE подать 1, счет будет продолжен дальше. Для повторения выполнения функции необходима новая загрузка регистра CR, то есть повторное программирование таймера.

Читайте также:  Windows 10 лагает браузер

Работа с перезапуском

При работе с перезапуском не требуется повторного программирования таймера для выполнения той же функции. По фронту сигнала GATE значение константы из регистра CR вновь переписывается в регистр CE, даже если текущая операция не была завершена.

Режим автозагрузки

В режиме автозагрузки регистр CR автоматически переписывается в регистр CE после завершения счета. Сигнал на выходе OUT появляется только при наличии на входе GATE уровня логической 1. Этот режим используется для создания программируемых импульсных генераторов и генераторов прямоугольных импульсов (меандра).

Каналы таймера

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

Канал 0

Канал 0 используется в системных часах времени суток (не следует путать с часами реального времени, реализованными на другой микросхеме). Этот канал работает в режиме 3 и используется как генератор импульсов с частотой примерно 18,2 Гц. Именно эти импульсы вызывают аппаратное прерывание INT 8h.

Канал 1

Канал 1 используется для регенерации содержимого динамической памяти компьютера. Выход канала OUT используется для запроса к каналу прямого доступа DMA, который и выполняет обновление содержимого памяти. Вам не следует перепрограммировать этот канал, так как это может привести к нарушениям в работе основной оперативной памяти компьютера.

Канал 2

Канал 2 подключен к громкоговорителю компьютера и может быть использован для генерации различных звуков или музыки, либо как генератор случайных чисел. Канал использует режим 3 таймеров 8253 и 8254.

Программирование таймера на уровне портов

Для чего вам может понадобиться перепрограммирование каналов таймера?

Если вам надо повысить точность измерения времени, выполняемого с помощью канала 0 таймера, вы можете увеличить частоту генерируемых этим каналом импульсов (стандартно 18,2 Гц). По окончании измерений режим работы канала необходимо восстановить для правильной работы системы.

Канал 2, подключенный к громкоговорителю, вы можете использовать для генерации различных звуков или музыки, о чем мы расскажем немного позже. Этот же канал пригодится и для генерации случайных чисел.

Таймеру соответствуют четыре порта ввода/вывода со следующими адресами:

Частота системного таймера windows

. Поняв бесперспективность дальнейшей дискусси, я решил разложить всё по полочкам и провести более аккуратные измерения. Листинг программы привожу по тексту ниже ибо он весьма велик.

Какие есть таймеры внутри операционной системы: ждущие таймеры, мультимедийные таймеры, таймер часов и бла-бла-бла. Всё это верхушка айсберга. В основании лежит единый системный таймер. Он же аппаратный программируемый таймер, который мы помним из школьного курса программирования аппаратных средств в MS DOS. Напомню про него в кратце: это кварц с частотой 1.19318 МГц, который управляет генерацией аппаратного прерывания IRQ0 через определённые интервалы. Частота генерации этого прерывания варьируется от 18.206 Гц (так было в MS DOS), до собственно 1.19318 МГц (предельная частота кварца). Управлять частотой генерации IRQ0 можно программно, поэтому он и называется программируемым. В цифрах мог немного ошибиться (давно это всё было) и в реалии всё чуть-чуть сложнее (на самом деле таймер имеет несколько каналов, предназначенных для разных вещей), но сути дела это не меняет. Главное что нужно понять, так это то, что частота так называемого системного таймера Windows по сути и является этой самой частотой генерации прерывания IRQ0. Опять же детали могут немного отличаться, за сим остави эту часть аппаратчикам, а сами плавно перейдём к программной части.

Частота системного таймера по-умолчанию зависит от множества факторов (например на моей Windows 7 c 3-мя ядрами она составляла 1ms), в то время как на соседнем w2k8 сервере с одним ядром примерно 15.6ms. Опять же значение по умолчанию не важно, важен тот факт, что мы можем его изменять. Либо напрямую с помощью функции режима ядра NtSetTimerResolution:

Либо с помощью функции timeBeginPeriod из Multimedia SDK, котороая согласно исследованиям и статье Марка Руссиновича «Inside Windows NT High Resolution Timers» действительно перенаправляет вызов функции NtSetTimerResolution и влияет на точность (частоту срабатывания) системного таймера. Казалось бы, вуаля: вот прекрасный способ увеличить точность временных функций и избавиться от задержек ожидания и так далее. Но действительность гораздо суровее, чем это кажется.

Читайте также:  Драйвер для принтера кэнон lbp 2900 для windows

Давайте разберёмся, на что влияет изменение точности системного таймера.
Ну естественно в первую очередь он влияет на точность временных измерений. Все остальные таймеры имеют свои показатели точности и гранулярности, которые в зависимости от критичности таймера либо близки к показателю системного, либо весьма далеки от него. Так например таймер часов на моей машине имеет точность примерно те же самый 15.6ms (получить это значение можно с помощью функции GetSystemTimeAdjustment). Принцип работы остальных таймеров примерно следующий: при срабатывании IRQ0 от некоего внутреннего счётчика этого таймера отнимается показатель времени, и когда счётчик становится меньше либо равен нулю, то таймер генерит событие. Судя по всему в случае некоторых таймеров счётчик уменьшается не на каждое срабатывание IRQ0 и уменьшается не на величину точности системного таймера, а на некоторое число, вычисляемое исходя из частоты срабатывания IRQ0 и точности этого таймера. Сразу признаюсь это лишь мои предположения, которые основаны на анализе значений системного таймера и показателей точности системных часов на моей машине.

Во-вторых, и что гораздо важнее, он влияет на точность отсчёта квантов процессорного времени, выделяемого планировщиком потокам. Если верить всё той же статье Марка Руссиновича («Windows NT High Resolution Timers»), квант отсчитывается по следующему алгоритму. При выделении потоку процессорного времени, определяется доступный ему квант в милисекундах — это значение сохраняется во внутреннюю переменную счётчик. При каждом срабатывании системного таймера, этот счётчик уменьшается на величину равную точности системного таймера. Таким образом, если квант равен 10ms, а точность системного таймера равна 1ms, то ровно через 10ms на 10-ом срабатывнии системного таймера поток будет вытеснен с процессора (если не случиться чего либо ужасного, вроде потока с Realtime приоритетом). Если же размер кванта равен тем же 10ms, а точность системного таймера 8ms, то вытеснение произойдёт через 18ms на 2-ом срабатывании таймера. В этом и только в это заключается влияение точности системного таймера на отсчёт кванта.

Теперь о том, на что не влияет точность системного таймера.
Она не влияет на размер кванта и на алгоритм работы планировщика задач. Размер кванта времени зависит от:

  • системной настройки «Processor scheduling» (My Computer / System Propertues / Advanced / Performance / Advanced), значение по-умолчанию которой зависит от типа системы — сервер или клиент;
  • факта принадлежности потока фоновому или активному процессу (в случае клиента);
    приоритета потока;
  • и прочее

Общее описание алгоритмы работы планировщика тоже предельно просто и описано даже в MSDN`е:

  • для каждого приоритета есть своя очередь (упрощённо говоря);
  • в первую очередь всегда выполняются потоки с наивысшем приоритетом;
  • потоки с меньшим приоритетом получают управление только если все потоки с приоритетом выше завершились или уснули;
  • когда поток отработал свой квант времени, он перемещается в конец очереди;
  • поток лишается остатка своего кванта времени, если запускает любую операцию синхронного обмена, wait- или sleep-функцию, вызывает функцию SwitchToThread или в системе появляется готовый к выполнению поток с более высоким приоритетом;
  • во всех остальных случаях поток отрабатывает свой квант до конца.

Из этого следует, что хоть изменение точности системного таймера и должны повлиять на точность отсчёта времени в функции Sleep, в общем случае они не должны повлиять на временные задержки, связанные с пробуждением спящего потока (пока процессор не освободится поток не сможет стать планируемым). И уж точно они не могут оказать практически никакого влияния на wait-функции, разве что на случай пробуждения по тайм-ауту.

Давайте проверять.
Простейшие тесты с вызовом timeBeginPeriod(1) и замерами для нескольких вызовов функции Sleep с параметром 1 (примеров коих множество на форуме), вроде показывают несостоятельность данного предположения: Sleep(1) действительно спит около 1ms. Я осмелился предположить иное, а именно: алгоритм работы планировщика работает именно так, как описано; а вот алгоритм функции Sleep может немного отличаться, например она может не впадать в коматозное состояние, если время сна меньше разрешения системного таймера или время сна успевает истечь до того, как процесс реально уснёт, поэтому происходит его мгновенное пробуждение. Короткие замеры показывают именно это самое побочное явление функции Sleep, суть которого если честно мне не интересна. Я поставил чебе цель проверить, действительно ли вызов Sleep(1) при точности системного таймера 1ms всегда будет спать ровно 1ms и никто не будет вмешиваться в этот процесс. Отдельный интерес представляет проверка поведения wait-функций в подобных же условиях. Для этих целей я написал простое приложение, которое может быть использовано со следующими аргументами (листинг ниже):
SleepTest.exe [-realtime] [-above-normal] [-loading-thread-below] [-adjust-timer] [-min-delay ] [-test-wait]
-realtime — запустить потоки с максимальным приоритетом (по умолчанию false)
-above-normal — запустить потоки с повышенным приоритетом (по умолчанию false)
-loading-thread-below — поток, эмитирующий «полезную» нагрузку запускается с приоритетом ниже, чем ждущий поток (по умолчанию false)
-adjust-timer — прменить timeBeginPeriod перед засыпанием (по умолчанию false)
-min-delay — минимальное значение задержки которое нужно выводить на экран (единица соответствует в 0.001ms; по умолчанию 150, что соответствует 1.5ms)
-test-wait — запустить тест для wait-функций вместо sleep (по умолчанию false)

Читайте также:  Установить windows для андроида

Итак тестирование.
Приложение скомпилировано на MS VC 2005 для 64-ёх битной платформы в release конфигурации по-умолчанию. Тестовая платформа: Windows 7 x64 с 3-ёх ядерным процессором (к сожалению все остальные платформы, которые есть под рукой — виртуальные и данный тест не имеет на них никакого смысла, потому что повлять на точность системного таймера для них мы не сможем — она всегда определяется хостовой системой). Машина имеет следующие показания точности системного таймера (по данным приложения CloclRes.exe).
D:\SleepTest\x64\release>clockres

ClockRes v2.0 — View the system clock resolution
Copyright (C) 2009 Mark Russinovich
SysInternals — www.sysinternals.com

Maximum timer interval: 15.600 ms
Minimum timer interval: 0.500 ms
Current timer interval: 1.000 ms

Приложение функционирует следующим образом. При старте создаёт несколько потоков: генерирующий нагрузку, ждущий и (для случая тестирования wait-функций) поток генерации события. Первые 2 потока всегда создаются с привязкой к одному процессору, чтобы эмулировать конкуренцию. 3-ий поток на многоядерной системе всегда привязывается к другому процессору, чтобы не оказывать влияния на вычисления. Поток генерирующий нагрузку просто загружает процессор, ждущий поток замеряет время ожидания (время нахождения внутри вызова Sleep(1) или время между генерацией события и выходом из wait-функции) и выводит его на экран, если оно больше указанного с помощью параметра -min-delay.

1) Запуск с нормальными приоритетами, без настройки таймера, тестируем Sleep (напоминаю, точность системного таймера по-умолчанию 1ms):
D:\SleepTest\x64\release>SleepTest.exe
399: 31.99ms
441: 1.85ms
1408: 2.02ms
3200: 1.55ms
3324: 1.77ms
3354: 1.79ms
4146: 1.67ms
8678: 1.81ms
10014: 3.1ms
11304: 1.63ms
13286: 9.58ms
15475: 1.72ms
16032: 32ms
19499: 2.8ms
20046: 1.68ms

2) Запуск с нормальными приоритетами, с настройкой таймера, тестируем Sleep:
D:\SleepTest\x64\release>SleepTest.exe -adjust-timer
5117: 1.67ms
5185: 2.01ms
5195: 3.15ms
6781: 27ms
8078: 2.02ms
9762: 2.14ms
9865: 2.01ms
11884: 6.96ms
11937: 3.98ms
12939: 3.04ms
13351: 7.99ms
18347: 4.04ms

Как и следовало ожидать, результат практически не отличается от предыдущего, потому что точность системного таймера и без того равна единице. Задержки становятся всё более очевидны и заметны, при переключении приложения на задний план

3) Убедимся, что на VMware эффекта от вызова timeBeginPeriod нет (запуск с нормальными приоритетами, с настройкой таймера, тестируем Sleep на Windows Server 2008 на VMware:
C:\Temp>SleepTest.exe -adjust-timer
1: 13.24ms
2: 14.37ms
3: 15.11ms
4: 14.24ms
5: 13.92ms
6: 14.85ms
7: 14.63ms
8: 23.27ms
9: 4.74ms
10: 14.58ms
11: 14.29ms
12: 15.04ms
13: 14.75ms

4) Запуск с приоритетом real-time, с настройкой таймера, тестируем Sleep:
d:\SleepTest\x64\release>SleepTest.exe -adjust-timer -realtime
1: 31.89ms
2: 31.98ms
3: 31.99ms
4: 31.99ms
5: 31.98ms
6: 32ms
7: 31.98ms
8: 31.98ms
9: 32ms
10: 31.98ms
11: 31.98ms

Этот результат наиболее красноречиво говорит о влиянии планировщика на функции ожидания.

5) Запуск с нормальным приоритетом, с настройкой таймера, тестируем WaitForSingleObject:
d:\Projects\Tests\SleepTest\x64\release>SleepTest.exe -adjust-timer -test-wait
6090: 1.61ms
26341: 31.83ms
31954: 2.3ms
33042: 2.01ms
39156: 34.76ms
52256: 27.89ms
91951: 2.47ms
105046: 31.78ms
118118: 31.51ms
131135: 31.13ms
184144: 31.21ms
197216: 30.87ms
210403: 30.59ms
236874: 1.64ms
250030: 31.98ms
263217: 1.58ms
289289: 3.19ms
302512: 1.53ms
342117: 3.15ms
355197: 40.36ms

Результат говорит сам за себя.

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

Оцените статью