Несколько слов в общем:
Объединение таймеров позволяет сократить количество прерываний. Приложениям разрешается указывать допуск для своих требований по времени. Это позволяет операционной системе «группировать» прерывания с парой последствий:
- количество прерываний может быть уменьшено. (+)
- количество переключений контекста может быть меньше. (+)
- потребление энергии может быть уменьшено. (+)
- большая часть операций может быть выполнена на этих пакетных прерываниях (-)
- планировщику, возможно, придется запланировать большое количество процессов в это время (-)
- разрешение по времени хуже (-)
Windows, как и другие операционные системы, работающие с прерываниями, всегда «группирует» события по времени. Все, что настроено на то, чтобы произойти в определенное время, зависит от установленного времени, чтобы истечь с прерыванием. Следовательно, события объединяются с прерыванием. Степень детализации этой схемы определяется частотой прерывания. Обязательно к прочтению тем, кто интересуется объединением таймеров: MSDN: объединение таймера Windows.
По соображениям производительности следует приложить все усилия, чтобы уменьшить количество прерываний, насколько это возможно. К сожалению, многие пакеты устанавливают очень высокое разрешение системного таймера, например с помощью интерфейса мультимедийного таймера timeBeginPeriod
/ timeEndPeriod
или базового API NtSetTimerResolution
. Как упоминал Ганс: «Chrome» - хороший пример того, как использование этих функций может быть сильно преувеличено.
Во-вторых, теперь, когда мне стало интересно ... timeSetEvent
- одна из функций мультимедийного таймера. Он использует timeBeginPeriod
под капотом.
И он использует это плохо: он устанавливает разрешение системного таймера для соответствия uResolution настолько хорошо, насколько это возможно в пределах разрешений таймера, доступных на исполняющей платформе. При больших значениях uDelay он может ждать с низким разрешением, пока не приблизится к истечению задержки, и только затем повышать разрешение системного таймера, но он устанавливает разрешение таймера для всего периода ожидания равным указано uResolution. Это болезненно, зная, что высокое разрешение применимо и к длительным задержкам. Однако функции мультимедийного таймера не предназначены для использования при больших задержках. Но снова и снова устанавливать разрешение - тоже нехорошо (см. Примечания ниже).
Резюме по timeSetEvent
: Эта функция вообще не делает ничего похожего на объединение, а наоборот: она необязательно увеличивает количество прерываний; в этом смысле он распределяет события по большему количеству прерываний, он «расщепляет» их.
SetThreadpoolTimer
впервые представляет идею "группирования" событий. В первую очередь это было вызвано растущими жалобами на время автономной работы ноутбуков с Windows. SetWaitableTimerEx
продвинул эту стратегию дальше, и SetCoalescableTimer
является новейшим API для доступа к таймерам объединения. Последний вводит TIMERV_DEFAULT_COALESCING и TIMERV_NO_COALESCING, о которых стоит подумать, поскольку они позволяют игнорировать определенные факты.
Воспользовавшись возможностью, сделаем несколько замечаний по разрешению системных таймеров:
Изменение разрешения системного таймера имеет больше последствий, чем просто увеличение частоты прерываний. Некоторые эффекты, возникающие при использовании timeBeginPeriod
/ NtSetTimerResolution
:
- Изменения частоты прерывания
- Квантовые изменения потоков (временной интервал потоков) (!)
- Икота системного времени (MSDN: "... частые звонки могут существенно повлиять на системные часы")
- Икота при активной корректировке системного времени (
SetSystemTimeAdjustment
)
Пункт 3. был частично решен в Windows 7, а пункт 4. был решен только в Windows 8.1. Ошибки системного времени могут достигать минимального поддерживаемого разрешения таймера (15,625 мс в типичных системах), и они накапливаются, когда timeBeginPeriod
/ NtSetTimerResolution
часто. Это может привести к значительному скачку при попытке настроить системное время в соответствии с эталоном NTP. Клиенты NTP должны работать с высоким разрешением таймера для достижения разумной точности при работе в версии Windows ‹Windows 8.
И наконец: сама Windows изменяет разрешение системного таймера всякий раз, когда видит в этом преимущества. Количество поддерживаемых разрешений таймера зависит от базового оборудования и версии Windows. Список доступных разрешений можно получить, просмотрев их, вызвав timeBeginPeriod
с увеличивающимися периодами, за которым следует вызов NtQueryTimerResolution. Некоторые из поддерживаемых разрешений могут быть "не одобрены" Windows на определенных платформах и изменены в соответствии с потребностями Windows. Пример: XP может изменить "заданное пользователем" разрешение с ~ 4 мс на 1 мс через короткий промежуток времени на определенных платформах. Некоторые версии Windows ‹8.1 действительно изменяют разрешение таймера в непредсказуемые моменты времени.
Если требуется, чтобы приложение было полностью независимым от этих артефактов, оно должно само получить максимально возможное разрешение. Таким образом, приложение доминирует в разрешении всей системы, и ему не нужно беспокоиться о том, что другие приложения или ОС меняют разрешение таймера. Более современные платформы поддерживают разрешение таймера 0,5 мс. timeBeginPeriod
не позволяет получить это разрешение, но NtSetTimerResolution делает это. Здесь я описал, как использовать NtSetTimerResolution для получения разрешения 0,5 мс.
В таких условиях потребление энергии, вероятно, возрастет, но это плата за надежное разрешение: затраты энергии на переключение контекста обычно составляют от 0,05 мДж до 0,2 мДж на современном оборудовании (кто-нибудь оценил общее количество переключений контекста во всем мире в год? ). Windows сокращает квант потока (временной интервал) до прибл. 2/3 при разрешении таймера выставлено на максимум. Как следствие, потребление энергии увеличивается прибл. 30%!
person
Arno
schedule
16.05.2014